int ub_wait(struct ub_ctx* ctx) { int err; ub_callback_t cb; void* cbarg; struct ub_result* res; int r; uint8_t* msg; uint32_t len; /* this is basically the same loop as _process(), but with changes. * holds the rrpipe lock and waits with tube_wait */ while(1) { lock_basic_lock(&ctx->rrpipe_lock); lock_basic_lock(&ctx->cfglock); if(ctx->num_async == 0) { lock_basic_unlock(&ctx->cfglock); lock_basic_unlock(&ctx->rrpipe_lock); break; } lock_basic_unlock(&ctx->cfglock); /* keep rrpipe locked, while * o waiting for pipe readable * o parsing message * o possibly decrementing num_async * do callback without lock */ r = tube_wait(ctx->rr_pipe); if(r) { r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); if(r == 0) { lock_basic_unlock(&ctx->rrpipe_lock); return UB_PIPE; } if(r == -1) { lock_basic_unlock(&ctx->rrpipe_lock); continue; } r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res); lock_basic_unlock(&ctx->rrpipe_lock); free(msg); if(r == 0) return UB_PIPE; if(r == 2) (*cb)(cbarg, err, res); } else { lock_basic_unlock(&ctx->rrpipe_lock); } } return UB_NOERROR; }
void tube_handle_signal(int ATTR_UNUSED(fd), short ATTR_UNUSED(events), void* arg) { struct tube* tube = (struct tube*)arg; uint8_t* buf; uint32_t len = 0; verbose(VERB_ALGO, "tube handle_signal"); while(tube_poll(tube)) { if(tube_read_msg(tube, &buf, &len, 1)) { fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb)); (*tube->listen_cb)(tube, buf, len, NETEVENT_NOERROR, tube->listen_arg); } } }
/** 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); } }
int ub_process(struct ub_ctx* ctx) { int r; uint8_t* msg; uint32_t len; while(1) { msg = NULL; lock_basic_lock(&ctx->rrpipe_lock); r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); lock_basic_unlock(&ctx->rrpipe_lock); if(r == 0) return UB_PIPE; else if(r == -1) break; if(!process_answer(ctx, msg, len)) { free(msg); return UB_PIPE; } free(msg); } return UB_NOERROR; }
void server_stats_obtain(struct worker* worker, struct worker* who, struct stats_info* s, int reset) { uint8_t *reply = NULL; uint32_t len = 0; if(worker == who) { /* just fill it in */ server_stats_compile(worker, s, reset); return; } /* communicate over tube */ verbose(VERB_ALGO, "write stats cmd"); if(reset) worker_send_cmd(who, worker_cmd_stats); else worker_send_cmd(who, worker_cmd_stats_noreset); verbose(VERB_ALGO, "wait for stats reply"); if(!tube_read_msg(worker->cmd, &reply, &len, 0)) fatal_exit("failed to read stats over cmd channel"); if(len != (uint32_t)sizeof(*s)) fatal_exit("stats on cmd channel wrong length %d %d", (int)len, (int)sizeof(*s)); memcpy(s, reply, (size_t)len); free(reply); }
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 }