/** the background thread func */ static void* libworker_dobg(void* arg) { /* setup */ uint32_t m; struct libworker* w = (struct libworker*)arg; struct ub_ctx* ctx; if(!w) { log_err("libunbound bg worker init failed, nomem"); return NULL; } ctx = w->ctx; log_thread_set(&w->thread_num); #ifdef THREADS_DISABLED /* we are forked */ w->is_bg_thread = 0; /* close non-used parts of the pipes */ tube_close_write(ctx->qq_pipe); tube_close_read(ctx->rr_pipe); #endif if(!tube_setup_bg_listen(ctx->qq_pipe, w->base, libworker_handle_control_cmd, w)) { log_err("libunbound bg worker init failed, no bglisten"); return NULL; } if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) { log_err("libunbound bg worker init failed, no bgwrite"); return NULL; } /* do the work */ comm_base_dispatch(w->base); /* cleanup */ m = UB_LIBCMD_QUIT; w->want_quit = 1; tube_remove_bg_listen(w->ctx->qq_pipe); tube_remove_bg_write(w->ctx->rr_pipe); libworker_delete(w); (void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m, (uint32_t)sizeof(m), 0); #ifdef THREADS_DISABLED /* close pipes from forked process before exit */ tube_close_read(ctx->qq_pipe); tube_close_write(ctx->rr_pipe); #endif return NULL; }
int libworker_bg(struct ub_ctx* ctx) { struct libworker* w; /* fork or threadcreate */ lock_basic_lock(&ctx->cfglock); if(ctx->dothread) { lock_basic_unlock(&ctx->cfglock); w = libworker_setup(ctx, 1, NULL); if(!w) return UB_NOMEM; w->is_bg_thread = 1; #ifdef ENABLE_LOCK_CHECKS w->thread_num = 1; /* for nicer DEBUG checklocks */ #endif ub_thread_create(&ctx->bg_tid, libworker_dobg, w); } else { lock_basic_unlock(&ctx->cfglock); #ifndef HAVE_FORK /* no fork on windows */ return UB_FORKFAIL; #else /* HAVE_FORK */ switch((ctx->bg_pid=fork())) { case 0: w = libworker_setup(ctx, 1, NULL); if(!w) fatal_exit("out of memory"); /* close non-used parts of the pipes */ tube_close_write(ctx->qq_pipe); tube_close_read(ctx->rr_pipe); (void)libworker_dobg(w); exit(0); break; case -1: return UB_FORKFAIL; default: /* close non-used parts, so that the worker * bgprocess gets 'pipe closed' when the * main process exits */ tube_close_read(ctx->qq_pipe); tube_close_write(ctx->rr_pipe); break; } #endif /* HAVE_FORK */ } return UB_NOERROR; }
void tube_delete(struct tube* tube) { if(!tube) return; tube_remove_bg_listen(tube); tube_remove_bg_write(tube); /* close fds after deleting commpoints, to be sure. * Also epoll does not like closing fd before event_del */ tube_close_read(tube); tube_close_write(tube); free(tube); }
void tube_delete(struct tube* tube) { if(!tube) return; tube_remove_bg_listen(tube); tube_remove_bg_write(tube); tube_close_read(tube); tube_close_write(tube); if(!WSACloseEvent(tube->event)) log_err("WSACloseEvent: %s", wsa_strerror(WSAGetLastError())); lock_basic_destroy(&tube->res_lock); verbose(VERB_ALGO, "tube deleted"); free(tube); }
/** * Close all pipes except for the numbered thread. * @param daemon: daemon to close pipes in. * @param thr: thread number 0..num-1 of thread to skip. */ static void close_other_pipes(struct daemon* daemon, int thr) { int i; for(i=0; i<daemon->num; i++) if(i!=thr) { if(i==0) { /* only close read part, need to write stats */ tube_close_read(daemon->workers[i]->cmd); } else { /* complete close channel to others */ tube_delete(daemon->workers[i]->cmd); daemon->workers[i]->cmd = NULL; } } }
/** * Fork and init the other threads. Main thread returns for special handling. * @param daemon: the daemon with other threads to fork. */ static void daemon_start_others(struct daemon* daemon) { int i; log_assert(daemon); verbose(VERB_ALGO, "start threads"); /* skip i=0, is this thread */ for(i=1; i<daemon->num; i++) { ub_thread_create(&daemon->workers[i]->thr_id, thread_start, daemon->workers[i]); #ifdef THREADS_DISABLED /* close pipe end of child */ tube_close_read(daemon->workers[i]->cmd); #endif /* no threads */ } }