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_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); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_poller_ref_t tb_poller_init(tb_cpointer_t priv) { // done tb_bool_t ok = tb_false; tb_poller_poll_ref_t poller = tb_null; do { // make poller poller = tb_malloc0_type(tb_poller_poll_t); tb_assert_and_check_break(poller); // init poll fds poller->pfds = tb_vector_init(0, tb_element_mem(sizeof(struct pollfd), tb_null, tb_null)); tb_assert_and_check_break(poller->pfds); // init copied poll fds poller->cfds = tb_vector_init(0, tb_element_mem(sizeof(struct pollfd), tb_null, tb_null)); tb_assert_and_check_break(poller->cfds); // init user private data poller->priv = priv; // init pair sockets if (!tb_socket_pair(TB_SOCKET_TYPE_TCP, poller->pair)) break; // insert pair socket first if (!tb_poller_insert((tb_poller_ref_t)poller, poller->pair[1], TB_POLLER_EVENT_RECV, tb_null)) break; // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (poller) tb_poller_exit((tb_poller_ref_t)poller); poller = tb_null; } // ok? return (tb_poller_ref_t)poller; }
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); }
static tb_object_ref_t tb_object_bin_reader_done(tb_stream_ref_t stream) { // read bin header tb_byte_t data[32] = {0}; if (!tb_stream_bread(stream, data, 5)) return tb_null; // check if (tb_strnicmp((tb_char_t const*)data, "tbo00", 5)) return tb_null; // init tb_object_ref_t object = tb_null; tb_object_bin_reader_t reader = {0}; // init reader reader.stream = stream; reader.list = tb_vector_init(256, tb_item_func_obj()); tb_assert_and_check_return_val(reader.list, tb_null); // the type & size tb_size_t type = 0; tb_uint64_t size = 0; tb_object_reader_bin_type_size(stream, &type, &size); // trace tb_trace_d("root: type: %lu, size: %llu", type, size); // the func tb_object_bin_reader_func_t func = tb_object_bin_reader_func(type); // check tb_assert(func); // read it if (func) object = func(&reader, type, size); // exit the list if (reader.list) tb_vector_exit(reader.list); // ok? return object; }
tb_long_t tb_regex_match_done(tb_char_t const* pattern, tb_size_t mode, tb_char_t const* cstr, tb_size_t size, tb_size_t start, tb_size_t* plength, tb_vector_ref_t* presults) { // clear results first if (presults) *presults = tb_null; // init regex tb_long_t ok = -1; tb_regex_ref_t regex = tb_regex_init(pattern, mode); if (regex) { // init results tb_vector_ref_t results = tb_vector_init(16, tb_element_mem(sizeof(tb_regex_match_t), tb_regex_match_exit, tb_null)); if (results) { // match regex ok = tb_regex_match(regex, cstr, size, start, plength, &results); // ok? if (ok >= 0) { // save results if (presults) { *presults = results; results = tb_null; } } // exit results if (results) tb_vector_exit(results); results = tb_null; } // exit regex tb_regex_exit(regex); } // ok? return ok; }
tb_long_t tb_regex_match(tb_regex_ref_t self, tb_char_t const* cstr, tb_size_t size, tb_size_t start, tb_size_t* plength, tb_vector_ref_t* presults) { // check tb_regex_t* regex = (tb_regex_t*)self; tb_assert_and_check_return_val(regex && regex->code && regex->match_data && cstr, -1); // done tb_long_t ok = -1; do { // clear length first if (plength) *plength = 0; // end? tb_check_break(start < size); // init options #ifdef __tb_debug__ tb_uint32_t options = 0; #else tb_uint32_t options = PCRE2_NO_UTF_CHECK; #endif // match it tb_long_t count = pcre2_match(regex->code, (PCRE2_SPTR)cstr, (PCRE2_SIZE)size, (PCRE2_SIZE)start, options, regex->match_data, tb_null); if (count < 0) { // no match? tb_check_break(count != PCRE2_ERROR_NOMATCH); #if defined(__tb_debug__) && !defined(TB_CONFIG_OS_WINDOWS) // get error info PCRE2_UCHAR info[256]; pcre2_get_error_message(count, info, sizeof(info)); // trace tb_trace_d("match failed at offset %lu: error: %ld, %s\n", start, count, info); #endif // end break; } // check tb_assertf_and_check_break(count, "ovector has not enough space!"); // get output vector PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(regex->match_data); tb_assert_and_check_break(ovector); // get the match offset and length tb_size_t offset = (tb_size_t)ovector[0]; tb_size_t length = (tb_size_t)ovector[1] - ovector[0]; tb_assert_and_check_break(offset + length <= size); // trace tb_trace_d("matched count: %lu, offset: %lu, length: %lu", count, offset, length); // save results if (presults) { // init results if not exists tb_vector_ref_t results = *presults; if (!results) { // init it if (!regex->results) regex->results = tb_vector_init(16, tb_element_mem(sizeof(tb_regex_match_t), tb_regex_match_exit, tb_null)); // save it *presults = results = regex->results; } tb_assert_and_check_break(results); // clear it first tb_vector_clear(results); // done tb_long_t i = 0; tb_regex_match_t entry; for (i = 0; i < count; i++) { // get substring offset and length tb_size_t substr_offset = ovector[i << 1]; tb_size_t substr_length = ovector[(i << 1) + 1] - ovector[i << 1]; tb_assert_and_check_break(substr_offset + substr_length <= size); // make match entry entry.cstr = tb_strndup(cstr + substr_offset, substr_length); entry.size = substr_length; entry.start = substr_offset; tb_assert_and_check_break(entry.cstr); // trace tb_trace_d(" matched: [%lu, %lu]: %s", entry.start, entry.size, entry.cstr); // append it tb_vector_insert_tail(results, &entry); } tb_assert_and_check_break(i == count); } // save length if (plength) *plength = length; // ok ok = offset; } while (0); // ok? return ok; }
tb_environment_ref_t tb_environment_init() { // init environment return tb_vector_init(8, tb_element_str(tb_true)); }
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_stack_ref_t tb_stack_init(tb_size_t grow, tb_element_t element) { return (tb_stack_ref_t)tb_vector_init(grow, element); }