forked from OctaForge/libostd
move coroutine context stuff to a separate file
This commit is contained in:
parent
e97e70b427
commit
3145ebe0c9
|
@ -17,9 +17,10 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "ostd/types.hh"
|
#include "ostd/types.hh"
|
||||||
#include "ostd/platform.hh"
|
|
||||||
#include "ostd/range.hh"
|
#include "ostd/range.hh"
|
||||||
|
|
||||||
|
#include "ostd/internal/context.hh"
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
|
|
||||||
constexpr size_t COROUTINE_DEFAULT_STACK_SIZE = SIGSTKSZ;
|
constexpr size_t COROUTINE_DEFAULT_STACK_SIZE = SIGSTKSZ;
|
||||||
|
@ -35,96 +36,6 @@ template<typename T>
|
||||||
struct coroutine_range;
|
struct coroutine_range;
|
||||||
|
|
||||||
namespace detail {
|
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 */
|
/* like reference_wrapper but for any value */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct arg_wrapper {
|
struct arg_wrapper {
|
||||||
|
|
112
ostd/internal/context.hh
Normal file
112
ostd/internal/context.hh
Normal 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
|
Loading…
Reference in a new issue