message tasklet_service::recv(tasklet& recver) { if(_stop) { throw stop_exception(); } bool switched = false; while (_channel_manager.empty(recver._channel)) { park(recver); if (empty_runnables()) { switch_tasklet(recver); } else { switch_tasklet(recver, pop_runnable()); } switched = true; } if (!switched) { yield(recver); } return _channel_manager.fetch(recver._channel); }
message tasklet_service::recv(tasklet& recver, double timeout) { if(_stop) { throw stop_exception(); } if (timeout == infinity) { return recv(recver); } bool switched = false; unsigned long long wake_ = now()+(int)(timeout*10); while (_channel_manager.empty(recver._channel)) { recver._state = timeout_waitting; recver._wake = wake_; _sleepers.insert(&recver); if (empty_runnables()) { switch_tasklet(recver); } else { switch_tasklet(recver, pop_runnable()); } switched = true; } if (!switched) { yield(recver); } return _channel_manager.fetch(recver._channel); }
static void schedule(struct thread *t) { struct thread *current = current_thread(); /* If t is NULL need to find new runnable thread. */ if (t == NULL) { if (thread_list_empty(&runnable_threads)) die("Runnable thread list is empty!\n"); t = pop_runnable(); } else { /* current is still runnable. */ push_runnable(current); } switch_to_thread(t->stack_current, ¤t->stack_current); }
void tasklet_service::yield(tasklet& tasklet_) { if(_stop) { throw stop_exception(); } if (empty_runnables()) { return; } push_runnable(tasklet_); assert(!empty_runnables()); tasklet& next = pop_runnable(); switch_tasklet(tasklet_, next); }
void tasklet_service::sleep(tasklet& tasklet_, double timeout) { if(_stop) { throw stop_exception(); } tasklet_._state = sleeping; tasklet_._wake = now()+(int)(timeout*10); _sleepers.insert(&tasklet_); if (empty_runnables()) { switch_tasklet(tasklet_); } else { tasklet& next_tasklet = pop_runnable(); switch_tasklet(tasklet_, next_tasklet); } }
tasklet& tasklet_service::pop_tasklet() { tasklet* ptasklet = NULL; while (!ptasklet && !_stop) { if (empty_runnables()) { //这里本来可能引发因为_condition.wait释放_mutex导致的线程安全问题 //但是很幸运的是,pop_tasklet只被threadlet::loop调用,这样就正好不会引发线程安全问题了 _condition.wait(); } else { assert(!empty_runnables()); ptasklet = &pop_runnable(); } } if (_stop && !ptasklet) { throw stop_exception(); } return *ptasklet; }