3 #include <libcopp/utils/config/libcopp_build_features.h>
21 #if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
22 LIBCOPP_COPP_NAMESPACE_BEGIN
23 struct fiber_context_tls_data_t {
24 using jump_src_data_t = coroutine_context_fiber::jump_src_data_t;
27 jump_src_data_t jump_data;
28 fiber_context_tls_data_t() : thread_fiber(nullptr) {
29 jump_data.from_co =
nullptr;
30 jump_data.from_fiber =
nullptr;
31 jump_data.to_co =
nullptr;
32 jump_data.to_fiber =
nullptr;
33 jump_data.priv_data =
nullptr;
35 ~fiber_context_tls_data_t() {
37 ConvertFiberToThread();
38 thread_fiber =
nullptr;
43 # if defined(LIBCOPP_LOCK_DISABLE_THIS_MT) && LIBCOPP_LOCK_DISABLE_THIS_MT
44 static fiber_context_tls_data_t gt_current_fiber;
46 static COPP_MACRO_THREAD_LOCAL fiber_context_tls_data_t gt_current_fiber;
49 static inline LPVOID get_this_fiber_address() {
50 if (!gt_current_fiber.thread_fiber) {
51 gt_current_fiber.thread_fiber = ConvertThreadToFiber(
nullptr);
54 return gt_current_fiber.thread_fiber;
57 static inline fiber_context_tls_data_t::jump_src_data_t &get_this_fiber_jump_src() {
58 return gt_current_fiber.jump_data;
61 struct libcopp_fiber_internal_api_set {
62 using jump_src_data_t = coroutine_context_fiber::jump_src_data_t;
64 static inline fiber_context_tls_data_t::jump_src_data_t &build_this_fiber_jump_src(coroutine_context_fiber &to_ctx,
66 fiber_context_tls_data_t::jump_src_data_t &jump_src = get_this_fiber_jump_src();
69 if (
nullptr == jump_src.from_co) {
70 jump_src.from_fiber = get_this_fiber_address();
72 jump_src.from_fiber = jump_src.from_co->callee_;
75 jump_src.to_co = &to_ctx;
76 jump_src.to_fiber = to_ctx.callee_;
77 jump_src.priv_data =
data;
81 UTIL_FORCEINLINE static void set_caller(coroutine_context_fiber *src, LPVOID fctx) {
93 static void __stdcall coroutine_fiber_context_callback(LPVOID lpParameter) {
94 coroutine_context_fiber *ctx =
reinterpret_cast<coroutine_context_fiber *
>(lpParameter);
102 jump_src_data_t jump_src = get_this_fiber_jump_src();
105 coroutine_context_fiber *ins_ptr = jump_src.to_co;
106 assert(ins_ptr == ctx);
107 if (ctx != ins_ptr) {
113 ins_ptr->caller_ = jump_src.from_fiber;
124 # if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
127 ins_ptr->run_and_recv_retcode(jump_src.priv_data);
128 # if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
130 ins_ptr->unhandle_exception_ = std::current_exception();
134 ins_ptr->flags_ |= coroutine_context_fiber::flag_type::EN_CFT_FINISHED;
145 static inline void jump_to(LPVOID to_fiber,
146 libcopp_fiber_internal_api_set::jump_src_data_t &jump_src) LIBCOPP_MACRO_NOEXCEPT {
147 coroutine_context_fiber *restore_co = jump_src.from_co;
149 SwitchToFiber(to_fiber);
152 jump_src = get_this_fiber_jump_src();
168 libcopp_fiber_internal_api_set::set_caller(jump_src.to_co, jump_src.from_fiber);
177 LIBCOPP_COPP_API coroutine_context_fiber::coroutine_context_fiber() LIBCOPP_MACRO_NOEXCEPT :
coroutine_context_base(),
181 flags_ |= flag_type::EN_CFT_IS_FIBER;
185 LIBCOPP_COPP_API coroutine_context_fiber::~coroutine_context_fiber() {
186 if (
nullptr != callee_) {
187 DeleteFiber(callee_);
191 LIBCOPP_COPP_API
int coroutine_context_fiber::create(coroutine_context_fiber *p, callback_type &&runner,
193 size_t private_buffer_size,
194 size_t stack_reserve_size_of_fiber) LIBCOPP_MACRO_NOEXCEPT {
200 if (0 != (private_buffer_size & (
sizeof(
size_t) - 1))) {
204 if (0 != (coroutine_size & (
sizeof(
size_t) - 1))) {
208 size_t stack_offset = private_buffer_size + coroutine_size;
209 if (
nullptr == callee_stack.sp || callee_stack.size <= stack_offset) {
216 if (callee_stack.sp <= p || coroutine_size <
sizeof(coroutine_context_fiber)) {
220 size_t this_offset =
reinterpret_cast<unsigned char *
>(callee_stack.sp) -
reinterpret_cast<unsigned char *
>(p);
221 if (this_offset <
sizeof(coroutine_context_fiber) + private_buffer_size || this_offset > stack_offset) {
226 p->set_runner(std::move(runner));
228 if (&p->callee_stack_ != &callee_stack) {
229 p->callee_stack_ = callee_stack;
231 p->private_buffer_size_ = private_buffer_size;
234 p->priv_data_ =
reinterpret_cast<unsigned char *
>(p->callee_stack_.sp) - p->private_buffer_size_;
236 CreateFiberEx(0, stack_reserve_size_of_fiber,
238 &libcopp_fiber_internal_api_set::coroutine_fiber_context_callback, p);
239 if (
nullptr == p->callee_) {
246 # if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
247 LIBCOPP_COPP_API
int coroutine_context_fiber::start(
void *priv_data) {
248 std::exception_ptr eptr;
249 int ret = start(eptr, priv_data);
254 LIBCOPP_COPP_API
int coroutine_context_fiber::start(std::exception_ptr &unhandled,
255 void *priv_data) LIBCOPP_MACRO_NOEXCEPT {
257 LIBCOPP_COPP_API
int coroutine_context_fiber::start(
void *priv_data) {
259 if (
nullptr == callee_) {
264 if (this_ctx && !this_ctx->
check_flags(flag_type::EN_CFT_IS_FIBER)) {
268 int from_status = status_type::EN_CRS_READY;
270 if (from_status < status_type::EN_CRS_READY) {
274 if (status_.compare_exchange_strong(from_status, status_type::EN_CRS_RUNNING,
280 if (from_status > status_type::EN_CRS_RUNNING) {
285 if (status_type::EN_CRS_RUNNING == from_status) {
291 libcopp_fiber_internal_api_set::jump_src_data_t jump_src =
292 libcopp_fiber_internal_api_set::build_this_fiber_jump_src(*
this, priv_data);
296 if (check_flags(flag_type::EN_CFT_FINISHED)) {
301 # if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
303 std::swap(unhandled, unhandle_exception_);
310 LIBCOPP_COPP_API
int coroutine_context_fiber::resume(
void *priv_data) {
return start(priv_data); }
311 # if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
312 LIBCOPP_COPP_API
int coroutine_context_fiber::resume(std::exception_ptr &unhandled,
313 void *priv_data) LIBCOPP_MACRO_NOEXCEPT {
314 return start(unhandled, priv_data);
319 if (
nullptr == callee_) {
323 int from_status = status_type::EN_CRS_RUNNING;
324 int to_status = status_type::EN_CRS_READY;
325 if (check_flags(flag_type::EN_CFT_FINISHED)) {
326 to_status = status_type::EN_CRS_FINISHED;
328 if (
false == status_.compare_exchange_strong(from_status, to_status,
331 switch (from_status) {
332 case status_type::EN_CRS_INVALID:
334 case status_type::EN_CRS_READY:
336 case status_type::EN_CRS_FINISHED:
337 case status_type::EN_CRS_EXITED:
345 jump_src_data_t jump_data;
346 jump_data.from_co =
this;
347 jump_data.from_fiber = callee_;
348 jump_data.to_co =
nullptr;
349 jump_data.to_fiber = caller_;
350 jump_data.priv_data =
nullptr;
354 if (
nullptr != priv_data) {
355 *priv_data = jump_data.priv_data;
361 namespace this_fiber {
362 LIBCOPP_COPP_API coroutine_context_fiber *
get_coroutine() LIBCOPP_MACRO_NOEXCEPT {
367 return static_cast<coroutine_context_fiber *
>(ret);
370 LIBCOPP_COPP_API
int yield(
void **priv_data) LIBCOPP_MACRO_NOEXCEPT {
372 if (
nullptr != pco) {
373 return pco->yield(priv_data);
379 LIBCOPP_COPP_NAMESPACE_END
base type of all coroutine context
static LIBCOPP_COPP_API void set_this_coroutine_base(coroutine_context_base *ctx) LIBCOPP_MACRO_NOEXCEPT
set current coroutine
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
static void jump_to(fcontext::fcontext_t &to_fctx, EXPLICIT_UNUSED_ATTR stack_context &from_sctx, 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_CAN_NOT_USE_CROSS_FCONTEXT_AND_FIBER
COPP_EC_CAN_NOT_USE_CROSS_FCONTEXT_AND_FIBER.
@ 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_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.
导入继承关系约束 Licensed under the MIT licenses.
#define COPP_UNLIKELY_IF(...)
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
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
void swap(intrusive_ptr< T > &lhs, intrusive_ptr< T > &rhs)