int main(int argc, char *argv[]) { unsigned int nworkers; unsigned int i; isc_thread_t workers[100]; char name[100]; void *dupname; if (argc > 1) nworkers = atoi(argv[1]); else nworkers = 2; if (nworkers > 100) nworkers = 100; printf("%d workers\n", nworkers); RUNTIME_CHECK(isc_rwlock_init(&lock, 5, 10) == ISC_R_SUCCESS); for (i = 0; i < nworkers; i++) { sprintf(name, "%02u", i); dupname = strdup(name); RUNTIME_CHECK(dupname != NULL); if (i != 0 && i % 3 == 0) RUNTIME_CHECK(isc_thread_create(run1, dupname, &workers[i]) == ISC_R_SUCCESS); else RUNTIME_CHECK(isc_thread_create(run2, dupname, &workers[i]) == ISC_R_SUCCESS); } for (i = 0; i < nworkers; i++) (void)isc_thread_join(workers[i], NULL); isc_rwlock_destroy(&lock); return (0); }
void isc_taskmgr_destroy(isc_taskmgr_t **managerp) { isc_taskmgr_t *manager; isc_task_t *task; unsigned int i; /* * Destroy '*managerp'. */ REQUIRE(managerp != NULL); manager = *managerp; REQUIRE(VALID_MANAGER(manager)); #ifndef ISC_PLATFORM_USETHREADS UNUSED(i); if (manager->refs > 1) { manager->refs--; *managerp = NULL; return; } #endif /* ISC_PLATFORM_USETHREADS */ XTHREADTRACE("isc_taskmgr_destroy"); /* * Only one non-worker thread may ever call this routine. * If a worker thread wants to initiate shutdown of the * task manager, it should ask some non-worker thread to call * isc_taskmgr_destroy(), e.g. by signalling a condition variable * that the startup thread is sleeping on. */ /* * Unlike elsewhere, we're going to hold this lock a long time. * We need to do so, because otherwise the list of tasks could * change while we were traversing it. * * This is also the only function where we will hold both the * task manager lock and a task lock at the same time. */ LOCK(&manager->lock); /* * Make sure we only get called once. */ INSIST(!manager->exiting); manager->exiting = ISC_TRUE; /* * Post shutdown event(s) to every task (if they haven't already been * posted). */ for (task = HEAD(manager->tasks); task != NULL; task = NEXT(task, link)) { LOCK(&task->lock); if (task_shutdown(task)) ENQUEUE(manager->ready_tasks, task, ready_link); UNLOCK(&task->lock); } #ifdef ISC_PLATFORM_USETHREADS /* * Wake up any sleeping workers. This ensures we get work done if * there's work left to do, and if there are already no tasks left * it will cause the workers to see manager->exiting. */ BROADCAST(&manager->work_available); UNLOCK(&manager->lock); /* * Wait for all the worker threads to exit. */ for (i = 0; i < manager->workers; i++) (void)isc_thread_join(manager->threads[i], NULL); #else /* ISC_PLATFORM_USETHREADS */ /* * Dispatch the shutdown events. */ UNLOCK(&manager->lock); while (isc__taskmgr_ready()) (void)isc__taskmgr_dispatch(); if (!ISC_LIST_EMPTY(manager->tasks)) isc_mem_printallactive(stderr); INSIST(ISC_LIST_EMPTY(manager->tasks)); #endif /* ISC_PLATFORM_USETHREADS */ manager_free(manager); *managerp = NULL; }
ISC_TIMERFUNC_SCOPE void isc__timermgr_destroy(isc_timermgr_t **managerp) { isc__timermgr_t *manager; isc_mem_t *mctx; /* * Destroy a timer manager. */ REQUIRE(managerp != NULL); manager = (isc__timermgr_t *)*managerp; REQUIRE(VALID_MANAGER(manager)); LOCK(&manager->lock); #ifdef USE_SHARED_MANAGER manager->refs--; if (manager->refs > 0) { UNLOCK(&manager->lock); *managerp = NULL; return; } timermgr = NULL; #endif /* USE_SHARED_MANAGER */ #ifndef USE_TIMER_THREAD isc__timermgr_dispatch((isc_timermgr_t *)manager); #endif REQUIRE(EMPTY(manager->timers)); manager->done = ISC_TRUE; #ifdef USE_TIMER_THREAD XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SIGNALDESTROY, "signal (destroy)")); SIGNAL(&manager->wakeup); #endif /* USE_TIMER_THREAD */ UNLOCK(&manager->lock); #ifdef USE_TIMER_THREAD /* * Wait for thread to exit. */ if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS) UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_thread_join() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); #endif /* USE_TIMER_THREAD */ /* * Clean up. */ #ifdef USE_TIMER_THREAD (void)isc_condition_destroy(&manager->wakeup); #endif /* USE_TIMER_THREAD */ DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); manager->common.impmagic = 0; manager->common.magic = 0; mctx = manager->mctx; isc_mem_put(mctx, manager, sizeof(*manager)); isc_mem_detach(&mctx); *managerp = NULL; #ifdef USE_SHARED_MANAGER timermgr = NULL; #endif }
ATF_TC_BODY(benchmark, tc) { isc_result_t result; char namestr[sizeof("name18446744073709551616.example.org.")]; unsigned int r; dns_rbt_t *mytree; dns_rbtnode_t *node; unsigned int i; unsigned int maxvalue = 1000000; isc_time_t ts1, ts2; double t; unsigned int nthreads; isc_thread_t threads[32]; UNUSED(tc); srandom(time(NULL)); debug_mem_record = ISC_FALSE; result = dns_test_begin(NULL, ISC_TRUE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); fnames = (dns_fixedname_t *) malloc(4000000 * sizeof(dns_fixedname_t)); names = (dns_name_t **) malloc(4000000 * sizeof(dns_name_t *)); values = (int *) malloc(4000000 * sizeof(int)); for (i = 0; i < 4000000; i++) { r = ((unsigned long) random()) % maxvalue; snprintf(namestr, sizeof(namestr), "name%u.example.org.", r); build_name_from_str(namestr, &fnames[i]); names[i] = dns_fixedname_name(&fnames[i]); values[i] = r; } /* Create a tree. */ mytree = NULL; result = dns_rbt_create(mctx, NULL, NULL, &mytree); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); /* Insert test data into the tree. */ for (i = 0; i < maxvalue; i++) { snprintf(namestr, sizeof(namestr), "name%u.example.org.", i); node = NULL; result = insert_helper(mytree, namestr, &node); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); node->data = (void *) (intptr_t) i; } result = isc_time_now(&ts1); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); nthreads = ISC_MIN(isc_os_ncpus(), 32); nthreads = ISC_MAX(nthreads, 1); for (i = 0; i < nthreads; i++) { result = isc_thread_create(find_thread, mytree, &threads[i]); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); } for (i = 0; i < nthreads; i++) { result = isc_thread_join(threads[i], NULL); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); } result = isc_time_now(&ts2); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); t = isc_time_microdiff(&ts2, &ts1); printf("%u findnode calls, %f seconds, %f calls/second\n", nthreads * 8 * 4000000, t / 1000000.0, (nthreads * 8 * 4000000) / (t / 1000000.0)); free(values); free(names); free(fnames); dns_rbt_destroy(&mytree); dns_test_end(); }
void isc_timermgr_destroy(isc_timermgr_t **managerp) { isc_timermgr_t *manager; isc_mem_t *mctx; /* * Destroy a timer manager. */ REQUIRE(managerp != NULL); manager = *managerp; REQUIRE(VALID_MANAGER(manager)); LOCK(&manager->lock); #ifndef ISC_PLATFORM_USETHREADS if (manager->refs > 1) { manager->refs--; UNLOCK(&manager->lock); *managerp = NULL; return; } isc__timermgr_dispatch(); #endif /* ISC_PLATFORM_USETHREADS */ REQUIRE(EMPTY(manager->timers)); manager->done = ISC_TRUE; #ifdef ISC_PLATFORM_USETHREADS XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SIGNALDESTROY, "signal (destroy)")); SIGNAL(&manager->wakeup); #endif /* ISC_PLATFORM_USETHREADS */ UNLOCK(&manager->lock); #ifdef ISC_PLATFORM_USETHREADS /* * Wait for thread to exit. */ if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS) UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_thread_join() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); #endif /* ISC_PLATFORM_USETHREADS */ /* * Clean up. */ #ifdef ISC_PLATFORM_USETHREADS (void)isc_condition_destroy(&manager->wakeup); #endif /* ISC_PLATFORM_USETHREADS */ DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); manager->magic = 0; mctx = manager->mctx; isc_mem_put(mctx, manager, sizeof(*manager)); isc_mem_detach(&mctx); *managerp = NULL; }