Commit d3b64a85 by FritzFlorian

WIP: Initialization of continuation chains.

parent 740ae661
Pipeline #1333 failed with stages
in 25 seconds
......@@ -35,11 +35,19 @@ class delayed_initialization_wrapper {
template<typename ...ARGS>
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>(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<T *>(memory_);
......
......@@ -3,6 +3,8 @@
#define PLS_CONT_MANAGER_H_
#include <memory>
#include <tuple>
#include <array>
#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<size_t NUM_CONTS, size_t MAX_CONT_SIZE>
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<MAX_CONT_SIZE>(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<MAX_CONT_SIZE>(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<size_t MAX_CONT_SIZE>
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<continuation_node,
std::array<char, MAX_CONT_SIZE - sizeof(continuation_node)>>;
char *tuple_memory = cont_storage.push_bytes<cont_node_memory_pair>();
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<size_t NUM_CONTS, size_t MAX_CONT_SIZE>
......
......@@ -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<typename R1ARG>
......@@ -76,14 +97,15 @@ class continuation : public base_continuation {
template<typename T>
using delayed_init = data_structures::delayed_initialization_wrapper<T>;
delayed_init<R1> result_1_;
delayed_init<R2> result_2_;
delayed_init<F> 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<unsigned short> results_missing_{};
// All fields/actual values stay uninitialized (save time on the fast path if we don not need them).
delayed_init<R1> result_1_;
delayed_init<R2> result_2_;
delayed_init<F> function_;
};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment