mirror of https://github.com/RainMark/cops.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
2.7 KiB
127 lines
2.7 KiB
#pragma once
|
|
|
|
#include <memory>
|
|
#include <functional>
|
|
#include <stdint.h>
|
|
|
|
#include <future.h>
|
|
|
|
#ifdef SPLIT_STACK
|
|
|
|
///////////////////////////
|
|
// forward declaration for splitstack-functions defined in libgcc
|
|
// https://github.com/gcc-mirror/gcc/blob/master/libgcc/generic-morestack.c
|
|
// https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/i386/morestack.S
|
|
|
|
enum splitstack_context_offsets {
|
|
MORESTACK_SEGMENTS = 0,
|
|
CURRENT_SEGMENT = 1,
|
|
CURRENT_STACK = 2,
|
|
STACK_GUARD = 3,
|
|
INITIAL_SP = 4,
|
|
INITIAL_SP_LEN = 5,
|
|
BLOCK_SIGNALS = 6,
|
|
|
|
NUMBER_OFFSETS = 10
|
|
};
|
|
|
|
extern "C" {
|
|
void *__splitstack_makecontext(std::size_t, void* [NUMBER_OFFSETS], std::size_t*);
|
|
void __splitstack_setcontext(void* [NUMBER_OFFSETS]);
|
|
void __splitstack_getcontext(void* [NUMBER_OFFSETS]);
|
|
void __splitstack_releasecontext(void* [NUMBER_OFFSETS]);
|
|
void __splitstack_resetcontext(void* [NUMBER_OFFSETS]);
|
|
void __splitstack_block_signals_context(void* [NUMBER_OFFSETS], int* new_value, int* old_value);
|
|
}
|
|
|
|
#endif
|
|
|
|
namespace cops {
|
|
class coro_t;
|
|
class event_loop_t;
|
|
}
|
|
|
|
using context = void*;
|
|
|
|
extern "C"
|
|
context switch_context(cops::coro_t* to, context ctx);
|
|
extern "C"
|
|
context make_context(context sp, void* entry);
|
|
|
|
namespace cops {
|
|
|
|
class stack_t {
|
|
public:
|
|
stack_t(size_t size = 64 * 1024) : size_(size) {
|
|
#ifdef SPLIT_STACK
|
|
sp_ = static_cast<char*>(__splitstack_makecontext(size_, ss_ctx_, &size_));
|
|
static int off = 0;
|
|
__splitstack_block_signals_context(ss_ctx_, &off, 0);
|
|
#else
|
|
sp_ = new char[size_];
|
|
#endif
|
|
}
|
|
~stack_t() {
|
|
#ifdef SPLIT_STACK
|
|
__splitstack_releasecontext(ss_ctx_);
|
|
#else
|
|
delete[] sp_;
|
|
#endif
|
|
}
|
|
|
|
void* sp() {
|
|
return sp_ + size_ - 1;
|
|
}
|
|
|
|
private:
|
|
char* sp_;
|
|
size_t size_;
|
|
#ifdef SPLIT_STACK
|
|
public:
|
|
using split_stack_context = void* [NUMBER_OFFSETS];
|
|
split_stack_context ss_ctx_{0};
|
|
split_stack_context next_{0};
|
|
#endif
|
|
};
|
|
|
|
#ifdef SPLIT_STACK
|
|
inline void switch_split_stack_context(stack_t::split_stack_context from,
|
|
stack_t::split_stack_context to) {
|
|
__splitstack_getcontext(from);
|
|
__splitstack_setcontext(to);
|
|
}
|
|
#endif
|
|
|
|
class coro_t {
|
|
public:
|
|
using Fn = std::function<void(void)>;
|
|
|
|
explicit coro_t(Fn&& fn)
|
|
: fn_(std::forward<Fn>(fn)) {
|
|
}
|
|
~coro_t() {
|
|
}
|
|
|
|
void switch_out();
|
|
void switch_in();
|
|
void detach(std::unique_ptr<coro_t>& self, event_loop_t* loop);
|
|
|
|
public:
|
|
context ctx_;
|
|
coro_t* next_;
|
|
stack_t stack_;
|
|
Fn fn_;
|
|
future_t<int> fut_;
|
|
};
|
|
|
|
extern coro_t* current;
|
|
void main(coro_t* coro, context ctx);
|
|
|
|
template <class Fn>
|
|
std::unique_ptr<coro_t> make_coro(Fn&& fn) {
|
|
auto coro = std::make_unique<coro_t>(std::forward<Fn>(fn));
|
|
coro->ctx_ = make_context(coro->stack_.sp(), (void*)main);
|
|
return coro;
|
|
}
|
|
|
|
} // cops
|
|
|