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); }
tb_bool_t tb_environment_insert(tb_environment_ref_t environment, tb_char_t const* value, tb_bool_t to_head) { // check tb_assert_and_check_return_val(environment && value, tb_false); // insert value into the head if (to_head) tb_vector_insert_head(environment, value); // insert value into the tail else tb_vector_insert_tail(environment, value); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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); }
tb_bool_t tb_environment_replace(tb_environment_ref_t environment, tb_char_t const* value) { // check tb_assert_and_check_return_val(environment, tb_false); // clear it first tb_vector_clear(environment); // insert value if (value) tb_vector_insert_tail(environment, value); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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_bool_t tb_aiop_rtor_poll_addo(tb_aiop_rtor_impl_t* rtor, tb_aioo_impl_t const* aioo) { // 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 && aioo && aioo->sock, tb_false); // the aiop tb_aiop_impl_t* aiop = rtor->aiop; tb_assert_and_check_return_val(aiop, tb_false); // add sock => aioo tb_bool_t ok = tb_false; tb_spinlock_enter(&impl->lock.hash); if (impl->hash) { tb_hash_set(impl->hash, aioo->sock, aioo); ok = tb_true; } tb_spinlock_leave(&impl->lock.hash); tb_assert_and_check_return_val(ok, tb_false); // the code tb_size_t code = aioo->code; // init pfd struct pollfd pfd = {0}; pfd.fd = ((tb_long_t)aioo->sock) - 1; if (code & TB_AIOE_CODE_RECV || code & TB_AIOE_CODE_ACPT) pfd.events |= POLLIN; if (code & TB_AIOE_CODE_SEND || code & TB_AIOE_CODE_CONN) pfd.events |= POLLOUT; // add pfd, TODO: addo by binary search tb_spinlock_enter(&impl->lock.pfds); tb_vector_insert_tail(impl->pfds, &pfd); tb_spinlock_leave(&impl->lock.pfds); // spak it if (aiop->spak[0] && code) tb_socket_send(aiop->spak[0], (tb_byte_t const*)"p", 1); // ok? return ok; }
tb_bool_t tb_poller_insert(tb_poller_ref_t self, tb_socket_ref_t sock, tb_size_t events, tb_cpointer_t priv) { // check tb_poller_poll_ref_t poller = (tb_poller_poll_ref_t)self; tb_assert_and_check_return_val(poller && poller->pfds && sock, tb_false); // oneshot is not supported now tb_assertf(!(events & TB_POLLER_EVENT_ONESHOT), "cannot insert events with oneshot, not supported!"); // init events struct pollfd pfd = {0}; if (events & TB_POLLER_EVENT_RECV) pfd.events |= POLLIN; if (events & TB_POLLER_EVENT_SEND) pfd.events |= POLLOUT; // save fd, TODO uses binary search pfd.fd = tb_sock2fd(sock); tb_vector_insert_tail(poller->pfds, &pfd); // bind user private data to socket tb_poller_hash_set(poller, sock, priv); // ok return tb_true; }
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_bool_t tb_vector_load(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.load && impl->func.free, tb_false); // clear the vector first tb_vector_clear(vector); // the offset tb_hize_t offset = tb_stream_offset(stream); // done tb_bool_t ok = tb_false; tb_uint32_t crc32 = 0; tb_pointer_t buff = tb_null; 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); // load the head crc32 tb_uint32_t crc32_head = tb_stream_bread_u32_be(stream); tb_assert_and_check_break(crc32_head == crc32); // make item buffer buff = impl->func.size? tb_malloc(impl->func.size) : tb_null; // load size tb_uint32_t size = tb_stream_bread_u32_be(stream); // load vector tb_uint32_t load = 0; for (load = 0; load < size; load++) { // load item if (!impl->func.load(&impl->func, buff, stream)) break; // the item data tb_cpointer_t data = impl->func.data(&impl->func, buff); // hash item tb_size_t hash = impl->func.hash(&impl->func, data, -1, 0); // calc item crc32 = tb_crc_encode_value(TB_CRC_MODE_32_IEEE_LE, crc32, hash); // save item tb_vector_insert_tail(vector, data); // free name impl->func.free(&impl->func, buff); } // check tb_assert_and_check_break(load == size); // load the body crc32 tb_uint32_t crc32_body = tb_stream_bread_u32_be(stream); tb_assert_and_check_break(crc32_body == crc32); // ok ok = tb_true; } while (0); // failed? if (!ok) { // restore it tb_stream_seek(stream, offset); // clear it tb_vector_clear(vector); } // exit buffer if (buff) tb_free(buff); buff = tb_null; // ok? return ok; }
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_bool_t tb_thread_pool_worker_walk_pull_and_clean(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t value) { // the worker pull tb_thread_pool_worker_t* worker = (tb_thread_pool_worker_t*)value; tb_assert_abort(worker && worker->jobs && worker->stats); // the job tb_thread_pool_job_t* job = (tb_thread_pool_job_t*)item; tb_assert_abort(job); // the job state tb_size_t state = tb_atomic_get(&job->state); // waiting and non-full? pull it tb_bool_t ok = tb_false; if (state == TB_STATE_WAITING && worker->pull < TB_THREAD_POOL_JOBS_PULL_TIME_MAXN) { // 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 pending", worker->id, job->task.done, job->task.name); } // finished or killed? remove it else if (state == TB_STATE_FINISHED || state == TB_STATE_KILLED) { // trace tb_trace_d("worker[%lu]: remove: task[%p:%s] from pending", worker->id, job->task.done, job->task.name); // exit the job if (job->task.exit) job->task.exit((tb_thread_pool_worker_ref_t)worker, job->task.priv); // remove it from the waiting or urgent jobs ok = tb_true; // refn-- if (job->refn > 1) job->refn--; // remove it from pool directly else { // the pool tb_thread_pool_impl_t* impl = (tb_thread_pool_impl_t*)worker->pool; tb_assert_abort(impl); // remove it from the jobs pool tb_fixed_pool_free(impl->jobs_pool, job); } } // remove it? return ok; }
tb_void_t tb_stack_put(tb_stack_ref_t stack, tb_cpointer_t data) { tb_vector_insert_tail((tb_vector_ref_t)stack, data); }