coro-timer-dispatch.cpp (3213B)
1 #include <coroutine> 2 #include <iostream> 3 #include <list> 4 #include <algorithm> 5 #include <unistd.h> 6 7 static int jiffies; 8 9 struct jiffies_scheduler 10 { 11 struct scheduled_event 12 { 13 std::coroutine_handle<> h; 14 int when; 15 16 friend bool operator <(int w, scheduled_event const& e) noexcept 17 { 18 return w < e.when; 19 } 20 }; 21 22 struct jiffies_timeout : std::suspend_always 23 { 24 jiffies_scheduler& scheduler; 25 int when; 26 27 jiffies_timeout(jiffies_scheduler& s, int w) 28 : scheduler(s) 29 , when(w) 30 {} 31 32 /*bool await_ready(void) const noexcept 33 { 34 return tasks.empty(); 35 }*/ 36 37 std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) 38 { 39 scheduler.schedule(h, when); 40 return scheduler.next(); 41 } 42 }; 43 44 std::list<scheduled_event> tasks; 45 46 void schedule(std::coroutine_handle<> h, int w) 47 { 48 auto pos = std::upper_bound(tasks.begin(), tasks.end(), w); 49 tasks.insert(pos, {h, w}); 50 } 51 52 std::coroutine_handle<> next(void) noexcept 53 { 54 if (tasks.empty()) 55 return std::noop_coroutine(); 56 57 // std::cout << "Wakeup @: "; 58 // for (auto e : tasks) 59 // std::cout << e.when << ' '; 60 // std::cout << '\n'; 61 62 auto e = tasks.front(); 63 if (e.when > jiffies) 64 return std::noop_coroutine(); 65 66 tasks.pop_front(); 67 return e.h; 68 } 69 70 jiffies_scheduler(void) = default; 71 72 void destroy(void) 73 { 74 if (not tasks.empty()) 75 std::cout << "Finishing early, cleaning up state of suspended tasks..." << std::endl; 76 77 for (auto e : tasks) 78 e.h.destroy(); 79 } 80 81 ~jiffies_scheduler() 82 { 83 destroy(); 84 } 85 86 jiffies_scheduler(jiffies_scheduler&& old) 87 : tasks(std::move(old.tasks)) 88 {} 89 90 jiffies_scheduler& operator =(jiffies_scheduler&& old) 91 { 92 destroy(); 93 tasks = std::move(old.tasks); 94 return *this; 95 } 96 97 bool operator ()(void) noexcept 98 { 99 if (tasks.empty()) 100 return false; 101 102 auto e = tasks.front(); 103 tasks.pop_front(); 104 105 int t = e.when - jiffies; 106 std::cout << "Sleeping for " << t << " seconds\n"; 107 108 ::sleep(t); 109 jiffies += t; 110 111 e.h(); 112 113 return true; 114 } 115 jiffies_timeout operator ()(int t) noexcept 116 { 117 return {*this, t + jiffies}; 118 } 119 } sleeper; 120 121 struct fire_forget_coroutine 122 { 123 struct promise_type 124 { 125 ~promise_type() {} 126 void get_return_object(void) {} 127 std::suspend_never initial_suspend(void) 128 { 129 //sleeper.schedule(std::coroutine_handle<promise_type>::from_promise(*this), 0); 130 return {}; 131 } 132 void return_void(void) {} 133 std::suspend_never final_suspend(void) noexcept 134 { 135 // sleeper(); 136 return {}; 137 } 138 void unhandled_exception(void) { std::terminate(); } 139 }; 140 }; 141 142 fire_forget_coroutine counter3(int x) 143 { 144 std::cout << jiffies << "| +" << x << '\n'; 145 co_await sleeper(x); 146 std::cout << jiffies << "| " << x << '\n'; 147 co_await sleeper(x); 148 std::cout << jiffies << "| ~" << x << '\n'; 149 co_return; 150 } 151 fire_forget_coroutine counter2(int x) 152 { 153 std::cout << jiffies << ": +" << x << '\n'; 154 co_await sleeper(x); 155 std::cout << jiffies << ": ~" << x << '\n'; 156 co_return; 157 } 158 159 fire_forget_coroutine counter() 160 { 161 counter3(5); 162 counter2(5); 163 counter2(10); 164 165 std::cout << jiffies << ":\n"; 166 co_await sleeper(1); 167 std::cout << jiffies << ":\n"; 168 169 std::cout << " DONE" << std::endl; 170 co_return; 171 } 172 173 int main() 174 { 175 counter(); 176 177 while (sleeper()) 178 std::cout << "event loop\n"; 179 180 return 0; 181 }