#ifndef PLS_TASK_H #define PLS_TASK_H #include #include #include "context_switcher/continuation.h" #include "context_switcher/context_switcher.h" #include "pls/internal/base/system_details.h" #include "pls/internal/data_structures/stamped_integer.h" #include "pls/internal/scheduling/traded_cas_field.h" namespace pls { namespace internal { namespace scheduling { /** * A task is the smallest unit of execution seen by the runtime system. * * Tasks represent a action dispatched by a potentially parallel call. * Tasks have their own execution context (stack and register state), making them stackefull coroutines. * Tasks can be suspended and resumed (stealing happens by resuming a task). * * Being coroutines tasks go through a very deliberate state machine: * - initialized (no execution state) * - running (currently executing user code) * - suspended (suspended by switching to a different task). */ struct alignas(base::system_details::CACHE_LINE_SIZE) task { void init(char *stack_memory, size_t stack_size, unsigned depth, unsigned thread_id) { stack_memory_ = stack_memory; stack_size_ = stack_size; depth_ = depth; thread_id_ = thread_id; } context_switcher::continuation get_continuation() { return std::move(continuation_); } void set_continuation(context_switcher::continuation &&continuation) { continuation_ = std::move(continuation); } template context_switcher::continuation run_as_task(F &&lambda) { return context_switcher::enter_context(stack_memory_, stack_size_, std::forward(lambda)); } // TODO: Proper access control and split it up into responsibilities // Stack/Continuation Management char *stack_memory_; size_t stack_size_; context_switcher::continuation continuation_; // Work-Stealing std::atomic traded_field_{}; task *resource_stack_next_{}; std::atomic resource_stack_root_{{0, 0}}; bool clean_; // Task Tree (we have a parent that we want to continue when we finish) task *parent_task_; unsigned depth_; unsigned thread_id_; // Memory Linked List task *prev_; task *next_; }; } } } #endif //PLS_TASK_H