examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

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 }