From 795d18bc275317b872813417aa9d450bbb8dee83 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 25 Nov 2013 14:11:34 +0100 Subject: [PATCH] Bug #431: Fix signal handler The signal handler implementation called async-signal-unsafe functions. Corresponding notifications are handled by the interface "sigwaitinfo" in a separate thread now. Signed-off-by: Markus Elfring --- src/rrd_daemon.c | 164 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 120 insertions(+), 44 deletions(-) diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c index abcffdd8..44869c27 100644 --- a/src/rrd_daemon.c +++ b/src/rrd_daemon.c @@ -248,6 +248,7 @@ static cache_item_t *cache_queue_head = NULL; static cache_item_t *cache_queue_tail = NULL; static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; +static sigset_t signal_set; static int config_write_interval = 300; static int config_write_jitter = 0; static int config_flush_interval = 3600; @@ -296,67 +297,143 @@ static int handle_request_help (HANDLER_PROTO); static void sig_common (const char *sig) /* {{{ */ { RRDD_LOG(LOG_NOTICE, "caught SIG%s", sig); + + int status = pthread_mutex_lock(&cache_lock); + + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "Lock failed.", status); + abort(); + } + if (state == RUNNING) { state = FLUSHING; } pthread_cond_broadcast(&flush_cond); + status = pthread_mutex_unlock(&cache_lock); + + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "Unlock failed.", status); + abort(); + } + pthread_cond_broadcast(&queue_cond); } /* }}} void sig_common */ -static void sig_int_handler (int UNUSED(s)) /* {{{ */ +static void* signal_receiver (void UNUSED(*args)) { - sig_common("INT"); -} /* }}} void sig_int_handler */ + siginfo_t signal_info; + int status; -static void sig_term_handler (int UNUSED(s)) /* {{{ */ -{ - sig_common("TERM"); -} /* }}} void sig_term_handler */ + while (1) + { + status = sigwaitinfo(&signal_set, &signal_info); -static void sig_usr1_handler (int UNUSED(s)) /* {{{ */ -{ - config_flush_at_shutdown = 1; - sig_common("USR1"); -} /* }}} void sig_usr1_handler */ + switch(status) + { + case -1: + RRDD_LOG(LOG_ERR, "%s: %s\nerrno: %d", __func__, "Signal wait failed.", errno); + abort(); -static void sig_usr2_handler (int UNUSED(s)) /* {{{ */ -{ - config_flush_at_shutdown = 0; - sig_common("USR2"); -} /* }}} void sig_usr2_handler */ + case SIGINT: + sig_common("INT"); + break; + + case SIGTERM: + sig_common("TERM"); + break; + + case SIGUSR1: + status = pthread_mutex_lock(&cache_lock); + + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "Lock failed.", status); + abort(); + } + + config_flush_at_shutdown = 1; + status = pthread_mutex_unlock(&cache_lock); -static void install_signal_handlers(void) /* {{{ */ + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "Unlock failed.", status); + abort(); + } + + sig_common("USR1"); + break; + + case SIGUSR2: + status = pthread_mutex_lock(&cache_lock); + + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "Lock failed.", status); + abort(); + } + + config_flush_at_shutdown = 0; + status = pthread_mutex_unlock(&cache_lock); + + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "Unlock failed.", status); + abort(); + } + + sig_common("USR2"); + break; + + default: + RRDD_LOG(LOG_NOTICE, + "%s: Signal %d was received from process %u.\n", + __func__, + status, + signal_info.si_pid); + } + } + + return NULL; +} + +static void install_signal_receiver(void) { - /* These structures are static, because `sigaction' behaves weird if the are - * overwritten.. */ - static struct sigaction sa_int; - static struct sigaction sa_term; - static struct sigaction sa_pipe; - static struct sigaction sa_usr1; - static struct sigaction sa_usr2; + pthread_t receiver; + int status = sigfillset(&signal_set); - /* Install signal handlers */ - memset (&sa_int, 0, sizeof (sa_int)); - sa_int.sa_handler = sig_int_handler; - sigaction (SIGINT, &sa_int, NULL); + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nerrno: %d", "Signal set could not be initialised.", errno); + abort(); + } + + /* Block all signals in the initial thread. */ + status = pthread_sigmask(SIG_SETMASK, &signal_set, NULL); - memset (&sa_term, 0, sizeof (sa_term)); - sa_term.sa_handler = sig_term_handler; - sigaction (SIGTERM, &sa_term, NULL); + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "Signal mask could not be set.", status); + abort(); + } - memset (&sa_pipe, 0, sizeof (sa_pipe)); - sa_pipe.sa_handler = SIG_IGN; - sigaction (SIGPIPE, &sa_pipe, NULL); + status = pthread_create(&receiver, NULL, signal_receiver, NULL); - memset (&sa_pipe, 0, sizeof (sa_usr1)); - sa_usr1.sa_handler = sig_usr1_handler; - sigaction (SIGUSR1, &sa_usr1, NULL); + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "A thread could not be created.", status); + abort(); + } - memset (&sa_usr2, 0, sizeof (sa_usr2)); - sa_usr2.sa_handler = sig_usr2_handler; - sigaction (SIGUSR2, &sa_usr2, NULL); + status = pthread_detach(receiver); -} /* }}} void install_signal_handlers */ + if (status) + { + RRDD_LOG(LOG_ERR, "%s\nstatus: %d", "A thread could not be detached.", status); + abort(); + } +} static int open_pidfile(char *action, int oflag) /* {{{ */ { @@ -3279,10 +3356,9 @@ static int daemonize (void) /* {{{ */ goto error; } - install_signal_handlers(); - openlog ("rrdcached", LOG_PID, LOG_DAEMON); RRDD_LOG(LOG_INFO, "starting up"); + install_signal_receiver(); cache_tree = g_tree_new_full ((GCompareDataFunc) strcmp, NULL, NULL, (GDestroyNotify) free_cache_item); -- 2.47.2