gb_mesh_face_ref_t gb_mesh_face_list_make(gb_mesh_face_list_ref_t list) { // check gb_mesh_face_list_impl_t* impl = (gb_mesh_face_list_impl_t*)list; tb_assert_and_check_return_val(impl && impl->pool, tb_null); // make it gb_mesh_face_ref_t face = (gb_mesh_face_ref_t)tb_fixed_pool_malloc0(impl->pool); tb_assert_and_check_return_val(face, tb_null); #ifdef __gb_debug__ // init id face->id = ++impl->id; // save list face->list = (tb_pointer_t)list; #endif // insert to the face list switch (impl->order) { case GB_MESH_ORDER_INSERT_HEAD: tb_list_entry_insert_head(&impl->head, &face->entry); break; case GB_MESH_ORDER_INSERT_TAIL: default: tb_list_entry_insert_tail(&impl->head, &face->entry); break; } // ok return face; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_transfer_task_exit(tb_transfer_pool_impl_t* impl, tb_transfer_task_t* task) { // check tb_assert_and_check_return(impl && impl->pool && task); // trace tb_trace_d("task[%p]: exit", task); // append task to the idle list tb_list_entry_insert_tail(&impl->idle, &task->entry); }
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); }
/* ////////////////////////////////////////////////////////////////////////////////////// * worker implementation */ static tb_bool_t tb_thread_pool_worker_walk_pull(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t value, tb_bool_t* is_break) { // the worker pull tb_thread_pool_worker_t* worker = (tb_thread_pool_worker_t*)value; tb_assert_abort(worker && worker->jobs && worker->stats && is_break); // full? if (worker->pull >= TB_THREAD_POOL_JOBS_PULL_TIME_MAXN) { // break it *is_break = tb_true; return tb_false; } // the job tb_thread_pool_job_t* job = (tb_thread_pool_job_t*)item; tb_assert_abort(job); // the pool tb_thread_pool_impl_t* impl = (tb_thread_pool_impl_t*)worker->pool; tb_assert_abort(impl); // append the job to the pending jobs tb_list_entry_insert_tail(&impl->jobs_pending, &job->entry); // append the job to the working jobs tb_vector_insert_tail(worker->jobs, job); // computate the job average time tb_size_t average_time = 200; if (tb_hash_map_size(worker->stats)) { tb_thread_pool_job_stats_t* stats = (tb_thread_pool_job_stats_t*)tb_hash_map_get(worker->stats, job->task.done); if (stats && stats->done_count) average_time = (tb_size_t)(stats->total_time / stats->done_count); } // update the pull time worker->pull += average_time; // trace tb_trace_d("worker[%lu]: pull: task[%p:%s] from %s", worker->id, job->task.done, job->task.name, iterator == tb_list_entry_itor(&impl->jobs_waiting)? "waiting" : "urgent"); // remove the job from the waiting or urgent jobs return tb_true; }
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); }
static tb_void_t tb_lo_scheduler_make_ready(tb_lo_scheduler_t* scheduler, tb_lo_coroutine_t* coroutine) { // check tb_assert(scheduler && coroutine); // mark ready state tb_lo_core_state_set(coroutine, TB_STATE_READY); // insert this coroutine to ready coroutines if (scheduler->running) { // .. -> coroutine(inserted) -> running -> .. tb_list_entry_insert_prev(&scheduler->coroutines_ready, &scheduler->running->entry, &coroutine->entry); } else { // .. last -> coroutine(inserted) tb_list_entry_insert_tail(&scheduler->coroutines_ready, &coroutine->entry); } }
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_thread_pool_job_t* tb_thread_pool_jobs_post_task(tb_thread_pool_impl_t* impl, tb_thread_pool_task_t const* task, tb_size_t* post_size) { // check tb_assert_and_check_return_val(impl && task && task->done && post_size, tb_null); // done tb_bool_t ok = tb_false; tb_thread_pool_job_t* job = tb_null; do { // check tb_assert_and_check_break(tb_list_entry_size(&impl->jobs_waiting) + tb_list_entry_size(&impl->jobs_urgent) + 1 < TB_THREAD_POOL_JOBS_WAITING_MAXN); // make job job = (tb_thread_pool_job_t*)tb_fixed_pool_malloc0(impl->jobs_pool); tb_assert_and_check_break(job); // init job job->refn = 1; job->state = TB_STATE_WAITING; job->task = *task; // non-urgent job? if (!task->urgent) { // post to the waiting jobs tb_list_entry_insert_tail(&impl->jobs_waiting, &job->entry); } else { // post to the urgent jobs tb_list_entry_insert_tail(&impl->jobs_urgent, &job->entry); } // the waiting jobs count tb_size_t jobs_waiting_count = tb_list_entry_size(&impl->jobs_waiting) + tb_list_entry_size(&impl->jobs_urgent); tb_assert_and_check_break(jobs_waiting_count); // update the post size if (*post_size < impl->worker_size) (*post_size)++; // trace tb_trace_d("task[%p:%s]: post: %lu: ..", task->done, task->name, *post_size); // init them if the workers have been not inited if (impl->worker_size < jobs_waiting_count) { tb_size_t i = impl->worker_size; tb_size_t n = tb_min(jobs_waiting_count, impl->worker_maxn); for (; i < n; i++) { // the worker tb_thread_pool_worker_t* worker = &impl->worker_list[i]; // clear worker tb_memset(worker, 0, sizeof(tb_thread_pool_worker_t)); // init worker worker->id = i; worker->pool = (tb_thread_pool_ref_t)impl; worker->loop = tb_thread_init(__tb_lstring__("thread_pool"), tb_thread_pool_worker_loop, worker, impl->stack); tb_assert_and_check_continue(worker->loop); } // update the worker size impl->worker_size = i; } // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it tb_fixed_pool_free(impl->jobs_pool, job); job = tb_null; } // ok? return job; }