diff --git a/ostd/coroutine.hh b/ostd/coroutine.hh index d88f8fe..7655b2d 100644 --- a/ostd/coroutine.hh +++ b/ostd/coroutine.hh @@ -17,9 +17,10 @@ #include #include "ostd/types.hh" -#include "ostd/platform.hh" #include "ostd/range.hh" +#include "ostd/internal/context.hh" + namespace ostd { constexpr size_t COROUTINE_DEFAULT_STACK_SIZE = SIGSTKSZ; @@ -35,96 +36,6 @@ template struct coroutine_range; namespace detail { - /* from boost.fcontext */ - using fcontext_t = void *; - - struct transfer_t { - fcontext_t ctx; - void *data; - }; - - extern "C" OSTD_EXPORT - transfer_t OSTD_CDECL ostd_jump_fcontext( - fcontext_t const to, void *vp - ); - - extern "C" OSTD_EXPORT - fcontext_t OSTD_CDECL ostd_make_fcontext( - void *sp, size_t size, void (*fn)(transfer_t) - ); - - extern "C" OSTD_EXPORT - transfer_t OSTD_CDECL ostd_ontop_fcontext( - fcontext_t const to, void *vp, transfer_t (*fn)(transfer_t) - ); - - struct coroutine_context { - protected: - struct forced_unwind { - fcontext_t ctx; - forced_unwind(fcontext_t c): ctx(c) {} - }; - - coroutine_context() {} - - coroutine_context(coroutine_context const &) = delete; - coroutine_context(coroutine_context &&c): - p_stack(std::move(c.p_stack)), p_coro(c.p_coro), p_orig(c.p_orig), - p_except(std::move(c.p_except)) - { - c.p_coro = c.p_orig = nullptr; - } - - coroutine_context &operator=(coroutine_context const &) = delete; - coroutine_context &operator=(coroutine_context &&c) { - swap(c); - return *this; - } - - void call() { - coro_jump(); - if (p_except) { - std::rethrow_exception(std::move(p_except)); - } - } - - void unwind() { - ostd_ontop_fcontext( - std::exchange(p_coro, nullptr), nullptr, - [](transfer_t t) -> transfer_t { - throw forced_unwind{t.ctx}; - } - ); - } - - void coro_jump() { - p_coro = ostd_jump_fcontext(p_coro, this).ctx; - } - - void yield_jump() { - p_orig = ostd_jump_fcontext(p_orig, nullptr).ctx; - } - - void swap(coroutine_context &other) noexcept { - using std::swap; - swap(p_stack, other.p_stack); - swap(p_coro, other.p_coro); - swap(p_orig, other.p_orig); - swap(p_except, other.p_except); - } - - void make_context(size_t ss, void (*callp)(transfer_t)) { - p_stack = std::unique_ptr{new byte[ss]}; - p_coro = ostd_make_fcontext(p_stack.get() + ss, ss, callp); - } - - /* TODO: new'ing the stack is sub-optimal */ - std::unique_ptr p_stack; - fcontext_t p_coro; - fcontext_t p_orig; - std::exception_ptr p_except; - }; - /* like reference_wrapper but for any value */ template struct arg_wrapper { diff --git a/ostd/internal/context.hh b/ostd/internal/context.hh new file mode 100644 index 0000000..49757a0 --- /dev/null +++ b/ostd/internal/context.hh @@ -0,0 +1,112 @@ +/* Context switching and stack allocation. + * + * This file is part of OctaSTD. See COPYING.md for futher information. + */ + +#ifndef OSTD_INTERNAL_CONTEXT_HH +#define OSTD_INTERNAL_CONTEXT_HH + +#include +#include + +#include "ostd/types.hh" +#include "ostd/platform.hh" +#include "ostd/internal/win32.hh" + +namespace ostd { +namespace detail { + +/* from boost.fcontext */ +using fcontext_t = void *; + +struct transfer_t { + fcontext_t ctx; + void *data; +}; + +extern "C" OSTD_EXPORT +transfer_t OSTD_CDECL ostd_jump_fcontext( + fcontext_t const to, void *vp +); + +extern "C" OSTD_EXPORT +fcontext_t OSTD_CDECL ostd_make_fcontext( + void *sp, size_t size, void (*fn)(transfer_t) +); + +extern "C" OSTD_EXPORT +transfer_t OSTD_CDECL ostd_ontop_fcontext( + fcontext_t const to, void *vp, transfer_t (*fn)(transfer_t) +); + +struct coroutine_context { +protected: + struct forced_unwind { + fcontext_t ctx; + forced_unwind(fcontext_t c): ctx(c) {} + }; + + coroutine_context() {} + + coroutine_context(coroutine_context const &) = delete; + coroutine_context(coroutine_context &&c): + p_stack(std::move(c.p_stack)), p_coro(c.p_coro), p_orig(c.p_orig), + p_except(std::move(c.p_except)) + { + c.p_coro = c.p_orig = nullptr; + } + + coroutine_context &operator=(coroutine_context const &) = delete; + coroutine_context &operator=(coroutine_context &&c) { + swap(c); + return *this; + } + + void call() { + coro_jump(); + if (p_except) { + std::rethrow_exception(std::move(p_except)); + } + } + + void unwind() { + ostd_ontop_fcontext( + std::exchange(p_coro, nullptr), nullptr, + [](transfer_t t) -> transfer_t { + throw forced_unwind{t.ctx}; + } + ); + } + + void coro_jump() { + p_coro = ostd_jump_fcontext(p_coro, this).ctx; + } + + void yield_jump() { + p_orig = ostd_jump_fcontext(p_orig, nullptr).ctx; + } + + void swap(coroutine_context &other) noexcept { + using std::swap; + swap(p_stack, other.p_stack); + swap(p_coro, other.p_coro); + swap(p_orig, other.p_orig); + swap(p_except, other.p_except); + } + + void make_context(size_t ss, void (*callp)(transfer_t)) { + p_stack = std::unique_ptr{new byte[ss]}; + p_coro = ostd_make_fcontext(p_stack.get() + ss, ss, callp); + } + + /* TODO: new'ing the stack is sub-optimal */ + std::unique_ptr p_stack; + fcontext_t p_coro; + fcontext_t p_orig; + std::exception_ptr p_except; +}; + +} +} + +#endif