void CoroutineManager::runCorEvent(VarisEvent* event){ size_t workerNumber = event->getCoroutine()->getId(); Coroutine* coroutine = &(coroutines_[workerNumber]); lastCoroutine_ = curCoroutine_ ; curCoroutine_ = coroutine->getId(); event->callback(); }
bool CoroutineManager::doWork(VarisEvent* event){ Coroutine* cor; if((cor = event->getCoroutine())!=NULL &&( event->getListenEventType()&T_COROUTINE)){ cor->setStatus(BUSY); runCorEvent(event); return true; } //no coroutine free if(freeCoroutine_.empty()){ return false; } if(!(event->getListenEventType()&T_COROUTINE)){ int tmpCoroutine = freeCoroutine_.top(); freeCoroutine_.pop(); ucontext_t* context = coroutines_[tmpCoroutine].getContext(); context->uc_link = coroutines_[0].getContext(); Coroutine* coroutine = &(coroutines_[tmpCoroutine]); coroutine->setStatus(READY); event->setCoroutine(coroutine); makecontext(context,(corfunc)(VarisEvent::handle),1,event); runCoroutine(tmpCoroutine); return true; } return false; }
void XsimCore::startSim() { while (!futureEvents.isEmpty()) { TimeSliceEvent* event = futureEvents.getNextEvent(); time = event->getTime(); std::cout << "Time: " << time << std::endl; while (!event->isEmpty()) { // Execute coroutines while (!event->isCoroutinesEmpty()) { Coroutine* coroutine = event->popNextCoroutine(); // Execute coroutine if it is not already running. if (coroutine->isFinished()) { coroutine->reset(); } coroutine->start(); } // Execute functions while (!event->isFunctionsEmpty()) { FunctionPtr function = event->popNextFunction(); // Execute function function(functionUserData[function]); } } futureEvents.removeFirstEvent(); } }
//notice void CoroutineManager::onCoroutineFinished(CoroutineManager* th){ while(true){ Coroutine cor = th->coroutines_[th->curCoroutine_]; cor.setStatus(FREE); th->freeCoroutine_.push(th->curCoroutine_); th->curCoroutine_ = 0; th->runCoroutine(1); } }
static void CALLBACK coroutine_trampoline(void *co_) { Coroutine *co = co_; while (true) { co->entry(co->entry_arg); qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); } }
void Detach() { Coroutine *Next = Current->Caller; if (Next) Current->Caller = Next->Callee = 0; else { Next = &Main; while (Next->Callee) Next = Next->Callee; } Next->Enter(); }
// virtual void Subroutine::Invoke( string& funcName ){ assert( this->m_freeList.size() > 0 ); Coroutine* c = this->m_freeList.back(); m_freeList.pop_back(); assert( c ); this->m_activeList.push_back( c ); c->executeFunction( funcName ); if( c->m_state == STATE_IDLE ){ this->m_activeList.remove( c ); this->m_freeList.push_back( c ); } }
void tst_basic::smallStack() { using namespace StackTests; Coroutine *c = Coroutine::build(&simpleCoroutine); c->createStack(1000); counter = 0; QCOMPARE(c->cont(), true); QCOMPARE(counter, 1); QCOMPARE(c->cont(), true); QCOMPARE(counter, 2); delete c; }
// virtual void Subroutine::OnUpdate(){ list<Coroutine*>::iterator iter = this->m_activeList.begin(); while( iter != this->m_activeList.end() ){ Coroutine* c = *iter; c->execute(); if( c->m_state == STATE_IDLE ){ iter++; this->m_activeList.remove( c ); this->m_freeList.push_back( c ); continue; } iter++; } }
bool CoroutineService::sleep(const int64_t secs){ Coroutine* cr =Coroutine::Running(); if(!cr){ WARN("service %s(%lld) fail to sleep, in main thread", name(), (long long)m_id); return false; } if(m_processing_command){ WARN("service %s(%lld) fail to sleep, in processing command", name(), (long long)m_id); return false; } const int64_t cr_id =cr->getId(); m_sleeper_table->set(cr_id, SafeNew<Int64>(DateTime::Now() + secs)); ASSERT(cr->yield(0, -1)); m_sleeper_table->remove(cr_id); return true; }
int64_t CoroutinePool::go(Coroutine::PFN_COROUTINE_TASK pfn, Object* arg, int64_t& cr_id){ if(m_cleaning){ WARN("coroutine pool go failed, cleaning"); return -ErrorCode::SYSTEM_ERROR; } if(!pfn){ return -ErrorCode::INVALID_ARG; } // prepare Coroutine* cr =_prepare_coroutine(pfn, arg); const int64_t result =_resume(cr, 0, 0); if(result == Coroutine::STATUS_WAITING){ cr_id =cr->getId(); } return result; }
/** helper **/ Coroutine* CoroutinePool::_prepare_coroutine(Coroutine::PFN_COROUTINE_TASK pfn, Object* arg){ // prepare coroutine GENERATE_ID(m_coroutine_id); Coroutine* cr =0; if(m_idle_coroutine_list->size() > 0){ cr =dynamic_cast< Coroutine* >(m_idle_coroutine_list->back()); m_active_coroutine_table->set(m_coroutine_id, cr); m_idle_coroutine_list->pop_back(); } else{ cr =SafeNew<Coroutine>(this); m_active_coroutine_table->set(m_coroutine_id, cr); } // set status cr->setId(m_coroutine_id); cr->setTask(pfn, arg); return cr; }
void ServletManager::execute(unsigned servlet_id, unsigned seq, unsigned size, Peer *peer) noexcept { if (servlet_id == GX_KEEPALIVE_SERVLET) { if (seq || size) { peer->close(); return; } return; } auto it = _map.find(servlet_id); if (it == _map.end()) { log_debug("servlet 0x%x not registered.", servlet_id); peer->close(); return; } ServletBase *servlet = it->second; Coroutine *co; bool use_co = servlet->use_coroutine(); if (use_co) { co = Coroutine::spawn(routine, peer); } else { co = Coroutine::self(); } if (!co) { log_debug("no coroutine available."); peer->input().read(nullptr, size); return; } co->context()->_servlet = servlet; co->context()->_seq = seq; co->context()->_size = size; if (use_co) { co->resume(); } else { routine(peer); } }
static void coroutine_trampoline(int i0, int i1) { union cc_arg arg; CoroutineUContext *self; Coroutine *co; arg.i[0] = i0; arg.i[1] = i1; self = arg.p; co = &self->base; /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } while (true) { co->entry(co->entry_arg); qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); } }
static void readScript(Coroutine<const char*>& self) { LineEditor* console = LineEditor::Get(); console->Open(); std::string line; do { line = console->Prompt("> "); if (line.empty()) continue; self.yield(line.c_str()); } while (true); }
void CoroutinePool::finalize(){ m_cleaning =true; // clean idle list for(int64_t i=0; i<m_idle_coroutine_list->size(); ++i){ Coroutine* cr =static_cast< Coroutine* >(m_idle_coroutine_list->get(i)); cr->resume(SafeNew<Error>(ErrorCode::COROUTINE_CLEAN), 0); ASSERT(cr->getStatus() == Coroutine::STATUS_DEAD); } CLEAN_POINTER(m_idle_coroutine_list); // clean active table Hash* active_cr_tb =m_active_coroutine_table; m_active_coroutine_table =0; HashIterator* it =static_cast< HashIterator* >(active_cr_tb->iterator()); while(it->next()){ Coroutine* cr =static_cast< Coroutine* >(it->getValue()); cr->resume(SafeNew<Error>(ErrorCode::COROUTINE_CLEAN), 0); ASSERT(cr->getStatus() == Coroutine::STATUS_DEAD); } CLEAN_POINTER(active_cr_tb); // super Super::finalize(); }
/** entry **/ void Coroutine::_entry(){ // prepare Coroutine* self =Running(); ASSERT(self); self->retain(); // loop while(1){ // check break if(Error* err= dynamic_cast< Error* >(self->m_resume_param)){ if(err->getCode() == ErrorCode::COROUTINE_CLEAN){ break; } } // run task try{ if(self->m_task){ self->m_task(self->m_arg); self->m_task =0; CLEAN_POINTER(self->m_arg); } } catch(...){ ERROR("coroutine exec task occurs exception, perhaps coroutine is cleaned"); break; } // yield self->_yield(0, STATUS_IDLE); } // clean INFO("coroutine %lld exit", (long long)self->m_id); self->m_status =STATUS_DEAD; g_running =0; self->release(); }
/** coroutine manager **/ void CoroutinePool::update(const int64_t now){ // process timeout if(m_active_coroutine_table && m_active_coroutine_table->size()>0){ // prepare Int64Array* ls =0; HashIterator* it =static_cast< HashIterator* >(m_active_coroutine_table->iterator()); while(it->next()){ Coroutine* cr =static_cast< Coroutine* >(it->getValue()); if(cr->isWaitingAndExpire(now)){ if(!ls){ ls =SafeNew<Int64Array>(); } ls->push_back(cr->getId()); } } // resume if(ls && ls->size()>0){ const int64_t n =ls->size(); for(int64_t i=0; i<n; ++i){ resume(ls->get(i), SafeNew<Error>(ErrorCode::TIMEOUT), 0); } } } }
PRIVATE void __sched(Coroutine coro) { long ret; void* para = regsw(coro->env, NULL); MAIN_RUN: para = coro->main(coro, para); coro->state = CORO_END; END_AGAIN: ret = (long)regsw(coro->env, para); switch(ret) { case CORO_PROMPT_RESET: para = regsw(coro->env, NULL); goto MAIN_RUN; default: /* can not resume coroutine whose state is C_END */ /* this situation can be seen as a kind of error */ para = NULL; goto END_AGAIN; } }
void CoroutineManager::runCoroutine(size_t workerNumber){ Coroutine* coroutine = &(coroutines_[workerNumber]); lastCoroutine_ = curCoroutine_ ; curCoroutine_ = coroutine->getId(); coroutine->work(); }
void Coroutine::setupEntry() { Coroutine *current = (Coroutine *)sys().getContextOfCoroutine(sys().activeCoroutine()); current->entry(); }
/** rpc **/ Object* CoroutineService::rpc(const int64_t who, const int64_t to, const int64_t cmd, const int64_t res_proto_grp_id, Object* req_param){ if(to == getId()){ ERROR("service %s(%lld) can't request self", name(), (long long)m_id); return 0; } // prepare Coroutine* cr =Coroutine::Running(); if(!cr){ WARN("service %s(%lld) %lld fail to rpc to %lld, in main thread", name(), (long long)m_id, (long long)who, (long long)to); return 0; } ASSERT(cr->canYield()); const int64_t cr_id =cr->getId(); // set rpc info CoroutineRpcInfo* rpc_info =SafeNew<CoroutineRpcInfo>(res_proto_grp_id, cr_id); if(!set_rpc(rpc_info)){ return 0; } const int64_t rpc_id =rpc_info->getId(); // prepare packet PACKET packet; packet.from =getId(); packet.to =to; packet.who =who; packet.sn =rpc_id; packet.command =cmd; packet.option =0; // request if(!DispatcherManager::RequestByObject(this, packet, req_param)){ WARN("service %s(%lld) %lld fail to rpc to %lld, service not ready", name(), (long long)m_id, (long long)who, (long long)to); return 0; } rpc_info->set(rpc_id, this); ENSURE(cr->yield(0, rpc_id)); // process respond if(Command* respond =dynamic_cast< Command* >(cr->getResumeParam())){ // prepare const PACKET res_packet =respond->getPacket(); if(res_packet.sn != static_cast<uint64_t>(rpc_id)){ WARN("service %s(%lld) %lld fail to rpc to %lld, rpc id mismatch", name(), (long long)m_id, (long long)who, (long long)to); return 0; } // body is object pointer if(res_packet.option & OPT_BODY_IS_OBJECT_POINTER){ return respond; } // body is protocol if(res_proto_grp_id>0){ Bytes* res_bs =respond->getBody(); const int64_t res_cmd =static_cast<int64_t>(res_packet.command); const int64_t group_id =res_proto_grp_id; const int64_t protocol_id =res_cmd; ProtocolBase* res_proto = ProtocolManager::CreateProtocol(group_id, protocol_id); if(!res_proto){ ERROR("service %s(%lld) %lld fail to rpc to %lld, create protocol group %lld id %lld error", name(), (long long)m_id, (long long)who, (long long)to, (long long)group_id, (long long)protocol_id); return 0; } if(!res_proto->fromBytes(res_bs)){ ERROR("service %s(%lld) %lld fail to rpc to %lld, unmarshal protocol name %s group %lld id %lld error", name(), (long long)m_id, (long long)who, (long long)to, res_proto->name(), (long long)group_id, (long long)protocol_id); return 0; } respond->setRequest(res_proto); } // body is not special return respond; } else{ return cr->getResumeParam(); } }