/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_object_reader_t* tb_object_xplist_reader() { // the reader static tb_object_reader_t s_reader = {0}; // init reader s_reader.read = tb_object_xplist_reader_done; s_reader.probe = tb_object_xplist_reader_probe; // init hooker s_reader.hooker = tb_hash_map_init(TB_HASH_MAP_BUCKET_SIZE_MICRO, tb_element_str(tb_false), tb_element_ptr(tb_null, tb_null)); tb_assert_and_check_return_val(s_reader.hooker, tb_null); // hook reader tb_hash_map_insert(s_reader.hooker, "date", tb_object_xplist_reader_func_date); tb_hash_map_insert(s_reader.hooker, "data", tb_object_xplist_reader_func_data); tb_hash_map_insert(s_reader.hooker, "array", tb_object_xplist_reader_func_array); tb_hash_map_insert(s_reader.hooker, "string", tb_object_xplist_reader_func_string); tb_hash_map_insert(s_reader.hooker, "integer", tb_object_xplist_reader_func_number); tb_hash_map_insert(s_reader.hooker, "real", tb_object_xplist_reader_func_number); tb_hash_map_insert(s_reader.hooker, "true", tb_object_xplist_reader_func_boolean); tb_hash_map_insert(s_reader.hooker, "false", tb_object_xplist_reader_func_boolean); tb_hash_map_insert(s_reader.hooker, "dict", tb_object_xplist_reader_func_dictionary); // ok return &s_reader; }
tb_void_t tb_thread_store_setp(tb_thread_store_data_t const* data) { // enter lock tb_spinlock_enter(&g_lock); // get data if (g_store) tb_hash_map_insert(g_store, (tb_pointer_t)tb_thread_self(), data); // leave lock tb_spinlock_leave(&g_lock); }
tb_void_t tb_object_dictionary_insert(tb_object_ref_t object, tb_char_t const* key, tb_object_ref_t val) { // check tb_object_dictionary_t* dictionary = tb_object_dictionary_cast(object); tb_assert_and_check_return(dictionary && dictionary->hash && key && val); // add tb_hash_map_insert(dictionary->hash, key, val); // refn-- if (!dictionary->incr) tb_object_exit(val); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_aiop_rtor_select_addo(tb_aiop_rtor_impl_t* rtor, tb_aioo_impl_t const* aioo) { // check tb_aiop_rtor_select_impl_t* impl = (tb_aiop_rtor_select_impl_t*)rtor; tb_assert_and_check_return_val(impl && rtor->aiop && aioo && aioo->sock, tb_false); // the aiop tb_aiop_impl_t* aiop = rtor->aiop; tb_assert_and_check_return_val(aiop, tb_false); // check size tb_spinlock_enter(&impl->lock.hash); tb_size_t size = tb_hash_map_size(impl->hash); tb_spinlock_leave(&impl->lock.hash); tb_assert_and_check_return_val(size < FD_SETSIZE, tb_false); // add sock => aioo tb_bool_t ok = tb_false; tb_spinlock_enter(&impl->lock.hash); if (impl->hash) { tb_hash_map_insert(impl->hash, aioo->sock, aioo); ok = tb_true; } tb_spinlock_leave(&impl->lock.hash); tb_assert_and_check_return_val(ok, tb_false); // the fd tb_long_t fd = ((tb_long_t)aioo->sock) - 1; // the code tb_size_t code = aioo->code; // enter tb_spinlock_enter(&impl->lock.pfds); // update fd max if (fd > (tb_long_t)impl->sfdm) impl->sfdm = (tb_size_t)fd; // init fds if (code & (TB_AIOE_CODE_RECV | TB_AIOE_CODE_ACPT)) FD_SET(fd, &impl->rfdi); if (code & (TB_AIOE_CODE_SEND | TB_AIOE_CODE_CONN)) FD_SET(fd, &impl->wfdi); // leave 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_object_json_reader_hook(tb_char_t type, tb_object_json_reader_func_t func) { // check tb_assert_and_check_return_val(type && func, tb_false); // the reader tb_object_reader_t* reader = tb_object_reader_get(TB_OBJECT_FORMAT_JSON); tb_assert_and_check_return_val(reader && reader->hooker, tb_false); // hook it tb_hash_map_insert(reader->hooker, (tb_pointer_t)(tb_size_t)type, func); // ok return tb_true; }
tb_bool_t tb_object_xplist_reader_hook(tb_char_t const* type, tb_object_xplist_reader_func_t func) { // check tb_assert_and_check_return_val(type && func, tb_false); // the reader tb_object_reader_t* reader = tb_object_reader_get(TB_OBJECT_FORMAT_XPLIST); tb_assert_and_check_return_val(reader && reader->hooker, tb_false); // hook it tb_hash_map_insert(reader->hooker, type, func); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_object_reader_t* tb_object_json_reader() { // the reader static tb_object_reader_t s_reader = {0}; // init reader s_reader.read = tb_object_json_reader_done; s_reader.probe = tb_object_json_reader_probe; // init hooker s_reader.hooker = tb_hash_map_init(TB_HASH_MAP_BUCKET_SIZE_MICRO, tb_element_uint8(), tb_element_ptr(tb_null, tb_null)); tb_assert_and_check_return_val(s_reader.hooker, tb_null); // hook reader tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'n', tb_object_json_reader_func_null); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'N', tb_object_json_reader_func_null); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'[', tb_object_json_reader_func_array); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'\'', tb_object_json_reader_func_string); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'\"', tb_object_json_reader_func_string); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'0', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'1', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'2', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'3', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'4', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'5', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'6', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'7', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'8', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'9', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'.', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'-', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'+', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'e', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'E', tb_object_json_reader_func_number); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'t', tb_object_json_reader_func_boolean); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'T', tb_object_json_reader_func_boolean); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'f', tb_object_json_reader_func_boolean); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'F', tb_object_json_reader_func_boolean); tb_hash_map_insert(s_reader.hooker, (tb_pointer_t)'{', tb_object_json_reader_func_dictionary); // ok return &s_reader; }
tb_size_t tb_hash_set_insert(tb_hash_set_ref_t self, tb_cpointer_t data) { return tb_hash_map_insert((tb_hash_map_ref_t)self, data, tb_b2p(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; }
static tb_void_t tb_ifaddrs_interface_done_hwaddr(tb_list_ref_t interfaces, tb_hash_map_ref_t names, struct nlmsghdr* response) { // check tb_assert_and_check_return(interfaces && names && response); // the info struct ifaddrmsg* info = (struct ifaddrmsg *)NLMSG_DATA(response); // attempt to find the interface name tb_bool_t owner = tb_false; tb_char_t* name = (tb_char_t*)tb_hash_map_get(names, tb_u2p(info->ifa_index)); if (!name) { // get the interface name struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFLA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFLA_IFNAME: { // make name name = (tb_char_t*)tb_ralloc(name, rta_data_size + 1); tb_assert_and_check_break(name); // copy name tb_strlcpy(name, rta_data, rta_data_size + 1); // save name tb_hash_map_insert(names, tb_u2p(info->ifa_index), name); owner = tb_true; } break; default: break; } } } // check tb_check_return(name); // done struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFLA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFLA_ADDRESS: { // no hwaddr? if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // check tb_check_break(rta_data_size == sizeof(interface->hwaddr.u8)); // save flags interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; if (info->ifa_flags & IFF_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save hwaddr tb_memcpy(interface->hwaddr.u8, rta_data, sizeof(interface->hwaddr.u8)); // trace tb_trace_d("name: %s, hwaddr: %{hwaddr}", name, &interface->hwaddr); // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } } break; case IFLA_IFNAME: case IFLA_BROADCAST: case IFLA_STATS: break; default: break; } } // exit name if (name && owner) tb_free(name); name = tb_null; }
static tb_void_t tb_ifaddrs_interface_done_ipaddr(tb_list_ref_t interfaces, tb_hash_map_ref_t names, struct nlmsghdr* response) { // check tb_assert_and_check_return(interfaces && names && response); // the info struct ifaddrmsg* info = (struct ifaddrmsg *)NLMSG_DATA(response); // must be not link tb_assert_and_check_return(info->ifa_family != AF_PACKET); // attempt to find the interface name tb_bool_t owner = tb_false; tb_char_t* name = (tb_char_t*)tb_hash_map_get(names, tb_u2p(info->ifa_index)); if (!name) { // get the interface name struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFA_LABEL: { // make name name = (tb_char_t*)tb_ralloc(name, rta_data_size + 1); tb_assert_and_check_break(name); // copy name tb_strlcpy(name, rta_data, rta_data_size + 1); // save name tb_hash_map_insert(names, tb_u2p(info->ifa_index), name); owner = tb_true; } break; default: break; } } } // check tb_check_return(name); // done struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done tb_pointer_t rta_data = RTA_DATA(rta); switch(rta->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: { // make ipaddr tb_ipaddr_t ipaddr; if (!tb_ifaddrs_netlink_ipaddr_save(&ipaddr, info->ifa_family, info->ifa_index, rta_data)) break; // save flags if ((info->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save ipaddr switch (tb_ipaddr_family(&ipaddr)) { case TB_IPADDR_FAMILY_IPV4: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; interface->ipaddr4 = ipaddr.u.ipv4; } break; case TB_IPADDR_FAMILY_IPV6: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; interface->ipaddr6 = ipaddr.u.ipv6; } break; default: break; } // trace tb_trace_d("name: %s, ipaddr: %{ipaddr}", name, &ipaddr); // new interface? save it if (tb_ipaddr_family(&ipaddr) && interface == &interface_new) { // save interface name interface->name = tb_strdup(name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case IFA_LABEL: case IFA_BROADCAST: break; default: break; } } // exit name if (name && owner) tb_free(name); name = tb_null; }