20 #ifndef STDEX_COROUTINE_H_ 21 #define STDEX_COROUTINE_H_ 24 #define STACK_LIMIT (1024 * 1024) 44 #if defined(__APPLE__) && defined(__MACH__) 67 std::function<void()> func;
71 Routine(std::function<
void()> f)
86 std::vector<Routine*> routines;
87 std::list<routine_t> indexes;
96 fiber = ConvertThreadToFiber(
nullptr);
101 for (
auto& routine : routines)
108 inline routine_t
create(std::function<
void()> f)
112 if (ordinator.indexes.empty())
114 ordinator.routines.push_back(routine);
115 return (routine_t)ordinator.routines.size();
119 routine_t
id = ordinator.indexes.front();
120 ordinator.indexes.pop_front();
121 assert(ordinator.routines[
id - 1] ==
nullptr);
122 ordinator.routines[
id - 1] = routine;
127 inline void destroy(routine_t
id)
129 Routine* routine = ordinator.routines[
id - 1];
130 assert(routine !=
nullptr);
133 ordinator.routines[
id - 1] =
nullptr;
134 ordinator.indexes.push_back(
id);
137 inline void __stdcall
entry(LPVOID)
139 routine_t
id = ordinator.current;
140 Routine* routine = ordinator.routines[
id - 1];
141 assert(routine !=
nullptr);
146 ordinator.current = 0;
148 SwitchToFiber(ordinator.fiber);
153 assert(ordinator.current == 0);
155 Routine* routine = ordinator.routines[
id - 1];
156 if (routine ==
nullptr)
162 if (routine->fiber ==
nullptr)
164 routine->fiber = CreateFiber(ordinator.stack_size,
entry, 0);
165 ordinator.current = id;
166 SwitchToFiber(routine->fiber);
170 ordinator.current = id;
171 SwitchToFiber(routine->fiber);
179 routine_t
id = ordinator.current;
180 Routine* routine = ordinator.routines[
id - 1];
181 if (routine ==
nullptr)
183 throw std::runtime_error(
"Error in yield of coroutine");
186 ordinator.current = 0;
187 SwitchToFiber(ordinator.fiber);
192 return ordinator.current;
196 template<
typename Function>
197 inline typename std::result_of<Function()>::type
198 await(Function &&func)
200 auto future = std::async(std::launch::async, func);
201 std::future_status status = future.wait_for(std::chrono::milliseconds(0));
203 while (status == std::future_status::timeout)
205 if (ordinator.current != 0)
208 status = future.wait_for(std::chrono::milliseconds(0));
215 template <
typename Function>
216 inline std::result_of_t<std::decay_t<Function>()>
await(Function&& func)
218 auto future = std::async(std::launch::async, func);
219 std::future_status status = future.wait_for(std::chrono::milliseconds(0));
221 while (status == std::future_status::timeout)
223 if (ordinator.current != 0)
226 status = future.wait_for(std::chrono::milliseconds(0));
270 for (
auto& routine : routines)
277 inline routine_t
create(std::function<
void()> f)
281 if (ordinator.indexes.empty())
283 ordinator.routines.push_back(routine);
284 return ordinator.routines.size();
288 routine_t
id = ordinator.indexes.front();
289 ordinator.indexes.pop_front();
290 assert(ordinator.routines[
id - 1] ==
nullptr);
291 ordinator.routines[
id - 1] = routine;
298 Routine* routine = ordinator.routines[
id - 1];
299 assert(routine !=
nullptr);
302 ordinator.routines[
id - 1] =
nullptr;
307 routine_t
id = ordinator.current;
308 Routine* routine = ordinator.routines[
id - 1];
312 ordinator.current = 0;
313 ordinator.indexes.push_back(
id);
318 assert(ordinator.current == 0);
320 Routine* routine = ordinator.routines[
id - 1];
321 if (routine ==
nullptr)
327 if (routine->
stack ==
nullptr)
332 getcontext(&routine->
ctx);
337 routine->
stack =
new char[ordinator.stack_size];
338 routine->
ctx.uc_stack.ss_sp = routine->
stack;
339 routine->
ctx.uc_stack.ss_size = ordinator.stack_size;
340 routine->
ctx.uc_link = &ordinator.ctx;
341 ordinator.current = id;
346 makecontext(&routine->
ctx, reinterpret_cast<void (*)(
void)>(
entry), 0);
350 swapcontext(&ordinator.ctx, &routine->
ctx);
354 ordinator.current = id;
355 swapcontext(&ordinator.ctx, &routine->
ctx);
363 routine_t
id = ordinator.current;
364 Routine* routine = ordinator.routines[
id - 1];
365 assert(routine !=
nullptr);
367 char* stack_top = routine->
stack + ordinator.stack_size;
368 char stack_bottom = 0;
369 assert(
size_t(stack_top - &stack_bottom) <= ordinator.stack_size);
371 ordinator.current = 0;
372 swapcontext(&routine->
ctx, &ordinator.ctx);
377 return ordinator.current;
380 template <
typename Function>
381 inline typename std::result_of<Function()>::type
await(Function&& func)
383 auto future = std::async(std::launch::async, func);
384 std::future_status status = future.wait_for(std::chrono::milliseconds(0));
386 while (status == std::future_status::timeout)
388 if (ordinator.current != 0)
391 status = future.wait_for(std::chrono::milliseconds(0));
398 template <
typename Type>
417 inline void push(
const Type& obj)
419 _list.push_back(obj);
420 if (_taker && _taker !=
current())
426 _list.push_back(std::move(obj));
427 if (_taker && _taker !=
current())
436 while (_list.empty())
439 Type obj = std::move(_list.front());
441 return std::move(obj);
451 if (_taker && _taker !=
current())
462 return _list.empty();
471 #endif //STDEX_COROUTINE_H_
static thread_local Ordinator ordinator
std::function< void()> func
std::list< routine_t > indexes
routine_t create(std::function< void()> f)
void destroy(routine_t id)
std::result_of< Function()>::type await(Function &&func)
void consumer(routine_t id)
void push(const Type &obj)
std::vector< Routine * > routines
Routine(std::function< void()> f)
ResumeResult resume(routine_t id)
Ordinator(size_t ss=STACK_LIMIT)