tb_bool_t tb_aico_open_sock(tb_aico_ref_t aico, tb_socket_ref_t sock) { // check tb_aico_impl_t* impl = (tb_aico_impl_t*)aico; tb_aicp_impl_t* aicp_impl = (tb_aicp_impl_t*)impl->aicp; tb_assert_and_check_return_val(impl && sock && aicp_impl && aicp_impl->ptor && aicp_impl->ptor->addo, tb_false); // done tb_bool_t ok = tb_false; do { // closed? tb_assert_and_check_break(tb_atomic_get(&impl->state) == TB_STATE_CLOSED); tb_assert_and_check_break(!impl->type && !impl->handle); // bind type and handle impl->type = TB_AICO_TYPE_SOCK; impl->handle = (tb_handle_t)sock; // addo aico ok = aicp_impl->ptor->addo(aicp_impl->ptor, impl); tb_assert_and_check_break(ok); // opened tb_atomic_set(&impl->state, TB_STATE_OPENED); } while (0); // ok? return ok; }
static tb_bool_t tb_async_transfer_open_func(tb_async_transfer_impl_t* impl, tb_size_t state, tb_hize_t offset, tb_hong_t size, tb_async_transfer_open_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return_val(impl, tb_false); // ok? tb_bool_t ok = tb_true; if (state == TB_STATE_OK) { // opened tb_atomic_set(&impl->state, TB_STATE_OPENED); // done func if (func) ok = func(state, offset, size, priv); } // failed? else { // init func and state impl->clos_opening.func = func; impl->clos_opening.priv = priv; impl->clos_opening.state = state; // close it ok = tb_async_transfer_clos((tb_async_transfer_ref_t)impl, tb_async_transfer_clos_opening_func, impl); } // ok? return ok; }
tb_bool_t tb_aico_open_task(tb_aico_ref_t aico, tb_bool_t ltimer) { // check tb_aico_impl_t* impl = (tb_aico_impl_t*)aico; tb_aicp_impl_t* aicp_impl = (tb_aicp_impl_t*)impl->aicp; tb_assert_and_check_return_val(impl && aicp_impl && aicp_impl->ptor && aicp_impl->ptor->addo, tb_false); // done tb_bool_t ok = tb_false; do { // closed? tb_assert_and_check_break(tb_atomic_get(&impl->state) == TB_STATE_CLOSED); tb_assert_and_check_break(!impl->type); // bind type and handle // hack: handle != null? using higher precision timer for being compatible with sock/file task impl->type = TB_AICO_TYPE_TASK; impl->handle = (tb_handle_t)(tb_size_t)!ltimer; // addo aico ok = aicp_impl->ptor->addo(aicp_impl->ptor, impl); tb_assert_and_check_break(ok); // opened tb_atomic_set(&impl->state, TB_STATE_OPENED); } while (0); // ok? return ok; }
tb_bool_t tb_semaphore_post(tb_semaphore_ref_t semaphore, tb_size_t post) { // check tb_semaphore_impl_t* impl = (tb_semaphore_impl_t*)semaphore; tb_assert_and_check_return_val(semaphore && impl->semaphore && impl->semaphore != INVALID_HANDLE_VALUE && post, tb_false); // += post tb_atomic_fetch_and_add(&impl->value, post); // post LONG prev = 0; if (!ReleaseSemaphore(impl->semaphore, (LONG)post, &prev) && prev >= 0) { // restore tb_atomic_fetch_and_sub(&impl->value, (tb_long_t)post); return tb_false; } // check tb_assert_and_check_return_val(prev + post <= TB_SEMAPHORE_VALUE_MAXN, tb_false); // save value tb_atomic_set(&impl->value, prev + post); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_async_transfer_clos_func(tb_async_transfer_impl_t* impl, tb_size_t state) { // check tb_assert_and_check_return(impl && impl->clos.func); // trace tb_trace_d("closed"); // closed tb_atomic_set(&impl->state, TB_STATE_CLOSED); // clear pause state tb_atomic_set(&impl->state_pause, TB_STATE_OK); // done func impl->clos.func(state, impl->clos.priv); }
tb_bool_t tb_async_stream_open_func(tb_async_stream_ref_t stream, tb_size_t state, tb_async_stream_open_func_t func, tb_cpointer_t priv) { // check tb_async_stream_impl_t* impl = tb_async_stream_impl(stream); tb_assert_and_check_return_val(impl, tb_false); // ok? tb_bool_t ok = tb_true; if (state == TB_STATE_OK) { // opened tb_atomic_set(&impl->istate, TB_STATE_OPENED); // done func if (func) ok = func(stream, state, priv); } // failed? else { // try closing ok? if (impl->clos_try && impl->clos_try(stream)) { // closed tb_atomic_set(&impl->istate, TB_STATE_CLOSED); // done func if (func) func(stream, state, priv); } else { // check tb_assert_and_check_return_val(impl->clos, tb_false); // init func and state impl->clos_opening.func = func; impl->clos_opening.priv = priv; impl->clos_opening.state = state; // close it ok = impl->clos(stream, tb_async_stream_clos_opening, tb_null); } } // ok? return ok; }
tb_void_t gb_quality_set(tb_size_t quality) { // check tb_assert_and_check_return(quality <= GB_QUALITY_TOP); // save quality tb_atomic_set(&g_quality, quality); }
tb_void_t tb_async_transfer_limitrate(tb_async_transfer_ref_t transfer, tb_size_t rate) { // check tb_async_transfer_impl_t* impl = (tb_async_transfer_impl_t*)transfer; tb_assert_and_check_return(impl); // set the limited rate tb_atomic_set(&impl->limited_rate, rate); }
tb_void_t tb_async_stream_open_done(tb_async_stream_ref_t stream) { // check tb_async_stream_impl_t* impl = tb_async_stream_impl(stream); tb_assert_and_check_return(impl); // opened or closed? tb_atomic_set(&impl->istate, TB_STATE_OPENED); }
tb_void_t tb_aico_timeout_set(tb_aico_ref_t aico, tb_size_t type, tb_long_t timeout) { // check tb_aico_impl_t* impl = (tb_aico_impl_t*)aico; tb_assert_and_check_return(impl && type < tb_arrayn(impl->timeout)); // set the impl timeout tb_atomic_set((tb_atomic_t*)(impl->timeout + type), timeout); }
tb_bool_t tb_async_transfer_clos_try(tb_async_transfer_ref_t transfer) { // check tb_async_transfer_impl_t* impl = (tb_async_transfer_impl_t*)transfer; tb_assert_and_check_return_val(impl, tb_false); // trace tb_trace_d("clos: try: .."); // done tb_bool_t ok = tb_false; do { // closed? if (TB_STATE_CLOSED == tb_atomic_get(&impl->state)) { ok = tb_true; break; } // try closing istream if (impl->istream && !tb_async_stream_clos_try(impl->istream)) break; // try closing ostream if (impl->ostream && !tb_async_stream_clos_try(impl->ostream)) break; // closed tb_atomic_set(&impl->state, TB_STATE_CLOSED); // clear pause state tb_atomic_set(&impl->state_pause, TB_STATE_OK); // ok ok = tb_true; } while (0); // trace tb_trace_d("clos: try: %s", ok? "ok" : "no"); // ok? return ok; }
static tb_void_t tb_demo_spider_exit(tb_demo_spider_t* spider) { // check tb_assert_and_check_return(spider); // trace tb_trace_d("exit: .."); // kill it tb_atomic_set(&spider->state, TB_STATE_KILLING); // kill all transfer tasks tb_transfer_pool_kill_all(tb_transfer_pool()); // kill all parser tasks tb_thread_pool_task_kill_all(tb_thread_pool()); // wait all transfer tasks exiting tb_transfer_pool_wait_all(tb_transfer_pool(), -1); // wait all parser tasks exiting tb_thread_pool_task_wait_all(tb_thread_pool(), -1); // enter tb_spinlock_enter(&spider->lock); // exit filter if (spider->filter) tb_bloom_filter_exit(spider->filter); spider->filter = tb_null; // exit pool if (spider->pool) tb_fixed_pool_exit(spider->pool); spider->pool = tb_null; // leave tb_spinlock_leave(&spider->lock); // exit lock tb_spinlock_exit(&spider->lock); // exit home tb_url_exit(&spider->home); // exit option #ifdef TB_CONFIG_MODULE_HAVE_OBJECT if (spider->option) tb_option_exit(spider->option); spider->option = tb_null; #endif // trace tb_trace_d("exit: ok"); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t tb_android_init(JavaVM* jvm) { // check if (!jvm) { // warning tb_trace_w("the java machine be not inited, please pass it to the tb_init function!"); } // init it tb_atomic_set(&g_jvm, (tb_size_t)jvm); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_async_stream_clos_opening(tb_async_stream_ref_t stream, tb_size_t state, tb_cpointer_t priv) { // check tb_async_stream_impl_t* impl = tb_async_stream_impl(stream); tb_assert_and_check_return(impl); // trace tb_trace_d("clos: opening: %s, state: %s", tb_url_cstr(&impl->url), tb_state_cstr(impl->clos_opening.state)); // closed tb_atomic_set(&impl->istate, TB_STATE_CLOSED); // done func if (impl->clos_opening.func) impl->clos_opening.func(stream, impl->clos_opening.state, impl->clos_opening.priv); }
/* ////////////////////////////////////////////////////////////////////////////////////// * private interfaces */ tb_void_t tb_async_stream_clear(tb_async_stream_ref_t stream) { // check tb_async_stream_impl_t* impl = tb_async_stream_impl(stream); tb_assert_and_check_return(impl); // clear rcache tb_buffer_clear(&impl->rcache_data); // clear wcache tb_buffer_clear(&impl->wcache_data); // clear istate tb_atomic_set(&impl->istate, TB_STATE_CLOSED); }
tb_void_t tb_timer_exit(tb_timer_ref_t timer) { // check tb_timer_impl_t* impl = (tb_timer_impl_t*)timer; tb_assert_and_check_return(impl); // stop it tb_atomic_set(&impl->stop, 1); // wait loop exit tb_size_t tryn = 10; while (tb_atomic_get(&impl->work) && tryn--) tb_msleep(500); // warning if (!tryn && tb_atomic_get(&impl->work)) tb_trace_w("[timer]: the loop has been not exited now!"); // post event tb_spinlock_enter(&impl->lock); tb_event_ref_t event = impl->event; tb_spinlock_leave(&impl->lock); if (event) tb_event_post(event); // enter tb_spinlock_enter(&impl->lock); // exit heap if (impl->heap) tb_heap_exit(impl->heap); impl->heap = tb_null; // exit pool if (impl->pool) tb_fixed_pool_exit(impl->pool); impl->pool = tb_null; // exit event if (impl->event) tb_event_exit(impl->event); impl->event = tb_null; // leave tb_spinlock_leave(&impl->lock); // exit lock tb_spinlock_exit(&impl->lock); // exit it tb_free(impl); }
tb_bool_t tb_aico_open_file_from_path(tb_aico_ref_t aico, tb_char_t const* path, tb_size_t mode) { // check tb_aico_impl_t* impl = (tb_aico_impl_t*)aico; tb_aicp_impl_t* aicp_impl = (tb_aicp_impl_t*)impl->aicp; tb_assert_and_check_return_val(impl && path && aicp_impl && aicp_impl->ptor && aicp_impl->ptor->addo, tb_false); // done tb_bool_t ok = tb_false; tb_file_ref_t file = tb_null; do { // closed? tb_assert_and_check_break(tb_atomic_get(&impl->state) == TB_STATE_CLOSED); tb_assert_and_check_break(!impl->type && !impl->handle); // init file file = tb_file_init(path, mode | TB_FILE_MODE_ASIO); tb_assert_and_check_break(file); // bind type and handle impl->type = TB_AICO_TYPE_FILE; impl->handle = (tb_handle_t)file; // addo aico ok = aicp_impl->ptor->addo(aicp_impl->ptor, impl); tb_assert_and_check_break(ok); // opened tb_atomic_set(&impl->state, TB_STATE_OPENED); } while (0); // failed? if (!ok) { // exit it if (file) tb_file_exit(file); file = tb_null; } // ok? return ok; }
tb_void_t tb_exit() { // have been exited? if (TB_STATE_OK != tb_atomic_fetch_and_pset(&g_state, TB_STATE_OK, TB_STATE_EXITING)) return ; // kill singleton tb_singleton_kill(); // exit object #ifdef TB_CONFIG_MODULE_HAVE_OBJECT tb_object_exit_env(); #endif // exit network envirnoment tb_network_exit_env(); // exit libm envirnoment tb_libm_exit_env(); // exit math envirnoment tb_math_exit_env(); // exit libc envirnoment tb_libc_exit_env(); // exit platform envirnoment tb_platform_exit_env(); // exit singleton tb_singleton_exit(); // exit memory envirnoment tb_memory_exit_env(); // trace tb_trace_d("exit: ok"); // exit trace tb_trace_exit(); // end tb_atomic_set(&g_state, TB_STATE_END); }
tb_void_t tb_thread_pool_kill(tb_thread_pool_ref_t pool) { // check tb_thread_pool_impl_t* impl = (tb_thread_pool_impl_t*)pool; tb_assert_and_check_return(impl); // enter tb_spinlock_enter(&impl->lock); // kill it tb_size_t post = 0; if (!impl->bstoped) { // trace tb_trace_d("kill: .."); // stoped impl->bstoped = tb_true; // kill all workers tb_size_t i = 0; tb_size_t n = impl->worker_size; for (i = 0; i < n; i++) tb_atomic_set(&impl->worker_list[i].bstoped, 1); // kill all jobs if (impl->jobs_pool) tb_fixed_pool_walk(impl->jobs_pool, tb_thread_pool_jobs_walk_kill_all, tb_null); // post it post = impl->worker_size; } // leave tb_spinlock_leave(&impl->lock); // post the workers if (post) tb_thread_pool_worker_post(impl, post); }
static tb_long_t tb_aiop_spak_clos(tb_aiop_ptor_impl_t* impl, tb_aice_ref_t aice) { // check tb_assert_and_check_return_val(impl && impl->aiop && impl->ltimer && impl->timer && aice, -1); tb_assert_and_check_return_val(aice->code == TB_AICE_CODE_CLOS, -1); // the aico tb_aiop_aico_t* aico = (tb_aiop_aico_t*)aice->aico; tb_assert_and_check_return_val(aico, -1); // trace tb_trace_d("clos: aico: %p, code: %u: %s", aico, aice->code, tb_state_cstr(tb_atomic_get(&aico->base.state))); // exit the timer task if (aico->task) { if (aico->bltimer) tb_ltimer_task_exit(impl->ltimer, aico->task); else tb_timer_task_exit(impl->timer, aico->task); aico->bltimer = 0; } aico->task = tb_null; // exit the sock if (aico->base.type == TB_AICO_TYPE_SOCK) { // remove aioo if (aico->aioo) tb_aiop_delo(impl->aiop, aico->aioo); aico->aioo = tb_null; // close the socket handle if (aico->base.handle) tb_socket_exit((tb_socket_ref_t)aico->base.handle); aico->base.handle = tb_null; } // exit file else if (aico->base.type == TB_AICO_TYPE_FILE) { // exit the file handle if (aico->base.handle) tb_file_exit((tb_file_ref_t)aico->base.handle); aico->base.handle = tb_null; } // clear waiting state aico->waiting = 0; aico->wait_ok = 0; aico->aice.code = TB_AICE_CODE_NONE; // clear type aico->base.type = TB_AICO_TYPE_NONE; // clear timeout tb_size_t i = 0; tb_size_t n = tb_arrayn(aico->base.timeout); for (i = 0; i < n; i++) aico->base.timeout[i] = -1; // closed tb_atomic_set(&aico->base.state, TB_STATE_CLOSED); // ok aice->state = TB_STATE_OK; return 1; }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_platform_semaphore_main(tb_int_t argc, tb_char_t** argv) { // init loop tb_demo_loop_t loop[10]; tb_size_t i = 0; tb_size_t n = tb_arrayn(loop); for (i = 0; i < n; i++) { // init semaphore loop[i].semaphore = tb_semaphore_init(0); tb_assert_and_check_break(loop[i].semaphore); // post semaphore tb_semaphore_post(loop[i].semaphore, 1); // init index loop[i].index = i; // init stoped loop[i].bstoped = 0; // init loop loop[i].loop = tb_thread_init(tb_null, tb_demo_loop, loop + i, 0); tb_assert_and_check_break(loop[i].loop); } // check tb_assert_and_check_return_val(i == n, 0); // wait some time tb_msleep(100); // post tb_char_t line[256]; tb_bool_t stop = tb_false; while (!stop) { // get line tb_char_t const* p = tb_demo_gets(line, sizeof(line)); tb_assert_and_check_break(p); // trace tb_trace_i("post: %s", p); // done while (*p && !stop) { tb_char_t ch = *p++; switch (ch) { case 'q': stop = tb_true; break; default: { if (ch >= '0' && ch <= '9') { // the index tb_size_t index = ch - '0'; tb_assert_and_check_break(index < n && index == loop[index].index); // post semaphore if (loop[index].semaphore) tb_semaphore_post(loop[index].semaphore, 1); } } break; } } } // post loop for (i = 0; i < n; i++) { // quit thread tb_atomic_set(&loop[i].bstoped, 1); // post semaphore if (loop[i].semaphore) tb_semaphore_post(loop[i].semaphore, 1); } // exit loop for (i = 0; i < n; i++) { // exit loop if (loop[i].loop) { // wait it if (!tb_thread_wait(loop[i].loop, 5000)) { // trace tb_trace_e("wait loop[%lu]: timeout", i); } // exit it tb_thread_exit(loop[i].loop); } // exit semaphore if (loop[i].semaphore) tb_semaphore_exit(loop[i].semaphore); } // exit tb_trace_i("exit"); return 0; }
tb_bool_t tb_async_transfer_open(tb_async_transfer_ref_t transfer, tb_hize_t offset, tb_async_transfer_open_func_t func, tb_cpointer_t priv) { // check tb_async_transfer_impl_t* impl = (tb_async_transfer_impl_t*)transfer; tb_assert_and_check_return_val(impl && impl->aicp && func, tb_false); // done tb_bool_t ok = tb_false; do { // set opening tb_size_t state = tb_atomic_fetch_and_pset(&impl->state, TB_STATE_CLOSED, TB_STATE_OPENING); // opened? done func directly if (state == TB_STATE_OPENED) { // check tb_assert_and_check_break(impl->istream && impl->ostream); // done func func(TB_STATE_OK, tb_async_stream_offset(impl->istream), tb_async_stream_size(impl->istream), priv); // ok ok = tb_true; break; } // must be closed tb_assert_and_check_break(state == TB_STATE_CLOSED); // clear pause state tb_atomic_set(&impl->state_pause, TB_STATE_OK); // init func impl->open.func = func; impl->open.priv = priv; // check tb_assert_and_check_break(impl->istream); tb_assert_and_check_break(impl->ostream); // init some rate info impl->done.base_time = tb_aicp_time(impl->aicp); impl->done.base_time1s = impl->done.base_time; impl->done.saved_size = 0; impl->done.saved_size1s = 0; impl->done.current_rate = 0; // ctrl stream if (impl->ctrl.func && !impl->ctrl.func(impl->istream, impl->ostream, impl->ctrl.priv)) break; // open and seek istream if (!tb_async_stream_open_seek(impl->istream, offset, tb_async_transfer_istream_open_func, impl)) break; // ok ok = tb_true; } while (0); // failed? restore state if (!ok) tb_atomic_set(&impl->state, TB_STATE_CLOSED); // ok? return ok; }
static tb_pointer_t tb_thread_pool_worker_loop(tb_cpointer_t priv) { // the worker tb_thread_pool_worker_t* worker = (tb_thread_pool_worker_t*)priv; // trace tb_trace_d("worker[%lu]: init", worker? worker->id : -1); // done do { // check tb_assert_and_check_break(worker && !worker->jobs && !worker->stats); // the pool tb_thread_pool_impl_t* impl = (tb_thread_pool_impl_t*)worker->pool; tb_assert_and_check_break(impl && impl->semaphore); // wait some time for leaving the lock tb_msleep((worker->id + 1)* 20); // init jobs worker->jobs = tb_vector_init(TB_THREAD_POOL_JOBS_WORKING_GROW, tb_element_ptr(tb_null, tb_null)); tb_assert_and_check_break(worker->jobs); // init stats worker->stats = tb_hash_map_init(TB_HASH_MAP_BUCKET_SIZE_MICRO, tb_element_ptr(tb_null, tb_null), tb_element_mem(sizeof(tb_thread_pool_job_stats_t), tb_null, tb_null)); tb_assert_and_check_break(worker->stats); // loop while (1) { // pull jobs if be idle if (!tb_vector_size(worker->jobs)) { // enter tb_spinlock_enter(&impl->lock); // init the pull time worker->pull = 0; // pull from the urgent jobs if (tb_list_entry_size(&impl->jobs_urgent)) { // trace tb_trace_d("worker[%lu]: try pulling from urgent: %lu", worker->id, tb_list_entry_size(&impl->jobs_urgent)); // pull it tb_remove_if_until(tb_list_entry_itor(&impl->jobs_urgent), tb_thread_pool_worker_walk_pull, worker); } // pull from the waiting jobs if (tb_list_entry_size(&impl->jobs_waiting)) { // trace tb_trace_d("worker[%lu]: try pulling from waiting: %lu", worker->id, tb_list_entry_size(&impl->jobs_waiting)); // pull it tb_remove_if_until(tb_list_entry_itor(&impl->jobs_waiting), tb_thread_pool_worker_walk_pull, worker); } // pull from the pending jobs and clean some finished and killed jobs if (tb_list_entry_size(&impl->jobs_pending)) { // trace tb_trace_d("worker[%lu]: try pulling from pending: %lu", worker->id, tb_list_entry_size(&impl->jobs_pending)); // no jobs? try to pull from the pending jobs if (!tb_vector_size(worker->jobs)) tb_remove_if(tb_list_entry_itor(&impl->jobs_pending), tb_thread_pool_worker_walk_pull_and_clean, worker); // clean some finished and killed jobs else tb_remove_if(tb_list_entry_itor(&impl->jobs_pending), tb_thread_pool_worker_walk_clean, worker); } // leave tb_spinlock_leave(&impl->lock); // idle? wait it if (!tb_vector_size(worker->jobs)) { // killed? tb_check_break(!tb_atomic_get(&worker->bstoped)); // trace tb_trace_d("worker[%lu]: wait: ..", worker->id); // wait some time tb_long_t wait = tb_semaphore_wait(impl->semaphore, -1); tb_assert_and_check_break(wait > 0); // trace tb_trace_d("worker[%lu]: wait: ok", worker->id); // continue it continue; } else { #ifdef TB_TRACE_DEBUG // update the jobs urgent size tb_size_t jobs_urgent_size = tb_list_entry_size(&impl->jobs_urgent); // update the jobs waiting size tb_size_t jobs_waiting_size = tb_list_entry_size(&impl->jobs_waiting); // update the jobs pending size tb_size_t jobs_pending_size = tb_list_entry_size(&impl->jobs_pending); // trace tb_trace_d("worker[%lu]: pull: jobs: %lu, time: %lu ms, waiting: %lu, pending: %lu, urgent: %lu", worker->id, tb_vector_size(worker->jobs), worker->pull, jobs_waiting_size, jobs_pending_size, jobs_urgent_size); #endif } } // done jobs tb_for_all (tb_thread_pool_job_t*, job, worker->jobs) { // check tb_assert_and_check_continue(job && job->task.done); // the job state tb_size_t state = tb_atomic_fetch_and_pset(&job->state, TB_STATE_WAITING, TB_STATE_WORKING); // the job is waiting? work it if (state == TB_STATE_WAITING) { // trace tb_trace_d("worker[%lu]: done: task[%p:%s]: ..", worker->id, job->task.done, job->task.name); // init the time tb_hong_t time = tb_cache_time_spak(); // done the job job->task.done((tb_thread_pool_worker_ref_t)worker, job->task.priv); // computate the time time = tb_cache_time_spak() - time; // exists? update time and count tb_size_t itor; tb_hash_map_item_ref_t item = tb_null; if ( ((itor = tb_hash_map_find(worker->stats, job->task.done)) != tb_iterator_tail(worker->stats)) && (item = (tb_hash_map_item_ref_t)tb_iterator_item(worker->stats, itor))) { // the stats tb_thread_pool_job_stats_t* stats = (tb_thread_pool_job_stats_t*)item->data; tb_assert_and_check_break(stats); // update the done count stats->done_count++; // update the total time stats->total_time += time; } // no item? add it if (!item) { // init stats tb_thread_pool_job_stats_t stats = {0}; stats.done_count = 1; stats.total_time = time; // add stats tb_hash_map_insert(worker->stats, job->task.done, &stats); } #ifdef TB_TRACE_DEBUG tb_size_t done_count = 0; tb_hize_t total_time = 0; tb_thread_pool_job_stats_t* stats = (tb_thread_pool_job_stats_t*)tb_hash_map_get(worker->stats, job->task.done); if (stats) { done_count = stats->done_count; total_time = stats->total_time; } // trace tb_trace_d("worker[%lu]: done: task[%p:%s]: time: %lld ms, average: %lld ms, count: %lu", worker->id, job->task.done, job->task.name, time, (total_time / (tb_hize_t)done_count), done_count); #endif // update the job state tb_atomic_set(&job->state, TB_STATE_FINISHED); } // the job is killing? work it else if (state == TB_STATE_KILLING) { // update the job state tb_atomic_set(&job->state, TB_STATE_KILLED); } } // clear jobs tb_vector_clear(worker->jobs); } } while (0); // exit worker if (worker) { // trace tb_trace_d("worker[%lu]: exit", worker->id); // stoped tb_atomic_set(&worker->bstoped, 1); // exit all private data tb_size_t i = 0; tb_size_t n = tb_arrayn(worker->priv); for (i = 0; i < n; i++) { // the private data tb_thread_pool_worker_priv_t* priv = &worker->priv[n - i - 1]; // exit it if (priv->exit) priv->exit((tb_thread_pool_worker_ref_t)worker, priv->priv); // clear it priv->exit = tb_null; priv->priv = tb_null; } // exit stats if (worker->stats) tb_hash_map_exit(worker->stats); worker->stats = tb_null; // exit jobs if (worker->jobs) tb_vector_exit(worker->jobs); worker->jobs = tb_null; } // exit tb_thread_return(tb_null); return tb_null; }
tb_void_t tb_android_exit() { // clear it tb_atomic_set(&g_jvm, 0); }