move coroutine context stuff to a separate file

master
Daniel Kolesa 2017-03-07 21:29:12 +01:00
parent e97e70b427
commit 3145ebe0c9
2 changed files with 114 additions and 91 deletions

View File

@ -17,9 +17,10 @@
#include <optional>
#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<typename T>
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<byte[]>{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<byte[]> p_stack;
fcontext_t p_coro;
fcontext_t p_orig;
std::exception_ptr p_except;
};
/* like reference_wrapper but for any value */
template<typename T>
struct arg_wrapper {

View File

@ -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 <memory>
#include <exception>
#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<byte[]>{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<byte[]> p_stack;
fcontext_t p_coro;
fcontext_t p_orig;
std::exception_ptr p_except;
};
}
}
#endif