static __tb_inline__ tb_lo_coroutine_t* tb_lo_scheduler_next_ready(tb_lo_scheduler_t* scheduler) { // check tb_assert(scheduler && tb_list_entry_size(&scheduler->coroutines_ready)); // get the next entry tb_list_entry_ref_t entry_next = scheduler->running? tb_list_entry_next(&scheduler->running->entry) : tb_list_entry_head(&scheduler->coroutines_ready); tb_assert(entry_next); // is list header? skip it and get the first entry if (entry_next == (tb_list_entry_ref_t)&scheduler->coroutines_ready) entry_next = tb_list_entry_next(entry_next); // get the next ready coroutine return (tb_lo_coroutine_t*)tb_list_entry(&scheduler->coroutines_ready, entry_next); }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_list_entry_main(tb_int_t argc, tb_char_t** argv) { // init the entries tb_demo_entry_t entries[12] = { {{0}, 0} , {{0}, 1} , {{0}, 2} , {{0}, 3} , {{0}, 4} , {{0}, 5} , {{0}, 6} , {{0}, 7} , {{0}, 8} , {{0}, 9} , {{0}, 10} , {{0}, 11} }; // init the list tb_list_entry_head_t list; tb_list_entry_init(&list, tb_demo_entry_t, entry, tb_demo_entry_copy); // insert entries tb_list_entry_insert_tail(&list, &entries[5].entry); tb_list_entry_insert_tail(&list, &entries[6].entry); tb_list_entry_insert_tail(&list, &entries[7].entry); tb_list_entry_insert_tail(&list, &entries[8].entry); tb_list_entry_insert_tail(&list, &entries[9].entry); tb_list_entry_insert_head(&list, &entries[4].entry); tb_list_entry_insert_head(&list, &entries[3].entry); tb_list_entry_insert_head(&list, &entries[2].entry); tb_list_entry_insert_head(&list, &entries[1].entry); tb_list_entry_insert_head(&list, &entries[0].entry); // the entry tb_demo_entry_t* entry = (tb_demo_entry_t*)tb_list_entry(&list, &entries[5].entry); tb_trace_i("entry: %lu", entry->data); tb_trace_i(""); // walk it tb_trace_i("insert: %lu", tb_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item0, tb_list_entry_itor(&list), item0) { tb_trace_i("%lu", item0->data); }
/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t tb_lo_scheduler_free(tb_list_entry_head_ref_t coroutines) { // check tb_assert(coroutines); // free all coroutines while (tb_list_entry_size(coroutines)) { // get the next entry from head tb_list_entry_ref_t entry = tb_list_entry_head(coroutines); tb_assert(entry); // remove it from the ready coroutines tb_list_entry_remove_head(coroutines); // exit this coroutine tb_lo_coroutine_exit((tb_lo_coroutine_t*)tb_list_entry(coroutines, entry)); } }
tb_bool_t tb_lo_scheduler_start(tb_lo_scheduler_t* scheduler, tb_lo_coroutine_func_t func, tb_cpointer_t priv, tb_lo_coroutine_free_t free) { // check tb_assert(func); // done tb_bool_t ok = tb_false; tb_lo_coroutine_t* coroutine = tb_null; do { // trace tb_trace_d("start .."); // get the current scheduler if (!scheduler) scheduler = (tb_lo_scheduler_t*)tb_lo_scheduler_self_(); tb_assert_and_check_break(scheduler); // have been stopped? do not continue to start new coroutines tb_check_break(!scheduler->stopped); // reuses dead coroutines in init function if (tb_list_entry_size(&scheduler->coroutines_dead)) { // get the next entry from head tb_list_entry_ref_t entry = tb_list_entry_head(&scheduler->coroutines_dead); tb_assert_and_check_break(entry); // remove it from the ready coroutines tb_list_entry_remove_head(&scheduler->coroutines_dead); // get the dead coroutine coroutine = (tb_lo_coroutine_t*)tb_list_entry(&scheduler->coroutines_dead, entry); // reinit this coroutine tb_lo_coroutine_reinit(coroutine, func, priv, free); } // init coroutine if (!coroutine) coroutine = tb_lo_coroutine_init((tb_lo_scheduler_ref_t)scheduler, func, priv, free); tb_assert_and_check_break(coroutine); // ready coroutine tb_lo_scheduler_make_ready(scheduler, coroutine); // the dead coroutines is too much? free some coroutines while (tb_list_entry_size(&scheduler->coroutines_dead) > TB_SCHEDULER_DEAD_CACHE_MAXN) { // get the next entry from head tb_list_entry_ref_t entry = tb_list_entry_head(&scheduler->coroutines_dead); tb_assert(entry); // remove it from the ready coroutines tb_list_entry_remove_head(&scheduler->coroutines_dead); // exit this coroutine tb_lo_coroutine_exit((tb_lo_coroutine_t*)tb_list_entry(&scheduler->coroutines_dead, entry)); } // ok ok = tb_true; } while (0); // trace tb_trace_d("start %s", ok? "ok" : "no"); // ok? return ok; }
tb_pointer_t tb_fixed_pool_malloc_(tb_fixed_pool_ref_t pool __tb_debug_decl__) { // check tb_fixed_pool_impl_t* impl = (tb_fixed_pool_impl_t*)pool; tb_assert_and_check_return_val(impl, tb_null); // done tb_bool_t ok = tb_false; tb_pointer_t data = tb_null; do { // no current slot or the current slot is full? update the current slot if (!impl->current_slot || tb_static_fixed_pool_full(impl->current_slot->pool)) { // move the current slot to the full slots if exists if (impl->current_slot) tb_list_entry_insert_tail(&impl->full_slots, &impl->current_slot->entry); // clear the current slot impl->current_slot = tb_null; // attempt to get a slot from the partial slots if (!tb_list_entry_is_null(&impl->partial_slots)) { // the head entry tb_list_entry_ref_t entry = tb_list_entry_head(&impl->partial_slots); tb_assert_and_check_break(entry); // the head slot impl->current_slot = (tb_fixed_pool_slot_t*)tb_list_entry(&impl->partial_slots, entry); tb_assert_and_check_break(impl->current_slot); // remove this slot from the partial slots tb_list_entry_remove(&impl->partial_slots, entry); } // make a new slot else impl->current_slot = tb_fixed_pool_slot_init(impl); } // check tb_assert_and_check_break(impl->current_slot && impl->current_slot->pool); tb_assert_and_check_break(!tb_static_fixed_pool_full(impl->current_slot->pool)); // make data from the current slot data = tb_static_fixed_pool_malloc(impl->current_slot->pool __tb_debug_args__); tb_assert_and_check_break(data); // done init if (impl->func_init && !impl->func_init(data, impl->func_priv)) break; // update the item count impl->item_count++; // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit data if (data && impl->current_slot && impl->current_slot->pool) tb_static_fixed_pool_free(impl->current_slot->pool, data __tb_debug_args__); data = tb_null; } // check tb_assertf_abort(data, "malloc(%lu) failed!", impl->item_size); // ok? return data; }
static tb_transfer_task_t* tb_transfer_task_init(tb_transfer_pool_impl_t* impl, tb_async_transfer_done_func_t done, tb_async_transfer_ctrl_func_t ctrl, tb_cpointer_t priv) { // check tb_assert_and_check_return_val(impl, tb_null); // done tb_bool_t ok = tb_false; tb_transfer_task_t* task = tb_null; do { // init task pool if (!impl->pool) impl->pool = tb_fixed_pool_init(tb_null, (impl->maxn >> 4) + 16, sizeof(tb_transfer_task_t), tb_null, tb_null, tb_null); tb_assert_and_check_break(impl->pool); // init task from the idle list first if (tb_list_entry_size(&impl->idle)) { // get the head entry tb_list_entry_ref_t entry = tb_list_entry_head(&impl->idle); tb_assert_and_check_break(entry); // the task task = (tb_transfer_task_t*)tb_list_entry(&impl->idle, entry); tb_assert_and_check_break(task); // remove the last task tb_list_entry_remove(&impl->idle, entry); // check tb_assert_and_check_break(task->transfer); } // init task from the task pool else { // make task task = (tb_transfer_task_t*)tb_fixed_pool_malloc0(impl->pool); tb_assert_and_check_break(task); // init transfer task->transfer = tb_async_transfer_init(impl->aicp, tb_true); tb_assert_and_check_break(task->transfer); } // init ctrl if (ctrl && !tb_async_transfer_ctrl(task->transfer, ctrl, priv)) break; // init task task->func = done; task->priv = priv; task->pool = impl; // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (task) tb_transfer_task_exit(impl, task); task = tb_null; } // ok? return task; }