static tb_void_t tb_aiop_ptor_kilo(tb_aicp_ptor_impl_t* ptor, tb_aico_impl_t* aico) { // check tb_aiop_ptor_impl_t* impl = (tb_aiop_ptor_impl_t*)ptor; tb_assert_and_check_return(impl && impl->timer && impl->ltimer && impl->aiop && aico); // trace tb_trace_d("kilo: aico: %p, type: %u: ..", aico, aico->type); // the aiop aico tb_aiop_aico_t* aiop_aico = (tb_aiop_aico_t*)aico; // add timeout task for killing the accept socket if (aico->type == TB_AICO_TYPE_SOCK && aiop_aico->aice.code == TB_AICE_CODE_ACPT) { // add task if (!aiop_aico->task) { aiop_aico->task = tb_ltimer_task_init(impl->ltimer, 10000, tb_false, tb_aiop_spak_wait_timeout, aico); aiop_aico->bltimer = 1; } } // kill the task if (aiop_aico->task) { // trace tb_trace_d("kilo: aico: %p, type: %u, task: %p: ..", aico, aico->type, aiop_aico->task); // kill task if (aiop_aico->bltimer) tb_ltimer_task_kill(impl->ltimer, aiop_aico->task); else tb_timer_task_kill(impl->timer, aiop_aico->task); } // kill sock if (aico->type == TB_AICO_TYPE_SOCK && aico->handle) { // trace tb_trace_d("kilo: aico: %p, type: %u, sock: %p: ..", aico, aico->type, aico->handle); // kill it tb_socket_kill(aico->handle, TB_SOCKET_KILL_RW); } // kill file else if (aico->type == TB_AICO_TYPE_FILE) { // kill it tb_aicp_file_kilo(impl, aico); } /* the aiop will wait long time if the lastest task wait period is too long * so spak the aiop manually for spak the ltimer */ tb_aiop_spak(impl->aiop); // trace tb_trace_d("kilo: aico: %p, type: %u: ok", aico, aico->type); }
static tb_void_t tb_aiop_spak_klist(tb_aiop_ptor_impl_t* impl) { // check tb_assert_and_check_return(impl && impl->klist); // enter tb_spinlock_enter(&impl->klock); // kill it if exists the killing aico if (tb_vector_size(impl->klist)) { // kill all tb_for_all_if (tb_aico_impl_t*, aico, impl->klist, aico) { // the aiop aico tb_aiop_aico_t* aiop_aico = (tb_aiop_aico_t*)aico; // sock? if (aico->type == TB_AICO_TYPE_SOCK) { // add it first if do not exists timeout task if (!aiop_aico->task) { aiop_aico->task = tb_ltimer_task_init(impl->ltimer, 10000, tb_false, tb_aiop_spak_wait_timeout, aico); aiop_aico->bltimer = 1; } // kill the task if (aiop_aico->task) { // kill task if (aiop_aico->bltimer) tb_ltimer_task_kill(impl->ltimer, aiop_aico->task); else tb_timer_task_kill(impl->timer, aiop_aico->task); } } else if (aico->type == TB_AICO_TYPE_FILE) { // kill file tb_aicp_file_kilo(impl, aico); } // trace tb_trace_d("kill: aico: %p, type: %u: ok", aico, aico->type); } }
static tb_bool_t tb_aiop_spak_wait(tb_aiop_ptor_impl_t* impl, tb_aice_ref_t aice) { // check tb_assert_and_check_return_val(impl && impl->aiop && impl->ltimer && aice, tb_false); // the aico tb_aiop_aico_t* aico = (tb_aiop_aico_t*)aice->aico; tb_assert_and_check_return_val(aico && aico->base.handle && !aico->task, tb_false); // the aioe code tb_size_t code = tb_aiop_aioe_code(aice); tb_assert_and_check_return_val(code != TB_AIOE_CODE_NONE, tb_false); // trace tb_trace_d("wait: aico: %p, code: %lu: time: %lld: ..", aico, aice->code, tb_cache_time_mclock()); // done tb_bool_t ok = tb_false; tb_aice_t prev = aico->aice; do { // wait it aico->aice = *aice; aico->waiting = 1; aico->wait_ok = 0; // wait once if not accept if (aice->code != TB_AICE_CODE_ACPT) code |= TB_AIOE_CODE_ONESHOT; // using the edge triggered mode if (tb_aiop_have(impl->aiop, TB_AIOE_CODE_CLEAR)) code |= TB_AIOE_CODE_CLEAR; // have aioo? if (!aico->aioo) { // addo wait if (!(aico->aioo = tb_aiop_addo(impl->aiop, aico->base.handle, code, &aico->aice))) break; } else { // sete wait if (!tb_aiop_sete(impl->aiop, aico->aioo, code, &aico->aice)) break; } // add timeout task tb_long_t timeout = tb_aico_impl_timeout_from_code((tb_aico_impl_t*)aico, aice->code); if (timeout >= 0) { // add it aico->task = tb_ltimer_task_init(impl->ltimer, timeout, tb_false, tb_aiop_spak_wait_timeout, aico); tb_assert_and_check_break(aico->task); aico->bltimer = 1; } // ok ok = tb_true; } while (0); // failed? restore it if (!ok) { // trace tb_trace_d("wait: aico: %p, code: %lu: failed", aico, aice->code); // restore it aico->aice = prev; aico->waiting = 0; } // ok? return ok; }
tb_bool_t tb_lo_scheduler_io_wait(tb_lo_scheduler_io_ref_t scheduler_io, tb_socket_ref_t sock, tb_size_t events, tb_long_t timeout) { // check tb_assert(scheduler_io && sock && scheduler_io->poller && scheduler_io->scheduler && events); // get the current coroutine tb_lo_coroutine_t* coroutine = tb_lo_scheduler_running(scheduler_io->scheduler); tb_assert(coroutine); // get the poller tb_poller_ref_t poller = scheduler_io->poller; tb_assert(poller); // trace tb_trace_d("coroutine(%p): wait events(%lu) with %ld ms for socket(%p) ..", coroutine, events, timeout, sock); // enable edge-trigger mode if be supported if (tb_poller_support(poller, TB_POLLER_EVENT_CLEAR)) events |= TB_POLLER_EVENT_CLEAR; // exists this socket? only modify events tb_socket_ref_t sock_prev = coroutine->rs.wait.sock; if (sock_prev == sock) { // return the cached events directly if the waiting events exists cache tb_size_t events_prev = coroutine->rs.wait.events; tb_size_t events_cache = coroutine->rs.wait.events_cache; if (events_cache && (events_prev & events)) { // check error? if (events_cache & TB_POLLER_EVENT_ERROR) { coroutine->rs.wait.events_cache = 0; return -1; } // clear cache events coroutine->rs.wait.events_cache &= ~events; // return the cached events coroutine->rs.wait.events_result = events_cache & events; return tb_false; } // modify socket from poller for waiting events if the waiting events has been changed if (events_prev != events && !tb_poller_modify(poller, sock, events, coroutine)) { // trace tb_trace_e("failed to modify sock(%p) to poller on coroutine(%p)!", sock, coroutine); // failed coroutine->rs.wait.events_result = -1; return tb_false; } } else { // remove the previous socket first if exists if (sock_prev && !tb_poller_remove(poller, sock_prev)) { // trace tb_trace_e("failed to remove sock(%p) to poller on coroutine(%p)!", sock_prev, coroutine); // failed coroutine->rs.wait.events_result = -1; return tb_false; } // insert socket to poller for waiting events if (!tb_poller_insert(poller, sock, events, coroutine)) { // trace tb_trace_e("failed to insert sock(%p) to poller on coroutine(%p)!", sock, coroutine); // failed coroutine->rs.wait.events_result = -1; return tb_false; } } #ifndef TB_CONFIG_MICRO_ENABLE // exists timeout? tb_cpointer_t task = tb_null; tb_bool_t is_ltimer = tb_false; if (timeout >= 0) { // high-precision interval? if (timeout % 1000) { // init task for timer task = tb_timer_task_init(scheduler_io->timer, timeout, tb_false, tb_lo_scheduler_io_timeout, coroutine); tb_assert_and_check_return_val(task, tb_false); } // low-precision interval? else { // init task for ltimer (faster) task = tb_ltimer_task_init(scheduler_io->ltimer, timeout, tb_false, tb_lo_scheduler_io_timeout, coroutine); tb_assert_and_check_return_val(task, tb_false); // mark as low-precision timer is_ltimer = tb_true; } } // check tb_assert(!((tb_size_t)(task) & 0x1)); // save the timer task to coroutine coroutine->rs.wait.task = (is_ltimer || !task)? task : (tb_cpointer_t)((tb_size_t)(task) | 0x1); #endif // save the socket to coroutine for the timer function coroutine->rs.wait.sock = sock; // save waiting events to coroutine coroutine->rs.wait.events = (tb_sint32_t)events; coroutine->rs.wait.events_cache = 0; coroutine->rs.wait.events_result = 0; // mark as waiting state coroutine->rs.wait.waiting = 1; // suspend it return tb_true; }