/** perform extended threaded test */ static int ext_test(struct ub_ctx* ctx, int argc, char** argv) { struct ext_thr_info inf[NUMTHR]; int i; if(argc == 1 && strcmp(argv[0], "localhost") == 0) q_is_localhost = 1; printf("extended test start (%d threads)\n", NUMTHR); for(i=0; i<NUMTHR; i++) { /* 0 = this, 1 = library bg worker */ inf[i].thread_num = i+2; inf[i].ctx = ctx; inf[i].argc = argc; inf[i].argv = argv; inf[i].numq = 100; ub_thread_create(&inf[i].tid, ext_thread, &inf[i]); } /* the work happens here */ for(i=0; i<NUMTHR; i++) { ub_thread_join(inf[i].tid); } printf("extended test end\n"); ub_ctx_delete(ctx); checklock_stop(); return 0; }
/** test hash table access by multiple threads */ static void test_threaded_table(struct lruhash* table) { int numth = 10; struct test_thr t[100]; int i; for(i=1; i<numth; i++) { t[i].num = i; t[i].table = table; ub_thread_create(&t[i].id, test_thr_main, &t[i]); } for(i=1; i<numth; i++) { ub_thread_join(t[i].id); } if(0) lruhash_status(table, "hashtest", 1); }
/** stop the bg thread */ static void ub_stop_bg(struct ub_ctx* ctx) { /* stop the bg thread */ lock_basic_lock(&ctx->cfglock); if(ctx->created_bg) { uint8_t* msg; uint32_t len; uint32_t cmd = UB_LIBCMD_QUIT; lock_basic_unlock(&ctx->cfglock); lock_basic_lock(&ctx->qqpipe_lock); (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd, (uint32_t)sizeof(cmd), 0); lock_basic_unlock(&ctx->qqpipe_lock); lock_basic_lock(&ctx->rrpipe_lock); while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) { /* discard all results except a quit confirm */ if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) { free(msg); break; } free(msg); } lock_basic_unlock(&ctx->rrpipe_lock); /* if bg worker is a thread, wait for it to exit, so that all * resources are really gone. */ lock_basic_lock(&ctx->cfglock); if(ctx->dothread) { lock_basic_unlock(&ctx->cfglock); ub_thread_join(ctx->bg_tid); } else { lock_basic_unlock(&ctx->cfglock); #ifndef UB_ON_WINDOWS if(waitpid(ctx->bg_pid, NULL, 0) == -1) { if(verbosity > 2) log_err("waitpid: %s", strerror(errno)); } #endif } } else { lock_basic_unlock(&ctx->cfglock); } }
/** * Stop the other threads. * @param daemon: the daemon with other threads. */ static void daemon_stop_others(struct daemon* daemon) { int i; log_assert(daemon); verbose(VERB_ALGO, "stop threads"); /* skip i=0, is this thread */ /* use i=0 buffer for sending cmds; because we are #0 */ for(i=1; i<daemon->num; i++) { worker_send_cmd(daemon->workers[i], worker_cmd_quit); } /* wait for them to quit */ for(i=1; i<daemon->num; i++) { /* join it to make sure its dead */ verbose(VERB_ALGO, "join %d", i); ub_thread_join(daemon->workers[i]->thr_id); verbose(VERB_ALGO, "join success %d", i); } }
void ub_ctx_delete(struct ub_ctx* ctx) { struct alloc_cache* a, *na; if(!ctx) return; /* stop the bg thread */ lock_basic_lock(&ctx->cfglock); if(ctx->created_bg) { uint8_t* msg; uint32_t len; uint32_t cmd = UB_LIBCMD_QUIT; lock_basic_unlock(&ctx->cfglock); lock_basic_lock(&ctx->qqpipe_lock); (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd, (uint32_t)sizeof(cmd), 0); lock_basic_unlock(&ctx->qqpipe_lock); lock_basic_lock(&ctx->rrpipe_lock); while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) { /* discard all results except a quit confirm */ if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) { free(msg); break; } free(msg); } lock_basic_unlock(&ctx->rrpipe_lock); /* if bg worker is a thread, wait for it to exit, so that all * resources are really gone. */ lock_basic_lock(&ctx->cfglock); if(ctx->dothread) { lock_basic_unlock(&ctx->cfglock); ub_thread_join(ctx->bg_tid); } else { lock_basic_unlock(&ctx->cfglock); } } else { lock_basic_unlock(&ctx->cfglock); } modstack_desetup(&ctx->mods, ctx->env); a = ctx->alloc_list; while(a) { na = a->super; a->super = &ctx->superalloc; alloc_clear(a); free(a); a = na; } local_zones_delete(ctx->local_zones); lock_basic_destroy(&ctx->qqpipe_lock); lock_basic_destroy(&ctx->rrpipe_lock); lock_basic_destroy(&ctx->cfglock); tube_delete(ctx->qq_pipe); tube_delete(ctx->rr_pipe); if(ctx->env) { slabhash_delete(ctx->env->msg_cache); rrset_cache_delete(ctx->env->rrset_cache); infra_delete(ctx->env->infra_cache); config_delete(ctx->env->cfg); free(ctx->env); } ub_randfree(ctx->seed_rnd); alloc_clear(&ctx->superalloc); traverse_postorder(&ctx->queries, delq, NULL); free(ctx); #ifdef USE_WINSOCK WSACleanup(); #endif }