3#include <libcopp/utils/config/libcopp_build_features.h>
13#if defined(LIBCOPP_MACRO_THREAD_LOCAL)
26#ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
28void __splitstack_getcontext(
void *[LIBCOPP_MACRO_SEGMENTED_STACK_NUMBER]);
30void __splitstack_setcontext(
void *[LIBCOPP_MACRO_SEGMENTED_STACK_NUMBER]);
32void __splitstack_releasecontext(
void *[LIBCOPP_MACRO_SEGMENTED_STACK_NUMBER]);
34void __splitstack_block_signals_context(
void *[LIBCOPP_MACRO_SEGMENTED_STACK_NUMBER],
int *,
int *);
38LIBCOPP_COPP_NAMESPACE_BEGIN
41#if !LIBCOPP_MACRO_ENABLE_MULTI_THREAD
43#elif defined(LIBCOPP_MACRO_THREAD_LOCAL)
46static pthread_once_t gt_coroutine_init_once = PTHREAD_ONCE_INIT;
47static pthread_key_t gt_coroutine_tls_key;
48static void init_pthread_this_coroutine_context() { (void)pthread_key_create(>_coroutine_tls_key,
nullptr); }
52#if !LIBCOPP_MACRO_ENABLE_MULTI_THREAD || defined(LIBCOPP_MACRO_THREAD_LOCAL)
55 (void)pthread_once(>_coroutine_init_once, init_pthread_this_coroutine_context);
56 pthread_setspecific(gt_coroutine_tls_key, p);
61#if !LIBCOPP_MACRO_ENABLE_MULTI_THREAD || defined(LIBCOPP_MACRO_THREAD_LOCAL)
64 (void)pthread_once(>_coroutine_init_once, init_pthread_this_coroutine_context);
71 : runner_ret_code_(0),
75 private_buffer_size_(0),
81 if (flags & flag_type::EN_CFT_MASK) {
90 if (flags & flag_type::EN_CFT_MASK) {
99 return 0 != (flags_ & flags);
109 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acq_rel,
110 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acquire)) {
128 LIBCOPP_MACRO_NOEXCEPT {
136 if (
nullptr != src) {
142 if (
nullptr != src) {
147#ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
151 if (
nullptr != jump_transfer.
from_co) {
155 sizeof(from_sctx.segments_ctx));
158 __splitstack_getcontext(from_sctx.segments_ctx);
160 __splitstack_setcontext(to_sctx.segments_ctx);
165 assert(src_ctx.data);
166 if (
nullptr == src_ctx.data) {
177 if (
nullptr == ins_ptr) {
183 ins_ptr->
caller_ = src_ctx.fctx;
186 if (
nullptr != jump_src.
from_co) {
194#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
198#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
200 ins_ptr->unhandle_exception_ = std::current_exception();
222 LIBCOPP_COPP_NAMESPACE_ID::fcontext::transfer_t res;
229#ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
230 assert(&from_sctx != &to_sctx);
235 libcopp_internal_api_set::splitstack_swapcontext(from_sctx, to_sctx, jump_transfer);
237 res = LIBCOPP_COPP_NAMESPACE_ID::fcontext::copp_jump_fcontext_v2(to_fctx, &jump_transfer);
238 if (
nullptr == res.data) {
275#ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
286 size_t private_buffer_size) LIBCOPP_MACRO_NOEXCEPT {
292 if (0 != (private_buffer_size & (
sizeof(
size_t) - 1))) {
296 if (0 != (coroutine_size & (
sizeof(
size_t) - 1))) {
300 size_t stack_offset = align_stack_size(private_buffer_size + coroutine_size);
301 if (
nullptr == callee_stack.sp || callee_stack.size <= stack_offset) {
313 static_cast<size_t>(
reinterpret_cast<unsigned char *
>(callee_stack.sp) -
reinterpret_cast<unsigned char *
>(p));
314 if (this_offset <
sizeof(
coroutine_context) + private_buffer_size || this_offset > stack_offset) {
319 p->set_runner(std::move(runner));
321 if (&p->callee_stack_ != &callee_stack) {
322 p->callee_stack_ = callee_stack;
324 p->private_buffer_size_ = private_buffer_size;
327 p->priv_data_ =
reinterpret_cast<unsigned char *
>(p->callee_stack_.sp) - p->private_buffer_size_;
329 p->callee_stack_.size - stack_offset,
331 if (
nullptr == p->callee_) {
338#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
340 std::exception_ptr eptr;
341 int ret =
start(eptr, priv_data);
346LIBCOPP_COPP_API
int coroutine_context::start(std::exception_ptr &unhandled,
void *priv_data) LIBCOPP_MACRO_NOEXCEPT {
354#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
358 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_CAN_NOT_USE_CROSS_FCONTEXT_AND_FIBER;
370 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acq_rel,
371 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acquire)) {
387#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
388 jump_data.
from_co = LIBCOPP_COPP_NAMESPACE_ID::this_coroutine::get_coroutine();
392 jump_data.
to_co =
this;
395#ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
407#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
409 std::swap(unhandled, unhandle_exception_);
417#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
419 return start(unhandled, priv_data);
424 if (
nullptr == callee_) {
428 int from_status = status_type::EN_CRS_RUNNING;
429 int to_status = status_type::EN_CRS_READY;
430 if (check_flags(flag_type::EN_CFT_FINISHED)) {
431 to_status = status_type::EN_CRS_FINISHED;
433 if (
false == status_.compare_exchange_strong(from_status, to_status,
434 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acq_rel,
435 LIBCOPP_COPP_NAMESPACE_ID::util::lock::memory_order_acquire)) {
436 switch (from_status) {
437 case status_type::EN_CRS_INVALID:
439 case status_type::EN_CRS_READY:
441 case status_type::EN_CRS_FINISHED:
442 case status_type::EN_CRS_EXITED:
452 jump_data.
to_co =
nullptr;
454#ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
455 jump_to(caller_, callee_stack_, caller_stack_, jump_data);
457 jump_to(caller_, callee_stack_, callee_stack_, jump_data);
460 if (
nullptr != priv_data) {
470#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
478LIBCOPP_COPP_API
int yield(
void **priv_data) LIBCOPP_MACRO_NOEXCEPT {
479#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
485 return pco->
yield(priv_data);
478LIBCOPP_COPP_API
int yield(
void **priv_data) LIBCOPP_MACRO_NOEXCEPT {
…}
491LIBCOPP_COPP_NAMESPACE_END
base type of all coroutine context
LIBCOPP_COPP_API ~coroutine_context_base()
LIBCOPP_COPP_API bool set_flags(int flags) LIBCOPP_MACRO_NOEXCEPT
set all flags to true
LIBCOPP_COPP_API int set_runner(callback_type &&runner)
set runner
static LIBCOPP_COPP_API void set_this_coroutine_base(coroutine_context_base *ctx) LIBCOPP_MACRO_NOEXCEPT
set current coroutine
LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type< LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type< int > > status_
static LIBCOPP_COPP_API coroutine_context_base * get_this_coroutine_base() LIBCOPP_MACRO_NOEXCEPT
get current coroutine
LIBCOPP_COPP_API bool check_flags(int flags) const LIBCOPP_MACRO_NOEXCEPT
check flags
LIBCOPP_COPP_API coroutine_context_base() LIBCOPP_MACRO_NOEXCEPT
LIBCOPP_UTIL_FORCEINLINE void run_and_recv_retcode(void *priv_data)
coroutine entrance function
LIBCOPP_COPP_API bool is_finished() const LIBCOPP_MACRO_NOEXCEPT
get runner return code
LIBCOPP_COPP_API bool unset_flags(int flags) LIBCOPP_MACRO_NOEXCEPT
set all flags to false
std::function< int(void *)> callback_type
base type of all stackful coroutine context
LIBCOPP_COPP_API coroutine_context() LIBCOPP_MACRO_NOEXCEPT
fcontext::fcontext_t caller_
stack_context callee_stack_
LIBCOPP_COPP_API int start(void *priv_data=nullptr)
start coroutine
LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type< LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type< int > > status_
LIBCOPP_COPP_API int yield(void **priv_data=nullptr) LIBCOPP_MACRO_NOEXCEPT
yield coroutine
LIBCOPP_COPP_API ~coroutine_context()
LIBCOPP_COPP_API int resume(void *priv_data=nullptr)
resume coroutine
fcontext::fcontext_t callee_
coroutine_context_base::callback_type callback_type
static LIBCOPP_COPP_API int create(coroutine_context *p, callback_type &&runner, const stack_context &callee_stack, size_t coroutine_size, size_t private_buffer_size) LIBCOPP_MACRO_NOEXCEPT
create coroutine context at stack context callee_
#define LIBCOPP_UTIL_FORCEINLINE
#define LIBCOPP_UTIL_LIKELY_CONDITION(__C)
#define LIBCOPP_UTIL_UNLIKELY_CONDITION(__C)
static void jump_to(fcontext::fcontext_t &to_fctx, LIBCOPP_EXPLICIT_UNUSED_ATTR stack_context &from_sctx, LIBCOPP_EXPLICIT_UNUSED_ATTR stack_context &to_sctx, libcopp_internal_api_set::jump_src_data_t &jump_transfer) LIBCOPP_MACRO_NOEXCEPT
call platform jump to asm instruction
@ COPP_EC_SUCCESS
COPP_EC_SUCCESS.
@ COPP_EC_IS_RUNNING
COPP_EC_IS_RUNNING.
@ COPP_EC_FCONTEXT_MAKE_FAILED
COPP_EC_FCONTEXT_MAKE_FAILED.
@ COPP_EC_ALREADY_INITED
COPP_EC_ALREADY_INITED.
@ COPP_EC_NOT_READY
COPP_EC_NOT_READY.
@ COPP_EC_NOT_INITED
COPP_EC_NOT_INITED.
@ COPP_EC_UNKNOWN
COPP_EC_UNKNOWN.
@ COPP_EC_ALREADY_EXIST
COPP_EC_ALREADY_EXIST.
@ COPP_EC_ARGS_ERROR
COPP_EC_ARGS_ERROR.
@ COPP_EC_NOT_RUNNING
COPP_EC_NOT_RUNNING.
#define LIBCOPP_EXPLICIT_UNUSED_ATTR
maybe_unused attribute usage: LIBCOPP_EXPLICIT_UNUSED_ATTR int a; class LIBCOPP_EXPLICIT_UNUSED_ATTR ...
static coroutine_context_base * gt_current_coroutine
static void set_this_coroutine_context(coroutine_context_base *p)
static coroutine_context_base * get_this_coroutine_context()
LIBCOPP_BOOST_CONTEXT_DECL fcontext_t LIBCOPP_BOOST_CONTEXT_CALLDECL copp_make_fcontext_v2(void *sp, std::size_t size, void(*fn)(transfer_t))
LIBCOPP_COPP_API_HEAD_ONLY void swap(LIBCOPP_COPP_NAMESPACE_ID::memory::strong_rc_ptr< T > &a, LIBCOPP_COPP_NAMESPACE_ID::memory::strong_rc_ptr< T > &b) noexcept
Support std::swap for strong_rc_ptr.
LIBCOPP_COPP_API int yield(void **priv_data=nullptr) LIBCOPP_MACRO_NOEXCEPT
yield current coroutine
LIBCOPP_COPP_API coroutine_context * get_coroutine() LIBCOPP_MACRO_NOEXCEPT
get current coroutine
coroutine_context * from_co
coroutine_context * to_co
status of safe coroutine context base
@ EN_CRS_INVALID
EN_CRS_INVALID.
@ EN_CRS_READY
EN_CRS_READY.
@ EN_CRS_FINISHED
EN_CRS_FINISHED.
@ EN_CRS_EXITED
EN_CRS_EXITED.
@ EN_CRS_RUNNING
EN_CRS_RUNNING.
static void coroutine_context_callback(LIBCOPP_COPP_NAMESPACE_ID::fcontext::transfer_t src_ctx)
static LIBCOPP_UTIL_FORCEINLINE void set_callee(coroutine_context *src, const fcontext::fcontext_t &fctx)
static LIBCOPP_UTIL_FORCEINLINE void set_caller(coroutine_context *src, const fcontext::fcontext_t &fctx)