tb_void_t tb_lo_scheduler_resume(tb_lo_scheduler_t* scheduler, tb_lo_coroutine_t* coroutine) { // check tb_assert(scheduler && coroutine); tb_assert(tb_lo_core_state(coroutine) == TB_STATE_SUSPEND); // remove it from the suspend coroutines tb_list_entry_remove(&scheduler->coroutines_suspend, &coroutine->entry); // make it as ready tb_lo_scheduler_make_ready(scheduler, coroutine); }
static tb_void_t tb_lo_scheduler_make_suspend(tb_lo_scheduler_t* scheduler, tb_lo_coroutine_t* coroutine) { // check tb_assert(scheduler && coroutine); tb_assert(tb_lo_core_state(coroutine) == TB_STATE_SUSPEND); // trace tb_trace_d("suspend coroutine(%p)", coroutine); // remove this coroutine from the ready coroutines tb_list_entry_remove(&scheduler->coroutines_ready, &coroutine->entry); // append this coroutine to suspend coroutines tb_list_entry_insert_tail(&scheduler->coroutines_suspend, &coroutine->entry); }
static tb_void_t tb_lo_scheduler_make_dead(tb_lo_scheduler_t* scheduler, tb_lo_coroutine_t* coroutine) { // check tb_assert(scheduler && coroutine); tb_assert(tb_lo_core_state(coroutine) == TB_STATE_END); // trace tb_trace_d("finish coroutine(%p)", coroutine); // free the user private data first if (coroutine->free) coroutine->free(coroutine->priv); // remove this coroutine from the ready coroutines tb_list_entry_remove(&scheduler->coroutines_ready, &coroutine->entry); // append this coroutine to dead coroutines tb_list_entry_insert_tail(&scheduler->coroutines_dead, &coroutine->entry); }
tb_void_t gb_mesh_face_list_kill(gb_mesh_face_list_ref_t list, gb_mesh_face_ref_t face) { // check gb_mesh_face_list_impl_t* impl = (gb_mesh_face_list_impl_t*)list; tb_assert_and_check_return(impl && impl->pool && face); #ifdef __gb_debug__ // check tb_assert_abort(face->id); // clear id face->id = 0; #endif // remove from the face list tb_list_entry_remove(&impl->head, &face->entry); // exit it tb_fixed_pool_free(impl->pool, face); }
tb_size_t tb_list_remove(tb_list_ref_t self, tb_size_t itor) { // check tb_list_t* list = (tb_list_t*)self; tb_assert_and_check_return_val(list && list->pool && itor, 0); // the node tb_list_entry_ref_t node = (tb_list_entry_ref_t)itor; tb_assert_and_check_return_val(node, tb_iterator_tail(self)); // the next node tb_list_entry_ref_t next = tb_list_entry_next(node); // remove node tb_list_entry_remove(&list->head, node); // free node tb_fixed_pool_free(list->pool, node); // the next node return (tb_size_t)next; }
static tb_bool_t tb_transfer_task_done(tb_size_t state, tb_hize_t offset, tb_hong_t size, tb_hize_t save, tb_size_t rate, tb_cpointer_t priv) { // the task tb_transfer_task_t* task = (tb_transfer_task_t*)priv; tb_assert_and_check_return_val(task && task->transfer, tb_false); // the pool tb_transfer_pool_impl_t* impl = (tb_transfer_pool_impl_t*)task->pool; tb_assert_and_check_return_val(impl, tb_false); // trace tb_trace_d("task[%p]: done: %llu bytes, rate: %lu bytes/s, state: %s", task, save, rate, tb_state_cstr(state)); // done func tb_bool_t ok = task->func? task->func(state, offset, size, save, rate, task->priv) : tb_true; // failed, killed or closed? if (state != TB_STATE_OK && state != TB_STATE_PAUSED) { // enter tb_spinlock_enter(&impl->lock); // remove task from the work list tb_list_entry_remove(&impl->work, &task->entry); // exit task tb_transfer_task_exit(impl, task); task = tb_null; // leave tb_spinlock_leave(&impl->lock); } // ok? return ok; }
tb_bool_t tb_fixed_pool_free_(tb_fixed_pool_ref_t pool, tb_pointer_t data __tb_debug_decl__) { // check tb_fixed_pool_impl_t* impl = (tb_fixed_pool_impl_t*)pool; tb_assert_and_check_return_val(impl, tb_false); // done tb_bool_t ok = tb_false; do { // check tb_assertf_and_check_break(impl->item_count, "double free data: %p", data); // find the slot tb_fixed_pool_slot_t* slot = tb_fixed_pool_slot_find(impl, data); tb_assertf_and_check_break(slot, "the data: %p not belong to pool: %p", data, pool); tb_assert_and_check_break(slot->pool); // the slot is full? tb_bool_t full = tb_static_fixed_pool_full(slot->pool); // done exit if (impl->func_exit) impl->func_exit(data, impl->func_priv); // free it if (!tb_static_fixed_pool_free(slot->pool, data __tb_debug_args__)) break; // not the current slot? if (slot != impl->current_slot) { // is full? move the slot to the partial slots if (full) { tb_list_entry_remove(&impl->full_slots, &slot->entry); tb_list_entry_insert_tail(&impl->partial_slots, &slot->entry); } // is null? exit the slot else if (tb_static_fixed_pool_null(slot->pool)) { tb_list_entry_remove(&impl->partial_slots, &slot->entry); tb_fixed_pool_slot_exit(impl, slot); } } // update the item count impl->item_count--; // ok ok = tb_true; } while (0); // failed? dump it #ifdef __tb_debug__ if (!ok) { // trace tb_trace_e("free(%p) failed! at %s(): %lu, %s", data, func_, line_, file_); // dump data tb_pool_data_dump((tb_byte_t const*)data, tb_true, "[fixed_pool]: [error]: "); // abort tb_abort(); } #endif // 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; }
tb_bool_t tb_transfer_pool_done(tb_transfer_pool_ref_t pool, tb_char_t const* iurl, tb_char_t const* ourl, tb_hize_t offset, tb_size_t rate, tb_async_transfer_done_func_t done, tb_async_transfer_ctrl_func_t ctrl, tb_cpointer_t priv) { // check tb_transfer_pool_impl_t* impl = (tb_transfer_pool_impl_t*)pool; tb_assert_and_check_return_val(impl && impl->aicp && iurl && ourl, tb_false); // enter tb_spinlock_enter(&impl->lock); // done tb_bool_t ok = tb_false; tb_transfer_task_t* task = tb_null; do { // check tb_check_break(TB_STATE_OK == tb_atomic_get(&impl->state)); // too many tasks? if (tb_list_entry_size(&impl->work) >= impl->maxn) { // trace tb_trace_e("too many tasks, done task: %s => %s failed!", iurl, ourl); break; } // init task task = tb_transfer_task_init(impl, done, ctrl, priv); tb_assert_and_check_break(task && task->transfer); // init transfer stream if (!tb_async_transfer_init_istream_from_url(task->transfer, iurl)) break; if (!tb_async_transfer_init_ostream_from_url(task->transfer, ourl)) break; // init transfer rate tb_async_transfer_limitrate(task->transfer, rate); // check tb_assert_and_check_break(impl->pool); // append to the work list tb_list_entry_insert_tail(&impl->work, &task->entry); // ok ok = tb_true; } while (0); // trace tb_trace_d("done: task: %p, %s => %s, work: %lu, idle: %lu, state: %s", task, iurl, ourl, tb_list_entry_size(&impl->work), tb_list_entry_size(&impl->idle), ok? "ok" : "no"); // failed? if (!ok) { // exit it if (task) tb_transfer_task_exit(impl, task); task = tb_null; } // leave tb_spinlock_leave(&impl->lock); // ok? done it if (ok && task && task->transfer) { // done if (!tb_async_transfer_open_done(task->transfer, 0, tb_transfer_task_done, task)) { // enter tb_spinlock_enter(&impl->lock); // remove task from the work list tb_list_entry_remove(&impl->work, &task->entry); // exit task tb_transfer_task_exit(impl, task); // leave tb_spinlock_leave(&impl->lock); // failed ok = tb_false; } } // ok? return ok; }
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; }