From f1341b913c0973670d1608c515210f5895c2c439 Mon Sep 17 00:00:00 2001 From: q66 Date: Sun, 12 Mar 2017 16:54:49 +0100 Subject: [PATCH] unify context_call between coroutines and generators --- ostd/coroutine.hh | 76 ++++++++++------------------------------ ostd/internal/context.hh | 50 +++++++++++++++++++------- 2 files changed, 56 insertions(+), 70 deletions(-) diff --git a/ostd/coroutine.hh b/ostd/coroutine.hh index c4a13c5..516a910 100644 --- a/ostd/coroutine.hh +++ b/ostd/coroutine.hh @@ -157,10 +157,9 @@ namespace detail { } template - void call_helper(Y &&yielder, F &func, std::index_sequence) { + void call_helper(F &func, std::index_sequence) { p_result = std::forward(func( - std::forward(yielder), - std::forward(std::get(p_args))... + Y{*this}, std::forward(std::get(p_args))... )); } @@ -191,8 +190,8 @@ namespace detail { } template - void call_helper(Y &&yielder, F &func, std::index_sequence) { - p_result = std::forward(func(std::forward(yielder))); + void call_helper(F &func, std::index_sequence) { + p_result = std::forward(func(Y{*this})); } void swap(coro_base &other) { @@ -222,11 +221,8 @@ namespace detail { void get_result() {} template - void call_helper(Y &&yielder, F &func, std::index_sequence) { - func( - std::forward(yielder), - std::forward(std::get(p_args))... - ); + void call_helper(F &func, std::index_sequence) { + func(Y{*this}, std::forward(std::get(p_args))...); } void swap(coro_base &other) { @@ -252,8 +248,8 @@ namespace detail { void get_result() {} template - void call_helper(Y &&yielder, F &func, std::index_sequence) { - func(std::forward(yielder)); + void call_helper(F &func, std::index_sequence) { + func(Y{*this}); } void swap(coro_base &other) { @@ -327,6 +323,8 @@ template struct coroutine: detail::coro_base { private: using base_t = detail::coro_base; + /* necessary so that context callback can access privates */ + friend struct detail::coroutine_context; public: using yield_type = detail::coro_yielder; @@ -344,7 +342,7 @@ public: this->set_dead(); return; } - this->make_context(sa, &context_call); + this->template make_context>(sa); } template @@ -395,31 +393,10 @@ public: } private: - /* the main entry point of the coroutine */ - template - static void context_call(detail::transfer_t t) { - auto &self = *(static_cast(t.data)); - self.p_orig = t.ctx; - if (self.is_hold()) { - /* we never got to execute properly, we're HOLD because we - * jumped here without setting the state to EXEC before that - */ - goto release; - } - try { - self.call_helper( - yield_type{self}, self.p_func, std::index_sequence_for{} - ); - } catch (detail::coroutine_context::forced_unwind v) { - /* forced_unwind is unique */ - self.p_orig = v.ctx; - } catch (...) { - /* some other exception, will be rethrown later */ - self.p_except = std::current_exception(); - } - /* switch back, release stack */ -release: - self.template finish(); + void resume_call() { + base_t::template call_helper( + p_func, std::index_sequence_for{} + ); } std::function p_func; @@ -440,6 +417,7 @@ template struct generator: detail::coroutine_context { private: using base_t = detail::coroutine_context; + friend struct detail::coroutine_context; struct yielder { yielder(generator &g): p_gen(g) {} @@ -473,7 +451,7 @@ public: this->set_dead(); return; } - this->make_context(sa, &context_call); + this->template make_context>(sa); /* generate an initial value */ resume(); } @@ -549,24 +527,8 @@ public: } private: - /* the main entry point of the generator */ - template - static void context_call(detail::transfer_t t) { - auto &self = *(static_cast(t.data)); - self.p_orig = t.ctx; - if (self.is_hold()) { - goto release; - } - try { - self.p_func(yield_type{self}); - } catch (detail::coroutine_context::forced_unwind v) { - self.p_orig = v.ctx; - } catch (...) { - self.p_except = std::current_exception(); - } -release: - self.p_result = nullptr; - self.template finish(); + void resume_call() { + p_func(yield_type{*this}); } std::function p_func; diff --git a/ostd/internal/context.hh b/ostd/internal/context.hh index 0a754b3..ab64f64 100644 --- a/ostd/internal/context.hh +++ b/ostd/internal/context.hh @@ -101,17 +101,6 @@ protected: ); } - template - void finish() { - set_dead(); - ostd_ontop_fcontext(p_orig, this, [](transfer_t t) -> transfer_t { - auto &self = *(static_cast(t.data)); - auto &sa = *(static_cast(self.p_sa)); - sa.deallocate(self.p_stack); - return { nullptr, nullptr }; - }); - } - void coro_jump() { p_coro = ostd_jump_fcontext(p_coro, this).ctx; } @@ -144,7 +133,18 @@ protected: } template - void make_context(SA &sa, void (*callp)(transfer_t)) { + void finish() { + set_dead(); + ostd_ontop_fcontext(p_orig, this, [](transfer_t t) -> transfer_t { + auto &self = *(static_cast(t.data)); + auto &sa = *(static_cast(self.p_sa)); + sa.deallocate(self.p_stack); + return { nullptr, nullptr }; + }); + } + + template + void make_context(SA &sa) { p_stack = sa.allocate(); constexpr size_t salign = alignof(SA); @@ -155,10 +155,34 @@ protected: size_t asize = p_stack.size - (static_cast(p_stack.ptr) - static_cast(sp)); - p_coro = ostd_make_fcontext(sp, asize, callp); + p_coro = ostd_make_fcontext(sp, asize, &context_call); p_sa = new (sp) SA(std::move(sa)); } + template + static void context_call(detail::transfer_t t) { + auto &self = *(static_cast(t.data)); + self.p_orig = t.ctx; + if (self.is_hold()) { + /* we never got to execute properly, we're HOLD because we + * jumped here without setting the state to EXEC before that + */ + goto release; + } + try { + self.resume_call(); + } catch (detail::coroutine_context::forced_unwind v) { + /* forced_unwind is unique */ + self.p_orig = v.ctx; + } catch (...) { + /* some other exception, will be rethrown later */ + self.p_except = std::current_exception(); + } + /* switch back, release stack */ +release: + self.template finish(); + } + stack_context p_stack; fcontext_t p_coro; fcontext_t p_orig;