static tb_size_t tb_vector_nreplace_last_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_vector_nreplace_last(vector, (tb_pointer_t)0xd, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_nreplace_last(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xd); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xd); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); }
static tb_size_t tb_vector_insert_tail_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_insert_tail(vector, (tb_pointer_t)0xf); t = tb_mclock() - t; // time tb_trace_i("tb_vector_insert_tail(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xf); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xf); // clear it tb_vector_clear(vector); tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); }
static tb_void_t tb_vector_int_dump(tb_vector_ref_t vector) { tb_trace_i("tb_int_t size: %lu, maxn: %lu", tb_vector_size(vector), tb_vector_maxn(vector)); tb_for_all (tb_char_t*, item, vector) { tb_trace_i("tb_int_t at[%lu]: %x", item_itor, item); }
tb_char_t const* tb_environment_at(tb_environment_ref_t environment, tb_size_t index) { // check tb_assert_and_check_return_val(environment, tb_null); // get the value return (index < tb_vector_size(environment))? (tb_char_t const*)tb_iterator_item(environment, index) : tb_null; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_size_t tb_environment_load(tb_environment_ref_t environment, tb_char_t const* name) { // check tb_assert_and_check_return_val(environment && name, 0); // clear environment first tb_vector_clear(environment); // get values tb_char_t const* values = tb_environment_get_impl(name, tb_null); tb_check_return_val(values, 0); // init value string tb_string_t value; if (tb_string_init(&value)) { // done tb_char_t const* p = values; tb_char_t c = '\0'; while (1) { // the character c = *p++; // make value if (c != ';' && c) tb_string_chrcat(&value, c); else { // save value to environment if (tb_string_size(&value)) tb_vector_insert_tail(environment, tb_string_cstr(&value)); // clear value tb_string_clear(&value); // end? tb_check_break(c); } } // exit value string tb_string_exit(&value); } // exit values if (values) tb_free(values); values = tb_null; // ok? return tb_vector_size(environment); }
static tb_void_t tb_aiop_spak_klist(tb_aiop_ptor_impl_t* impl) { // check tb_assert_and_check_return(impl && impl->klist); // enter tb_spinlock_enter(&impl->klock); // kill it if exists the killing aico if (tb_vector_size(impl->klist)) { // kill all tb_for_all_if (tb_aico_impl_t*, aico, impl->klist, aico) { // the aiop aico tb_aiop_aico_t* aiop_aico = (tb_aiop_aico_t*)aico; // sock? if (aico->type == TB_AICO_TYPE_SOCK) { // add it first if do not exists timeout task if (!aiop_aico->task) { aiop_aico->task = tb_ltimer_task_init(impl->ltimer, 10000, tb_false, tb_aiop_spak_wait_timeout, aico); aiop_aico->bltimer = 1; } // kill the task if (aiop_aico->task) { // kill task if (aiop_aico->bltimer) tb_ltimer_task_kill(impl->ltimer, aiop_aico->task); else tb_timer_task_kill(impl->timer, aiop_aico->task); } } else if (aico->type == TB_AICO_TYPE_FILE) { // kill file tb_aicp_file_kilo(impl, aico); } // trace tb_trace_d("kill: aico: %p, type: %u: ok", aico, aico->type); } }
static tb_size_t tb_vector_iterator_prev_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_rfor_all (tb_char_t*, item, vector) tb_used(item); t = tb_mclock() - t; // time tb_trace_i("tb_vector_iterator_prev(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); }
tb_bool_t tb_environment_save(tb_environment_ref_t environment, tb_char_t const* name) { // check tb_assert_and_check_return_val(environment && name, tb_false); // empty? remove this environment variable if (!tb_vector_size(environment)) return !unsetenv(name); // init values string tb_string_t values; if (!tb_string_init(&values)) return tb_false; // make values string tb_for_all_if (tb_char_t const*, value, environment, value) { // the single value cannot exist ':' tb_assertf(!tb_strchr(value, ':'), "invalid value: %s", value); // append value tb_string_cstrcat(&values, value); tb_string_chrcat(&values, ':'); }
tb_void_t tb_vector_dump(tb_vector_ref_t vector) { // check tb_vector_impl_t* impl = (tb_vector_impl_t*)vector; tb_assert_and_check_return(impl); // trace tb_trace_i("vector: size: %lu", tb_vector_size(vector)); // done tb_char_t cstr[4096]; tb_for_all (tb_pointer_t, data, vector) { // trace if (impl->element.cstr) { tb_trace_i(" %s", impl->element.cstr(&impl->element, data, cstr, sizeof(cstr))); } else { tb_trace_i(" %p", data); } } }
tb_size_t tb_environment_size(tb_environment_ref_t environment) { return tb_vector_size(environment); }
static tb_object_ref_t tb_object_bin_reader_func_dictionary(tb_object_bin_reader_t* reader, tb_size_t type, tb_uint64_t size) { // check tb_assert_and_check_return_val(reader && reader->stream && reader->list, tb_null); // empty? if (!size) return tb_object_dictionary_init(TB_OBJECT_DICTIONARY_SIZE_MICRO, tb_false); // init dictionary tb_object_ref_t dictionary = tb_object_dictionary_init(0, tb_false); tb_assert_and_check_return_val(dictionary, tb_null); // walk tb_size_t i = 0; tb_size_t n = (tb_size_t)size; for (i = 0; i < n; i++) { // read key tb_object_ref_t key = tb_null; do { // the type & size tb_size_t type = 0; tb_uint64_t size = 0; tb_object_reader_bin_type_size(reader->stream, &type, &size); // trace tb_trace_d("key: type: %lu, size: %llu", type, size); // is index? if (!type) { // the object index tb_size_t index = (tb_size_t)size; // check tb_assert_and_check_break(index < tb_vector_size(reader->list)); // the item key = (tb_object_ref_t)tb_iterator_item(reader->list, index); } else { // check tb_assert_and_check_break(type == TB_OBJECT_TYPE_STRING); // the reader func tb_object_bin_reader_func_t func = tb_object_bin_reader_func(type); tb_assert_and_check_break(func); // read it key = func(reader, type, size); tb_assert_and_check_break(key); // save it tb_vector_insert_tail(reader->list, key); // refn-- tb_object_dec(key); } } while (0); // check tb_assert_and_check_break(key && tb_object_type(key) == TB_OBJECT_TYPE_STRING); tb_assert_and_check_break(tb_object_string_size(key) && tb_object_string_cstr(key)); // read val tb_object_ref_t val = tb_null; do { // the type & size tb_size_t type = 0; tb_uint64_t size = 0; tb_object_reader_bin_type_size(reader->stream, &type, &size); // trace tb_trace_d("val: type: %lu, size: %llu", type, size); // is index? if (!type) { // the object index tb_size_t index = (tb_size_t)size; // check tb_assert_and_check_break(index < tb_vector_size(reader->list)); // the item val = (tb_object_ref_t)tb_iterator_item(reader->list, index); // refn++ if (val) tb_object_inc(val); } else { // the reader func tb_object_bin_reader_func_t func = tb_object_bin_reader_func(type); tb_assert_and_check_break(func); // read it val = func(reader, type, size); // save it if (val) tb_vector_insert_tail(reader->list, val); } } while (0); // check tb_assert_and_check_break(val); // set key => val tb_object_dictionary_set(dictionary, tb_object_string_cstr(key), val); } // failed? if (i != n) { if (dictionary) tb_object_exit(dictionary); dictionary = tb_null; } // ok? return dictionary; }
static tb_object_ref_t tb_object_bin_reader_func_array(tb_object_bin_reader_t* reader, tb_size_t type, tb_uint64_t size) { // check tb_assert_and_check_return_val(reader && reader->stream && reader->list, tb_null); // empty? if (!size) return tb_object_array_init(TB_OBJECT_BIN_READER_ARRAY_GROW, tb_false); // init array tb_object_ref_t array = tb_object_array_init(TB_OBJECT_BIN_READER_ARRAY_GROW, tb_false); tb_assert_and_check_return_val(array, tb_null); // walk tb_size_t i = 0; tb_size_t n = (tb_size_t)size; for (i = 0; i < n; i++) { // the type & size tb_size_t type = 0; tb_uint64_t size = 0; tb_object_reader_bin_type_size(reader->stream, &type, &size); // trace tb_trace_d("item: type: %lu, size: %llu", type, size); // is index? tb_object_ref_t item = tb_null; if (!type) { // the object index tb_size_t index = (tb_size_t)size; // check tb_assert_and_check_break(index < tb_vector_size(reader->list)); // the item item = (tb_object_ref_t)tb_iterator_item(reader->list, index); // refn++ if (item) tb_object_inc(item); } else { // the reader func tb_object_bin_reader_func_t func = tb_object_bin_reader_func(type); tb_assert_and_check_break(func); // read it item = func(reader, type, size); // save it tb_vector_insert_tail(reader->list, item); } // check tb_assert_and_check_break(item); // append item tb_object_array_append(array, item); } // failed? if (i != n) { if (array) tb_object_exit(array); array = tb_null; } // ok? return array; }
static __tb_inline__ tb_void_t g2_gl_draw_stencil_clip_path(g2_gl_draw_t* draw, g2_clipper_item_t const* item) { // check tb_assert_and_check_return(item->type == G2_CLIPPER_ITEM_PATH); // the clip path g2_gl_path_t* path = (g2_gl_path_t*)item->u.path; tb_assert_and_check_return(path); // null? tb_check_return(!g2_path_null(path)); // like g2_gl_path_make_like(path); // like rect? if (path->like == G2_GL_PATH_LIKE_RECT) { // clip bounds g2_gl_draw_stencil_clip_bounds(draw, &path->rect); // ok return ; } // like triangle? else if (path->like == G2_GL_PATH_LIKE_TRIG) { // clip triangle g2_clipper_item_t clip = {0}; clip.type = G2_CLIPPER_ITEM_TRIANGLE; clip.mode = item->mode; clip.u.triangle = path->trig; g2_gl_draw_stencil_clip_triangle(draw, &clip); // ok return ; } // make draw if (!g2_gl_path_make_fill(path)) return ; // check tb_assert(path->fill.data && tb_vector_size(path->fill.data)); tb_assert(path->fill.size && tb_vector_size(path->fill.size)); tb_check_return(path->fill.rect.x1 < path->fill.rect.x2 && path->fill.rect.y1 < path->fill.rect.y2); // init vertices if (draw->context->version < 0x20) g2_glVertexPointer(2, G2_GL_FLOAT, 0, tb_vector_data(path->fill.data)); else g2_glVertexAttribPointer(g2_gl_program_location(draw->program, G2_GL_PROGRAM_LOCATION_VERTICES), 2, G2_GL_FLOAT, G2_GL_FALSE, 0, tb_vector_data(path->fill.data)); // clip path tb_size_t head = 0; tb_size_t size = 0; tb_size_t itor = tb_iterator_head(path->fill.size); tb_size_t tail = tb_iterator_tail(path->fill.size); for (; itor != tail; itor++) { size = tb_iterator_item(path->fill.size, itor); g2_glDrawArrays(G2_GL_TRIANGLE_FAN, (g2_GLint_t)head, (g2_GLint_t)size); head += size; } }
tb_void_t tb_vector_ninsert_tail(tb_vector_ref_t vector, tb_cpointer_t data, tb_size_t size) { tb_vector_ninsert_prev(vector, tb_vector_size(vector), data, size); }
tb_size_t tb_stack_size(tb_stack_ref_t stack) { return tb_vector_size((tb_vector_ref_t)stack); }
static tb_long_t tb_aiop_rtor_poll_wait(tb_aiop_rtor_impl_t* rtor, tb_aioe_t* list, tb_size_t maxn, tb_long_t timeout) { // check tb_aiop_rtor_poll_impl_t* impl = (tb_aiop_rtor_poll_impl_t*)rtor; tb_assert_and_check_return_val(impl && impl->pfds && impl->cfds && list && maxn, -1); // the aiop tb_aiop_impl_t* aiop = rtor->aiop; tb_assert_and_check_return_val(aiop, tb_false); // loop tb_long_t wait = 0; tb_bool_t stop = tb_false; tb_hong_t time = tb_mclock(); while (!wait && !stop && (timeout < 0 || tb_mclock() < time + timeout)) { // copy pfds tb_spinlock_enter(&impl->lock.pfds); tb_vector_copy(impl->cfds, impl->pfds); tb_spinlock_leave(&impl->lock.pfds); // cfds struct pollfd* cfds = (struct pollfd*)tb_vector_data(impl->cfds); tb_size_t cfdm = tb_vector_size(impl->cfds); tb_assert_and_check_return_val(cfds && cfdm, -1); // wait tb_long_t cfdn = poll(cfds, cfdm, timeout); tb_assert_and_check_return_val(cfdn >= 0, -1); // timeout? tb_check_return_val(cfdn, 0); // sync tb_size_t i = 0; for (i = 0; i < cfdm && wait < maxn; i++) { // the sock tb_socket_ref_t sock = tb_fd2sock(cfds[i].fd); tb_assert_and_check_return_val(sock, -1); // the events tb_size_t events = cfds[i].revents; tb_check_continue(events); // spak? if (sock == aiop->spak[1] && (events & POLLIN)) { // read spak tb_char_t spak = '\0'; if (1 != tb_socket_recv(aiop->spak[1], (tb_byte_t*)&spak, 1)) return -1; // killed? if (spak == 'k') return -1; // stop to wait stop = tb_true; // continue it continue ; } // skip spak tb_check_continue(sock != aiop->spak[1]); // the aioo tb_size_t code = TB_AIOE_CODE_NONE; tb_cpointer_t priv = tb_null; tb_aioo_impl_t* aioo = tb_null; tb_spinlock_enter(&impl->lock.hash); if (impl->hash) { aioo = (tb_aioo_impl_t*)tb_hash_get(impl->hash, sock); if (aioo) { // save code & data code = aioo->code; priv = aioo->priv; // oneshot? clear it if (aioo->code & TB_AIOE_CODE_ONESHOT) { aioo->code = TB_AIOE_CODE_NONE; aioo->priv = tb_null; } } } tb_spinlock_leave(&impl->lock.hash); tb_check_continue(aioo && code); // init aioe tb_aioe_t aioe = {0}; aioe.priv = priv; aioe.aioo = (tb_aioo_ref_t)aioo; if (events & POLLIN) { aioe.code |= TB_AIOE_CODE_RECV; if (code & TB_AIOE_CODE_ACPT) aioe.code |= TB_AIOE_CODE_ACPT; } if (events & POLLOUT) { aioe.code |= TB_AIOE_CODE_SEND; if (code & TB_AIOE_CODE_CONN) aioe.code |= TB_AIOE_CODE_CONN; } if ((events & POLLHUP) && !(code & (TB_AIOE_CODE_RECV | TB_AIOE_CODE_SEND))) aioe.code |= TB_AIOE_CODE_RECV | TB_AIOE_CODE_SEND; // save aioe list[wait++] = aioe; // oneshot? if (code & TB_AIOE_CODE_ONESHOT) { tb_spinlock_enter(&impl->lock.pfds); struct pollfd* pfds = (struct pollfd*)tb_vector_data(impl->pfds); if (pfds) pfds[i].events = 0; tb_spinlock_leave(&impl->lock.pfds); } } } // ok return wait; }
tb_long_t tb_poller_wait(tb_poller_ref_t self, tb_poller_event_func_t func, tb_long_t timeout) { // check tb_poller_poll_ref_t poller = (tb_poller_poll_ref_t)self; tb_assert_and_check_return_val(poller && poller->pfds && poller->cfds && func, -1); // loop tb_long_t wait = 0; tb_bool_t stop = tb_false; tb_hong_t time = tb_mclock(); while (!wait && !stop && (timeout < 0 || tb_mclock() < time + timeout)) { // pfds struct pollfd* pfds = (struct pollfd*)tb_vector_data(poller->pfds); tb_size_t pfdm = tb_vector_size(poller->pfds); tb_assert_and_check_return_val(pfds && pfdm, -1); // wait tb_long_t pfdn = poll(pfds, pfdm, timeout); tb_assert_and_check_return_val(pfdn >= 0, -1); // timeout? tb_check_return_val(pfdn, 0); // copy fds tb_vector_copy(poller->cfds, poller->pfds); // walk the copied fds pfds = (struct pollfd*)tb_vector_data(poller->cfds); pfdm = tb_vector_size(poller->cfds); // sync tb_size_t i = 0; for (i = 0; i < pfdm; i++) { // the sock tb_socket_ref_t sock = tb_fd2sock(pfds[i].fd); tb_assert_and_check_return_val(sock, -1); // the poll events tb_size_t poll_events = pfds[i].revents; tb_check_continue(poll_events); // spak? if (sock == poller->pair[1] && (poll_events & POLLIN)) { // read spak tb_char_t spak = '\0'; if (1 != tb_socket_recv(poller->pair[1], (tb_byte_t*)&spak, 1)) return -1; // killed? if (spak == 'k') return -1; // stop to wait stop = tb_true; // continue it continue ; } // skip spak tb_check_continue(sock != poller->pair[1]); // init events tb_size_t events = TB_POLLER_EVENT_NONE; if (poll_events & POLLIN) events |= TB_POLLER_EVENT_RECV; if (poll_events & POLLOUT) events |= TB_POLLER_EVENT_SEND; if ((poll_events & POLLHUP) && !(events & (TB_POLLER_EVENT_RECV | TB_POLLER_EVENT_SEND))) events |= TB_POLLER_EVENT_RECV | TB_POLLER_EVENT_SEND; // call event function func(self, sock, events, tb_poller_hash_get(poller, sock)); // update the events count wait++; } } // ok return wait; }
tb_void_t tb_vector_insert_tail(tb_vector_ref_t vector, tb_cpointer_t data) { tb_vector_insert_prev(vector, tb_vector_size(vector), data); }
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_bool_t tb_vector_save(tb_vector_ref_t vector, tb_stream_ref_t stream) { // check tb_vector_impl_t* impl = (tb_vector_impl_t*)vector; tb_assert_and_check_return_val(impl && stream, tb_false); tb_assert_and_check_return_val(impl->func.hash && impl->func.save, tb_false); // the offset tb_hize_t offset = tb_stream_offset(stream); // done tb_bool_t ok = tb_false; tb_uint32_t crc32 = 0; do { // calc type crc32 = tb_crc_encode_cstr(TB_CRC_MODE_32_IEEE_LE, crc32, "vector"); // calc item type crc32 = tb_crc_encode_value(TB_CRC_MODE_32_IEEE_LE, crc32, impl->func.type); // calc item size crc32 = tb_crc_encode_value(TB_CRC_MODE_32_IEEE_LE, crc32, impl->func.size); // save the head crc32 if (!tb_stream_bwrit_u32_be(stream, crc32)) break; // the size tb_size_t size = tb_vector_size(vector); // save size if (!tb_stream_bwrit_u32_be(stream, (tb_uint32_t)size)) break; // save vector tb_size_t save = 0; tb_for_all (tb_cpointer_t, item, vector) { // save item if (!impl->func.save(&impl->func, item, stream)) break; // hash item tb_size_t hash = impl->func.hash(&impl->func, item, -1, 0); // calc item crc32 = tb_crc_encode_value(TB_CRC_MODE_32_IEEE_LE, crc32, hash); // update the save count save++; } // check tb_assert_and_check_break(save == size); // save the body crc32 if (!tb_stream_bwrit_u32_be(stream, crc32)) break; // ok ok = tb_true; } while (0); // failed? restore it if (!ok) tb_stream_seek(stream, offset); // ok? return ok; }
tb_void_t g2_gl_draw_path(g2_gl_painter_t* painter, tb_size_t mode, g2_gl_path_t const* path) { // check tb_assert_and_check_return(painter && path); tb_assert_and_check_return((mode == G2_STYLE_MODE_FILL) || (mode == G2_STYLE_MODE_STOK)); // null? tb_check_return(!g2_path_null(path)); // make like g2_gl_path_make_like((g2_gl_path_t*)path); // make draw if (!g2_gl_path_make_fill((g2_gl_path_t*)path)) return ; // check tb_assert(path->fill.data && tb_vector_size(path->fill.data)); tb_assert(path->fill.size && tb_vector_size(path->fill.size)); tb_check_return(path->fill.rect.x1 < path->fill.rect.x2 && path->fill.rect.y1 < path->fill.rect.y2); // like rect? if (path->like == G2_GL_PATH_LIKE_RECT) { // draw bounds g2_gl_draw_bounds(painter, mode, &path->rect); // ok return ; } // like triangle? else if (path->like == G2_GL_PATH_LIKE_TRIG) { // draw triangle g2_gl_draw_triangle(painter, mode, &path->trig); // ok return ; } // init draw g2_gl_draw_t draw = {0}; if (!g2_gl_draw_init(&draw, painter, mode, path->like == G2_GL_PATH_LIKE_CONX? G2_GL_DRAW_FLAG_CONVEX : G2_GL_DRAW_FLAG_NONE)) return ; // init bounds g2_gl_rect_t bounds = path->fill.rect; if (draw.mode == G2_STYLE_MODE_STOK) g2_gl_bounds_stok(&bounds, 1); // clip draw g2_gl_draw_clip(&draw, &bounds); // init vertices if (draw.context->version < 0x20) g2_glVertexPointer(2, G2_GL_FLOAT, 0, tb_vector_data(path->fill.data)); else g2_glVertexAttribPointer(g2_gl_program_location(draw.program, G2_GL_PROGRAM_LOCATION_VERTICES), 2, G2_GL_FLOAT, G2_GL_FALSE, 0, tb_vector_data(path->fill.data)); // draw vertices tb_size_t head = 0; tb_size_t size = 0; tb_size_t itor = tb_iterator_head(path->fill.size); tb_size_t tail = tb_iterator_tail(path->fill.size); g2_GLenum_t gmode = (draw.mode == G2_STYLE_MODE_FILL)? G2_GL_TRIANGLE_FAN : G2_GL_LINE_STRIP; for (; itor != tail; itor++) { size = tb_iterator_item(path->fill.size, itor); g2_glDrawArrays(gmode, (g2_GLint_t)head, (g2_GLint_t)size); head += size; } // draw fill g2_gl_draw_fill(&draw, &bounds); // exit draw g2_gl_draw_exit(&draw); }