summaryrefslogtreecommitdiff
path: root/async/time_scheduler.h
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2022-04-16 20:59:36 +0200
committerVegard Storheil Eriksen <zyp@jvnv.net>2022-04-16 21:02:39 +0200
commitd6c95a111c0950757d75496af254e3427e3769b6 (patch)
tree049d63096e434a7dba49e018e6836faaa440ec01 /async/time_scheduler.h
parentc6b1f1112a3f4a5139700ef33da62c1ebdc3a7ba (diff)
async: Add preliminary time scheduler.
Diffstat (limited to 'async/time_scheduler.h')
-rw-r--r--async/time_scheduler.h76
1 files changed, 76 insertions, 0 deletions
diff --git a/async/time_scheduler.h b/async/time_scheduler.h
new file mode 100644
index 0000000..e09de16
--- /dev/null
+++ b/async/time_scheduler.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <chrono>
+
+#include "scheduler.h"
+
+template <typename Duration = std::chrono::milliseconds>
+struct time_scheduler_t {
+ struct wakeup_future : public schedulable {
+ time_scheduler_t& tsched;
+ Duration time;
+ wakeup_future(time_scheduler_t& tsched, Duration time) : tsched(tsched), time(time) {}
+
+ bool await_ready() {
+ return tsched.now >= time;
+ }
+
+ bool await_suspend(std::coroutine_handle<> h) {
+ if(tsched.now >= time) {
+ return false;
+ } else {
+ awaiter = h;
+ tsched.push_wakeup(this);
+ return true;
+ }
+ }
+
+ void await_resume() {}
+
+ void resume() {
+ scheduler.schedule(*this);
+ }
+ };
+
+ Duration now;
+
+ wakeup_future* wakeup_queue;
+
+ void push_wakeup(wakeup_future* fut) {
+ wakeup_future** p = &wakeup_queue;
+
+ while((*p) && (*p)->time <= fut->time) {
+ p = reinterpret_cast<wakeup_future**>(&(*p)->next);
+ }
+
+ fut->next = *p;
+ *p = fut;
+ }
+
+ async_flag tick_flag;
+
+ void tick() {
+ tick_flag.set();
+ }
+
+ task wakeup_task() {
+ while(1) {
+ co_await tick_flag;
+ now++;
+
+ while(wakeup_queue && wakeup_queue->time <= now) {
+ auto fut = wakeup_queue;
+ wakeup_queue = static_cast<wakeup_future*>(fut->next);
+ fut->resume();
+ }
+ }
+ }
+
+ wakeup_future sleep_until(Duration time) {
+ return {*this, time};
+ }
+
+ wakeup_future sleep(Duration duration) {
+ return sleep_until(now + duration);
+ }
+};