void coroutine_context_base::coroutine_context_callback(::copp::fcontext::transfer_t src_ctx) {assert(src_ctx.data);if (NULL==src_ctx.data) {abort();return; } // copy jump_src_data_t in case it's destroyed laterjump_src_data_t jump_src =*reinterpret_cast<jump_src_data_t*>(src_ctx.data); // this must in a coroutine coroutine_context_base *ins_ptr =jump_src.to_co;assert(ins_ptr);if (NULL== ins_ptr) {abort();return; } // update caller of to_coins_ptr->caller_ =src_ctx.fctx; // save from_co's fcontext and switch statusif (UTIL_CONFIG_NULLPTR !=jump_src.from_co) {jump_src.from_co->callee_ =src_ctx.fctx;int from_status =status_t::EN_CRS_RUNNING; // from coroutine change status from running to readyjump_src.from_co->status_.compare_exchange_strong(from_status,status_t::EN_CRS_READY); } // this_coroutineset_this_coroutine_context(ins_ptr); // run logic codeins_ptr->run_and_recv_retcode(jump_src.priv_data);ins_ptr->status_.store(status_t::EN_CRS_FINISHED); // jump back to callerins_ptr->yield();}
最重要的是save from_co's fcontext and switch status下面的这一段。这里的作用就是切入后要把跳入前的上下文保存到来源的协程中。
然后是恢复的流程(调用resume/yield函数):
void coroutine_context_base::jump_to(fcontext::fcontext_t&to_fctx,stack_context&from_sctx,stack_context&to_sctx,jump_src_data_t&jump_transfer) UTIL_CONFIG_NOEXCEPT { copp::fcontext::transfer_t res;jump_src_data_t*jump_src;int from_status;bool swap_success;// can not use any more stack now// can not initialize those vars here#ifdefCOPP_MACRO_USE_SEGMENTED_STACKSassert(&from_sctx !=&to_sctx); // ROOT->A: jump_transfer.from_co == NULL, jump_transfer.to_co == A, from_sctx == A.caller_stack_, skip backup segments
// A->B.start(): jump_transfer.from_co == A, jump_transfer.to_co == B, from_sctx == B.caller_stack_, backup segments
// B.yield()->A: jump_transfer.from_co == B, jump_transfer.to_co == NULL, from_sctx == B.callee_stack_, skip backup segments
if (UTIL_CONFIG_NULLPTR !=jump_transfer.from_co) {__splitstack_getcontext(jump_transfer.from_co->callee_stack_.segments_ctx);if (&from_sctx !=&jump_transfer.from_co->callee_stack_) { memcpy(&from_sctx.segments_ctx, &jump_transfer.from_co->callee_stack_.segments_ctx, sizeof(from_sctx.segments_ctx));
} } else {__splitstack_getcontext(from_sctx.segments_ctx); }__splitstack_setcontext(to_sctx.segments_ctx);#endif res = copp::fcontext::copp_jump_fcontext(to_fctx,&jump_transfer);if (NULL==res.data) {abort();return; } jump_src =reinterpret_cast<jump_src_data_t*>(res.data);assert(jump_src); /** * save from_co's fcontext and switch status * we should use from_co in transfer_t, because it may not jump from jump_transfer.to_co * * if we jump sequence is A->B->C->A.resume(), and if this call is A->B, then * jump_src->from_co = C, jump_src->to_co = A, jump_transfer.from_co = A, jump_transfer.to_co = B * and now we should save the callee of C and set the caller of A = C * * if we jump sequence is A->B.yield()->A, and if this call is A->B, then * jump_src->from_co = B, jump_src->to_co = NULL, jump_transfer.from_co = A, jump_transfer.to_co = B * and now we should save the callee of B and should change the caller of A * */ // update caller of to_co if not jump from yield modeif (UTIL_CONFIG_NULLPTR !=jump_src->to_co) {jump_src->to_co->caller_ =res.fctx; }if (UTIL_CONFIG_NULLPTR !=jump_src->from_co) {jump_src->from_co->callee_ =res.fctx; from_status =jump_src->from_co->status_.load();if (status_t::EN_CRS_RUNNING == from_status) {jump_src->from_co->status_.compare_exchange_strong(from_status,status_t::EN_CRS_READY); } elseif (status_t::EN_CRS_FINISHED == from_status) { // if in finished status, change it to exitedjump_src->from_co->status_.store(status_t::EN_CRS_EXITED); } } // private datajump_transfer.priv_data =jump_src->priv_data; // this_coroutineset_this_coroutine_context(jump_transfer.from_co); // resume running status of from_coif (NULL!=jump_transfer.from_co) { from_status =jump_transfer.from_co->status_.load(); swap_success =false;while (!swap_success &&status_t::EN_CRS_READY == from_status) { swap_success = jump_transfer.from_co->status_.compare_exchange_strong(from_status, status_t::EN_CRS_RUNNING);
} }}
同样,需要关注的部分是update caller of to_co if not jump from yield mode后面的保存上下下文的部分。