From 799c535a95094297a38d922a0e9903b2e8a1a4bd Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Wed, 15 Sep 2021 23:18:10 +0200 Subject: async: Add coroutine tasks and scheduler. --- async/scheduler.h | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 async/scheduler.h (limited to 'async/scheduler.h') diff --git a/async/scheduler.h b/async/scheduler.h new file mode 100644 index 0000000..0196aa5 --- /dev/null +++ b/async/scheduler.h @@ -0,0 +1,163 @@ +#pragma once + +#include + +struct schedulable { + schedulable* next = nullptr; + + std::coroutine_handle<> awaiter; + + schedulable() {} + schedulable(std::coroutine_handle<> h) : awaiter(h) {} +}; + +struct scheduler_t { + schedulable* first = nullptr; + schedulable** last_next_p = &first; + + void run() { + while(first) { + auto sch = pop_next(); + sch.awaiter.resume(); + } + } + + schedulable& pop_next() { + critical_section lock; + + auto sch = first; + first = first->next; + + if(!first) { + last_next_p = &first; + } + + return *sch; + } + + void schedule(schedulable& sch) { + critical_section lock; + + sch.next = nullptr; + *last_next_p = &sch; + last_next_p = &sch.next; + } +}; + +scheduler_t scheduler; + +struct yield : public schedulable { + bool await_ready() { + return false; + } + + bool await_suspend(std::coroutine_handle<> h) { + awaiter = h; + scheduler.schedule(*this); + return true; + } + + void await_resume() {} +}; + +template +struct future : public schedulable { + std::optional value; + + bool await_ready() { + return bool(value); + } + + bool await_suspend(std::coroutine_handle<> h) { + if(value) { + return false; + } else { + awaiter = h; + return true; + } + } + + T await_resume() { + return *value; // TODO: move? + } + + bool done() { + return bool(value); + } + + void set(T v) { + if(value) { + return; + } + + value = v; + + if(awaiter) { + scheduler.schedule(*this); + } + } + + void reset() { + value.reset(); + awaiter = nullptr; + } +}; + +template <> +struct future : public schedulable { + bool ready; + + future() : ready(false) {} + + bool await_ready() { + return ready; + } + + bool await_suspend(std::coroutine_handle<> h) { + if(ready) { + return false; + } else { + awaiter = h; + return true; + } + } + + void await_resume() { + + } + + bool done() { + return ready; + } + + void set() { + if(ready) { + return; + } + + ready = true; + + if(awaiter) { + scheduler.schedule(*this); + } + } + + void reset() { + awaiter = nullptr; + ready = false; + } +}; + +struct task : public schedulable { + struct promise_type { + task get_return_object() { + auto handle = std::coroutine_handle::from_promise(*this); + return {handle}; + } + std::suspend_always initial_suspend() { return {}; } + std::suspend_never final_suspend() { return {}; } + void return_void() {} + }; + + task(std::coroutine_handle h) : schedulable(h) {} +}; -- cgit v1.2.3