static tb_void_t tb_aicp_instance_exit(tb_handle_t handle, tb_cpointer_t priv) { // check tb_assert_and_check_return(handle); // wait all if (!tb_aicp_wait_all((tb_aicp_ref_t)handle, 5000)) return ; // kill aicp tb_aicp_kill((tb_aicp_ref_t)handle); // exit loop tb_thread_ref_t loop = (tb_thread_ref_t)priv; if (loop) { // wait it if (!tb_thread_wait(loop, 5000)) return ; // exit it tb_thread_exit(loop); } // exit it tb_aicp_exit((tb_aicp_ref_t)handle); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_sock_dns_done_func(tb_aicp_dns_ref_t dns, tb_char_t const* host, tb_ipv4_t const* addr, tb_cpointer_t priv) { // check tb_assert_and_check_return(dns); // the aicp tb_aicp_ref_t aicp = tb_aicp_dns_aicp(dns); tb_assert_and_check_return(aicp); // addr ok? if (addr) { // trace tb_trace_i("dns[%s]: %u.%u.%u.%u", host, addr->u8[0], addr->u8[1], addr->u8[2], addr->u8[3]); } // timeout or failed? else { // trace tb_trace_i("dns[%s]: failed", host); } // exit addr if (dns) tb_aicp_dns_exit(dns); // kill aicp tb_aicp_kill(aicp); }
tb_bool_t tb_aicp_exit(tb_aicp_ref_t aicp) { // check tb_aicp_impl_t* impl = (tb_aicp_impl_t*)aicp; tb_assert_and_check_return_val(impl, tb_false); // kill all first tb_aicp_kill_all((tb_aicp_ref_t)impl); // wait all exiting if (tb_aicp_wait_all((tb_aicp_ref_t)impl, 5000) <= 0) { // wait failed, trace left aicos tb_spinlock_enter(&impl->lock); if (impl->pool) tb_fixed_pool_walk(impl->pool, tb_aicp_walk_wait, tb_null); tb_spinlock_leave(&impl->lock); return tb_false; } // kill loop tb_aicp_kill((tb_aicp_ref_t)impl); // wait workers exiting tb_hong_t time = tb_mclock(); while (tb_atomic_get(&impl->work) && (tb_mclock() < time + 5000)) tb_msleep(500); // exit proactor if (impl->ptor) { tb_assert(impl->ptor && impl->ptor->exit); impl->ptor->exit(impl->ptor); impl->ptor = tb_null; } // exit aico pool tb_spinlock_enter(&impl->lock); if (impl->pool) tb_fixed_pool_exit(impl->pool); impl->pool = tb_null; tb_spinlock_leave(&impl->lock); // exit lock tb_spinlock_exit(&impl->lock); // free impl tb_free(impl); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_demo_sock_aico_clos(tb_aice_t const* aice) { // check tb_assert_and_check_return_val(aice && aice->aico && aice->code == TB_AICE_CODE_CLOS, tb_false); // trace tb_trace_d("aico[%p]: clos: %s", aice->aico, tb_state_cstr(aice->state)); // exit aico tb_aico_exit(aice->aico); // kill aicp tb_aicp_kill(tb_aico_aicp(aice->aico)); // ok return tb_true; }
tb_void_t tb_aicp_loop_util(tb_aicp_ref_t aicp, tb_bool_t (*stop)(tb_cpointer_t priv), tb_cpointer_t priv) { // check tb_aicp_impl_t* impl = (tb_aicp_impl_t*)aicp; tb_assert_and_check_return(impl); // the ptor tb_aicp_ptor_impl_t* ptor = impl->ptor; tb_assert_and_check_return(ptor && ptor->loop_spak); // the loop spak tb_long_t (*loop_spak)(tb_aicp_ptor_impl_t* , tb_handle_t, tb_aice_ref_t , tb_long_t ) = ptor->loop_spak; // worker++ tb_atomic_fetch_and_inc(&impl->work); // init loop tb_handle_t loop = ptor->loop_init? ptor->loop_init(ptor) : tb_null; // trace tb_trace_d("loop[%p]: init", loop); // spak ctime tb_cache_time_spak(); // loop while (1) { // spak tb_aice_t resp = {0}; tb_long_t ok = loop_spak(ptor, loop, &resp, -1); // spak ctime tb_cache_time_spak(); // failed? tb_check_break(ok >= 0); // timeout? tb_check_continue(ok); // check aico tb_aico_impl_t* aico = (tb_aico_impl_t*)resp.aico; tb_assert_and_check_continue(aico); // trace tb_trace_d("loop[%p]: spak: code: %lu, aico: %p, state: %s: %ld", loop, resp.code, aico, aico? tb_state_cstr(tb_atomic_get(&aico->state)) : "null", ok); // pending? clear state if be not accept or accept failed tb_size_t state = TB_STATE_OPENED; state = (resp.code != TB_AICE_CODE_ACPT || resp.state != TB_STATE_OK)? tb_atomic_fetch_and_pset(&aico->state, TB_STATE_PENDING, state) : tb_atomic_get(&aico->state); // killed or killing? if (state == TB_STATE_KILLED || state == TB_STATE_KILLING) { // update the aice state resp.state = TB_STATE_KILLED; // killing? update to the killed state tb_atomic_fetch_and_pset(&aico->state, TB_STATE_KILLING, TB_STATE_KILLED); } // done func, @note maybe the aico exit will be called if (resp.func && !resp.func(&resp)) { // trace #ifdef __tb_debug__ tb_trace_e("loop[%p]: done aice func failed with code: %lu at line: %lu, func: %s, file: %s!", loop, resp.code, aico->line, aico->func, aico->file); #else tb_trace_e("loop[%p]: done aice func failed with code: %lu!", loop, resp.code); #endif } // killing? update to the killed state tb_atomic_fetch_and_pset(&aico->state, TB_STATE_KILLING, TB_STATE_KILLED); // stop it? if (stop && stop(priv)) tb_aicp_kill(aicp); } // exit loop if (ptor->loop_exit) ptor->loop_exit(ptor, loop); // worker-- tb_atomic_fetch_and_dec(&impl->work); // trace tb_trace_d("loop[%p]: exit", loop); }
static tb_pointer_t tb_aiop_spak_loop(tb_cpointer_t priv) { // check tb_aiop_ptor_impl_t* impl = (tb_aiop_ptor_impl_t*)priv; tb_aicp_impl_t* aicp = impl? impl->base.aicp : tb_null; // done do { // check tb_assert_and_check_break(impl && impl->aiop && impl->list && impl->timer && impl->ltimer && aicp); // trace tb_trace_d("loop: init"); // loop while (!tb_atomic_get(&aicp->kill)) { // the delay tb_size_t delay = tb_timer_delay(impl->timer); // the ldelay tb_size_t ldelay = tb_ltimer_delay(impl->ltimer); tb_assert_and_check_break(ldelay != -1); // trace tb_trace_d("loop: wait: .."); // wait aioe tb_long_t real = tb_aiop_wait(impl->aiop, impl->list, impl->maxn, tb_min(delay, ldelay)); // trace tb_trace_d("loop: wait: %ld", real); // spak ctime tb_cache_time_spak(); // spak timer if (!tb_timer_spak(impl->timer)) break; // spak ltimer if (!tb_ltimer_spak(impl->ltimer)) break; // killed? tb_check_break(real >= 0); // error? out of range tb_assert_and_check_break(real <= impl->maxn); // timeout? tb_check_continue(real); // grow it if aioe is full if (real == impl->maxn) { // grow size impl->maxn += (aicp->maxn >> 4) + 16; if (impl->maxn > aicp->maxn) impl->maxn = aicp->maxn; // grow list impl->list = tb_ralloc(impl->list, impl->maxn * sizeof(tb_aioe_t)); tb_assert_and_check_break(impl->list); } // walk aioe list tb_size_t i = 0; tb_bool_t end = tb_false; for (i = 0; i < real && !end; i++) { // the aioe tb_aioe_ref_t aioe = &impl->list[i]; tb_assert_and_check_break_state(aioe, end, tb_true); // the aice tb_aice_ref_t aice = (tb_aice_ref_t)aioe->priv; tb_assert_and_check_break_state(aice, end, tb_true); // the aico tb_aiop_aico_t* aico = (tb_aiop_aico_t*)aice->aico; tb_assert_and_check_break_state(aico, end, tb_true); // have wait? tb_check_continue(aice->code); // have been waited ok for the timer timeout/killed func? need not spak it repeatly tb_check_continue(!aico->wait_ok); // sock? if (aico->base.type == TB_AICO_TYPE_SOCK) { // push the acpt aice if (aice->code == TB_AICE_CODE_ACPT) end = tb_aiop_push_acpt(impl, aice)? tb_false : tb_true; // push the sock aice else end = tb_aiop_push_sock(impl, aice)? tb_false : tb_true; } else if (aico->base.type == TB_AICO_TYPE_FILE) { // poll file tb_aicp_file_poll(impl); } else tb_assert(0); } // end? tb_check_break(!end); // work it tb_aiop_spak_work(impl); } } while (0); // trace tb_trace_d("loop: exit"); // kill tb_aicp_kill((tb_aicp_ref_t)aicp); // exit tb_thread_return(tb_null); return tb_null; }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_asio_aicpd_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argv[1], 0); // init tb_aicp_ref_t aicp = tb_null; tb_aico_ref_t aico = tb_null; // tb_aico_ref_t task = tb_null; tb_thread_ref_t loop[16] = {tb_null}; do { // init aicp aicp = tb_aicp_init(16); tb_assert_and_check_break(aicp); // init sock aico aico = tb_aico_init(aicp); tb_assert_and_check_break(aico); // init addr tb_ipaddr_t addr; tb_ipaddr_set(&addr, tb_null, 9090, TB_IPADDR_FAMILY_IPV4); // open sock aico if (!tb_aico_open_sock_from_type(aico, TB_SOCKET_TYPE_TCP, tb_ipaddr_family(&addr))) break; // bind port if (!tb_socket_bind(tb_aico_sock(aico), &addr)) break; // listen sock if (!tb_socket_listen(tb_aico_sock(aico), 20)) break; #if 0 // init task aico task = tb_aico_init(aicp); tb_assert_and_check_break(task); // open task aico if (!tb_aico_open_task(task, tb_false)) break; // run task if (!tb_aico_task_run(task, 0, tb_demo_task_func, tb_null)) break; if (!tb_aico_task_run(aico, 0, tb_demo_task_func, tb_null)) break; #endif // post acpt if (!tb_aico_acpt(aico, tb_demo_sock_acpt_func, argv[1])) break; // done loop loop[0] = tb_thread_init(tb_null, tb_demo_loop, aicp, 0); loop[1] = tb_thread_init(tb_null, tb_demo_loop, aicp, 0); loop[2] = tb_thread_init(tb_null, tb_demo_loop, aicp, 0); loop[3] = tb_thread_init(tb_null, tb_demo_loop, aicp, 0); // wait exit getchar(); } while (0); // trace tb_trace_i("end"); #if 1 if (aicp) { // kill all tb_aicp_kill_all(aicp); // wait all tb_aicp_wait_all(aicp, -1); // kill aicp tb_aicp_kill(aicp); } // wait exit { // exit loop tb_thread_ref_t* l = loop; for (; *l; l++) { tb_thread_wait(*l, -1, tb_null); tb_thread_exit(*l); } } #endif // exit aicp if (aicp) tb_aicp_exit(aicp); return 0; }