]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/commitdiff
Bug #431: Fix signal handler 434/head
authorMarkus Elfring <elfring@users.sourceforge.net>
Mon, 25 Nov 2013 13:11:34 +0000 (14:11 +0100)
committerMarkus Elfring <elfring@users.sourceforge.net>
Mon, 25 Nov 2013 13:11:34 +0000 (14:11 +0100)
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 <elfring@users.sourceforge.net>
src/rrd_daemon.c

index abcffdd8a94ff545bf0b27ea16177db53810dfc8..44869c27c9c4589c8f7a9eb36f5236624407d5cf 100644 (file)
@@ -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);