commit 665a10412fc08fdc81263695f3bb86fda96eb88e
parent 00c134357d45d84224f4fc126c921f12b2ea2b6f
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Sat, 2 Apr 2022 18:16:05 +0100
Add coroutine timer dispatch example
Diffstat:
3 files changed, 180 insertions(+), 0 deletions(-)
diff --git a/src/robin.cpp b/src/coro-round-robin.cpp
diff --git a/src/coro-timer-dispatch.cpp b/src/coro-timer-dispatch.cpp
@@ -0,0 +1,180 @@
+#include <coroutine>
+#include <iostream>
+#include <list>
+#include <unistd.h>
+
+static int jiffies;
+
+struct jiffies_scheduler
+{
+ struct scheduled_event
+ {
+ std::coroutine_handle<> h;
+ int when;
+
+ friend bool operator <(int w, scheduled_event const& e) noexcept
+ {
+ return w < e.when;
+ }
+ };
+
+ struct jiffies_timeout : std::suspend_always
+ {
+ jiffies_scheduler& scheduler;
+ int when;
+
+ jiffies_timeout(jiffies_scheduler& s, int w)
+ : scheduler(s)
+ , when(w)
+ {}
+
+ /*bool await_ready(void) const noexcept
+ {
+ return tasks.empty();
+ }*/
+
+ std::coroutine_handle<> await_suspend(std::coroutine_handle<> h)
+ {
+ scheduler.schedule(h, when);
+ return scheduler.next();
+ }
+ };
+
+ std::list<scheduled_event> tasks;
+
+ void schedule(std::coroutine_handle<> h, int w)
+ {
+ auto pos = std::upper_bound(tasks.begin(), tasks.end(), w);
+ tasks.insert(pos, {h, w});
+ }
+
+ std::coroutine_handle<> next(void) noexcept
+ {
+ if (tasks.empty())
+ return std::noop_coroutine();
+
+// std::cout << "Wakeup @: ";
+// for (auto e : tasks)
+// std::cout << e.when << ' ';
+// std::cout << '\n';
+
+ auto e = tasks.front();
+ if (e.when > jiffies)
+ return std::noop_coroutine();
+
+ tasks.pop_front();
+ return e.h;
+ }
+
+ jiffies_scheduler(void) = default;
+
+ void destroy(void)
+ {
+ if (not tasks.empty())
+ std::cout << "Finishing early, cleaning up state of suspended tasks..." << std::endl;
+
+ for (auto e : tasks)
+ e.h.destroy();
+ }
+
+ ~jiffies_scheduler()
+ {
+ destroy();
+ }
+
+ jiffies_scheduler(jiffies_scheduler&& old)
+ : tasks(std::move(old.tasks))
+ {}
+
+ jiffies_scheduler& operator =(jiffies_scheduler&& old)
+ {
+ destroy();
+ tasks = std::move(old.tasks);
+ return *this;
+ }
+
+ bool operator ()(void) noexcept
+ {
+ if (tasks.empty())
+ return false;
+
+ auto e = tasks.front();
+ tasks.pop_front();
+
+ int t = e.when - jiffies;
+ std::cout << "Sleeping for " << t << " seconds\n";
+
+ ::sleep(t);
+ jiffies += t;
+
+ e.h();
+
+ return true;
+ }
+ jiffies_timeout operator ()(int t) noexcept
+ {
+ return {*this, t + jiffies};
+ }
+} sleeper;
+
+struct fire_forget_coroutine
+{
+ struct promise_type
+ {
+ ~promise_type() {}
+ void get_return_object(void) {}
+ std::suspend_never initial_suspend(void)
+ {
+ //sleeper.schedule(std::coroutine_handle<promise_type>::from_promise(*this), 0);
+ return {};
+ }
+ void return_void(void) {}
+ std::suspend_never final_suspend(void) noexcept
+ {
+// sleeper();
+ return {};
+ }
+ void unhandled_exception(void) { std::terminate(); }
+ };
+};
+
+fire_forget_coroutine counter3(int x)
+{
+ std::cout << jiffies << "| +" << x << '\n';
+ co_await sleeper(x);
+ std::cout << jiffies << "| " << x << '\n';
+ co_await sleeper(x);
+ std::cout << jiffies << "| ~" << x << '\n';
+ co_return;
+}
+fire_forget_coroutine counter2(int x)
+{
+ std::cout << jiffies << ": +" << x << '\n';
+ co_await sleeper(x);
+ std::cout << jiffies << ": ~" << x << '\n';
+ co_return;
+}
+
+fire_forget_coroutine counter()
+{
+ counter3(5);
+ counter2(5);
+ counter2(10);
+
+ std::cout << jiffies << ":\n";
+ co_await sleeper(1);
+ std::cout << jiffies << ":\n";
+
+ std::cout << " DONE" << std::endl;
+ co_return;
+}
+
+int main()
+{
+ counter();
+
+ while (sleeper())
+ std::cout << "event loop\n";
+
+ return 0;
+}
diff --git a/src/coro.cpp b/src/coro-unconditional-dispatch.cpp