From: Wouter Wijngaards Date: Tue, 27 Feb 2007 10:33:04 +0000 (+0000) Subject: Signal solution X-Git-Tag: release-0.1~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0e3a0235404fdf62504bdacc9e82e50f3feeafb9;p=thirdparty%2Funbound.git Signal solution git-svn-id: file:///svn/unbound/trunk@152 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/daemon.c b/daemon/daemon.c index bb766c4ce..5c88a9f0b 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -48,11 +48,61 @@ #include "util/log.h" #include "util/config_file.h" #include "services/listen_dnsport.h" - -/* @@@ TODO remove */ -#include "pthread.h" #include +/** How many quit requests happened. */ +static int sig_record_quit = 0; +/** How many reload requests happened. */ +static int sig_record_reload = 0; + +/** used when no other sighandling happens, so we don't die + * when multiple signals in quick succession are sent to us. */ +static RETSIGTYPE record_sigh(int sig) +{ + switch(sig) + { + case SIGTERM: + case SIGQUIT: + case SIGINT: + sig_record_quit++; + break; + case SIGHUP: + sig_record_reload++; + break; + default: + log_err("ignoring signal %d", sig); + } +} + +/** + * Signal handling during the time when netevent is disabled. + * Stores signals to replay later. + */ +static void +signal_handling_record() +{ + if( signal(SIGTERM, record_sigh) == SIG_ERR || + signal(SIGQUIT, record_sigh) == SIG_ERR || + signal(SIGINT, record_sigh) == SIG_ERR || + signal(SIGHUP, record_sigh) == SIG_ERR) + log_err("install sighandler: %s", strerror(errno)); +} + +/** + * Replay old signals. + * @param wrk: worker that handles signals. + */ +static void +signal_handling_playback(struct worker* wrk) +{ + if(sig_record_quit) + worker_sighandler(SIGTERM, wrk); + if(sig_record_reload) + worker_sighandler(SIGHUP, wrk); + sig_record_quit = 0; + sig_record_reload = 0; +} + struct daemon* daemon_init() { @@ -60,6 +110,7 @@ daemon_init() sizeof(struct daemon)); if(!daemon) return NULL; + signal_handling_record(); lock_basic_init(&daemon->lock); daemon->need_to_exit = 0; return daemon; @@ -212,7 +263,7 @@ daemon_fork(struct daemon* daemon) if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports, BUFSZ, 1)) fatal_exit("Could not initialize main thread"); - /* see if other threads have started correctly? */ + signal_handling_playback(daemon->workers[0]); /* Start resolver service on main thread. */ log_info("start of service (%s).", PACKAGE_STRING); @@ -231,6 +282,9 @@ daemon_cleanup(struct daemon* daemon) { int i; log_assert(daemon); + /* before stopping main worker, handle signals ourselves, so we + don't die on multiple reload signals for example. */ + signal_handling_record(); for(i=0; inum; i++) worker_delete(daemon->workers[i]); free(daemon->workers); diff --git a/daemon/daemon.h b/daemon/daemon.h index 0fb185d70..46edecaa4 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -101,7 +101,8 @@ void daemon_fork(struct daemon* daemon); void daemon_cleanup(struct daemon* daemon); /** - * Delete worker. + * Delete workers, close listening ports. + * @param daemon: the daemon. */ void daemon_delete(struct daemon* daemon); diff --git a/daemon/worker.c b/daemon/worker.c index e6da5a483..c2f5eccde 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -376,15 +376,18 @@ worker_delete(struct worker* worker) { if(!worker) return; - close(worker->cmd_send_fd); + if(worker->cmd_send_fd != -1) + close(worker->cmd_send_fd); worker->cmd_send_fd = -1; - close(worker->cmd_recv_fd); + if(worker->cmd_recv_fd != -1) + close(worker->cmd_recv_fd); worker->cmd_recv_fd = -1; listen_delete(worker->front); outside_network_delete(worker->back); comm_signal_delete(worker->comsig); comm_point_delete(worker->cmd_com); comm_base_delete(worker->base); + ub_randfree(worker->rndstate); free(worker->rndstate); free(worker); } diff --git a/daemon/worker.h b/daemon/worker.h index ec01f5fd8..72576a5f8 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -157,4 +157,11 @@ int worker_set_fwd(struct worker* worker, const char* ip, int port); void worker_send_cmd(struct worker* worker, ldns_buffer* buffer, enum worker_commands cmd); +/** + * Worker signal handler function. User argument is the worker itself. + * @param sig: signal number. + * @param arg: the worker (main worker) that handles signals. + */ +void worker_sighandler(int sig, void* arg); + #endif /* DAEMON_WORKER_H */ diff --git a/doc/Changelog b/doc/Changelog index 36f7c0fdc..85ca5e211 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -3,6 +3,8 @@ - forking is used if no threading is available. Tested, it works, since pipes work across processes as well. Thread_join is replaced with waitpid. + - During reloads the daemon will temporarily handle signals, + so that they do not result in problems. 26 February 2007: Wouter - ub_random code used to select ID and port. diff --git a/util/netevent.c b/util/netevent.c index a51d59217..28b6eecd0 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -507,7 +507,8 @@ static void comm_point_local_handle_callback(int fd, short event, void* arg) if(event&EV_READ) { if(!comm_point_tcp_handle_read(fd, c, 1)) { - log_err("error in localhdl"); + (void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED, + NULL); } return; } diff --git a/util/random.c b/util/random.c index 3e19da876..976b6a0e2 100644 --- a/util/random.c +++ b/util/random.c @@ -357,5 +357,7 @@ ub_random (struct ub_randstate* s) void ub_randfree(struct ub_randstate* state) { + if(!state) + return; free(state->state); }