diff --git a/lib/pls/include/pls/internal/data_structures/delayed_initialization_wrapper.h b/lib/pls/include/pls/internal/data_structures/delayed_initialization_wrapper.h index 1d93398..d02f94e 100644 --- a/lib/pls/include/pls/internal/data_structures/delayed_initialization_wrapper.h +++ b/lib/pls/include/pls/internal/data_structures/delayed_initialization_wrapper.h @@ -35,11 +35,19 @@ class delayed_initialization_wrapper { template void initialize(ARGS &&...args) { - PLS_ASSERT(initialized_, "Can only initialize delayed wrapper object once!") + PLS_ASSERT(!initialized_, "Can only initialize delayed wrapper object once!") new(memory_) T(std::forward(args)...); initialized_ = true; } + + void destroy() { + PLS_ASSERT(initialized_, "Can only destroy initialized objects!") + + memory_->~T(); + initialized_ = false; + } + T &object() { PLS_ASSERT(initialized_, "Can not use an uninitialized delayed wrapper object!") return *reinterpret_cast(memory_); diff --git a/lib/pls/include/pls/internal/scheduling/cont_manager.h b/lib/pls/include/pls/internal/scheduling/cont_manager.h index 104337f..1290921 100644 --- a/lib/pls/include/pls/internal/scheduling/cont_manager.h +++ b/lib/pls/include/pls/internal/scheduling/cont_manager.h @@ -3,6 +3,8 @@ #define PLS_CONT_MANAGER_H_ #include +#include +#include #include "pls/internal/data_structures/aligned_stack.h" #include "pls/internal/scheduling/continuation.h" @@ -13,14 +15,45 @@ namespace scheduling { class cont_manager { public: - explicit cont_manager(size_t num_conts, size_t max_cont_size, data_structures::aligned_stack &cont_storage) - : num_conts_{num_conts}, max_cont_size_{max_cont_size}, cont_storage_{cont_storage} { - //TODO: Init linked list like structure + template + explicit cont_manager(data_structures::aligned_stack &cont_storage) { + // First node is currently active and our local start + start_node_ = active_node_ = init_cont_node(cont_storage, nullptr, nullptr); + + // Build up chain after it + continuation_node *current_node = start_node_; + for (size_t i = 1; i < NUM_CONTS; i++) { + continuation_node *next_node = init_cont_node(cont_storage, start_node_, current_node); + current_node->set_prev(next_node); + } }; + continuation_node *fast_path_get_next() { + active_node_ = active_node_->get_next(); + return active_node_; + } + void fast_path_return() { + active_node_ = active_node_->get_prev(); + } + + private: + template + static continuation_node *init_cont_node(data_structures::aligned_stack &cont_storage, + continuation_node *cont_chain_start, + continuation_node *prev) { + // Represents one cont node and its corresponding memory buffer (as one continuous block of memory). + using cont_node_memory_pair = std::tuple>; + char *tuple_memory = cont_storage.push_bytes(); + char *cont_node_address = tuple_memory; + char *cont_node_memory_address = tuple_memory + sizeof(continuation_node); + + return new(cont_node_address) continuation_node(cont_node_memory_address, cont_chain_start, prev); + } + private: - const size_t num_conts_, max_cont_size_; - data_structures::aligned_stack &cont_storage_; + continuation_node *start_node_; + continuation_node *active_node_; }; template diff --git a/lib/pls/include/pls/internal/scheduling/continuation.h b/lib/pls/include/pls/internal/scheduling/continuation.h index f9a2420..6a2ef5f 100644 --- a/lib/pls/include/pls/internal/scheduling/continuation.h +++ b/lib/pls/include/pls/internal/scheduling/continuation.h @@ -20,10 +20,27 @@ class base_continuation { class continuation_node { public: + continuation_node(char *continuation_memory, continuation_node *cont_chain_start, continuation_node *prev) + : continuation_memory_{continuation_memory}, + continuation_{nullptr}, + cont_chain_start_{cont_chain_start}, + prev_{prev}, + next_{nullptr}, + offered_chain_{nullptr} {} + + void set_cont_chain_start(continuation_node *cont_chain_start) { cont_chain_start_ = cont_chain_start; } + continuation_node *get_cont_chain_start() { return cont_chain_start_; } + void set_next(continuation_node *next) { next_ = next; } + continuation_node *get_next() { return next_; } + void set_prev(continuation_node *prev) { prev_ = prev; } + continuation_node *get_prev() { return prev_; } + + base_continuation *continuation() { return continuation_; } private: // Pointer to memory region reserved for the companion continuation. // Must be a buffer big enough to hold any continuation encountered in the program. + char *continuation_memory_; base_continuation *continuation_; // Linked list property of continuations (continuation chains as memory management). @@ -47,6 +64,10 @@ class continuation : public base_continuation { // E.g. handle passing the result to the parent continuation function_.object()(result_1_.object(), result_2_.object()); } + + // Warning: De-constructor only called once the continuation is actually needed. + // This should be a non issue, as all memory in the continuation is uninitialized + // until the first use anyways to save runtime. ~continuation() override = default; template @@ -76,14 +97,15 @@ class continuation : public base_continuation { template using delayed_init = data_structures::delayed_initialization_wrapper; - delayed_init result_1_; - delayed_init result_2_; - delayed_init function_; - // Also uninitialized at first, only take the atomic write on the slow path. // The stealer will init it to 2 while stealing, the 'stolen' sync will then make sure // everyone sees the value in correct order. std::atomic results_missing_{}; + + // All fields/actual values stay uninitialized (save time on the fast path if we don not need them). + delayed_init result_1_; + delayed_init result_2_; + delayed_init function_; }; }