added signal handling without races
authorChristian Pointner <equinox@realraum.at>
Sun, 3 May 2009 13:41:04 +0000 (13:41 +0000)
committerChristian Pointner <equinox@realraum.at>
Sun, 3 May 2009 13:41:04 +0000 (13:41 +0000)
door_daemon/door_daemon.c
door_daemon/sig_handler.c
door_daemon/sig_handler.h

index 6e4db12..cf12668 100644 (file)
@@ -238,7 +238,12 @@ int main_loop(int door_fd, int cmd_listen_fd)
   int max_fd = door_fd > cmd_listen_fd ? door_fd : cmd_listen_fd;
   cmd_t* cmd_q = NULL;
 
-  signal_init();
+  int sig_fd = signal_init();
+  if(sig_fd < 0)
+    return -1;
+  FD_SET(sig_fd, &readfds);
+  max_fd = (max_fd < sig_fd) ? sig_fd : max_fd;
+
   int return_value = 0;
   while(!return_value) {
     memcpy(&tmpfds, &readfds, sizeof(tmpfds));
@@ -249,13 +254,14 @@ int main_loop(int door_fd, int cmd_listen_fd)
       return_value = -1;
       break;
     }
-    if(!ret)
+    if(!ret || ret == -1)
       continue;
 
-    if(signal_exit) {
+    if(signal_handle()) {
       return_value = 1;
       break;
     }
+    FD_CLR(sig_fd, &tmpfds);
 
     if(FD_ISSET(door_fd, &tmpfds)) {
       return_value = process_door(door_fd, &cmd_q);
@@ -298,6 +304,7 @@ int main_loop(int door_fd, int cmd_listen_fd)
   }
 
   cmd_clear(&cmd_q);
+  signal_stop();
   return return_value;
 }
 
index 6fd4b85..7a1ad74 100644 (file)
 
 #include "log.h"
 #include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <errno.h>
+
 #include "sig_handler.h"
 
-volatile sig_atomic_t signal_exit = 0;
+#include <stdio.h>
+
+
+static int sig_pipe_fds[2];
+
 
-void signal_init()
+static void sig_handler(int sig)
 {
-  signal(SIGINT, handle_signal);
-  signal(SIGQUIT, handle_signal);
-  signal(SIGTERM, handle_signal);
-  signal(SIGHUP, handle_signal);
-  signal(SIGUSR1, handle_signal);
-  signal(SIGUSR2, handle_signal);
+  sigset_t set;
+  int ret = read(sig_pipe_fds[0], &set, sizeof(sigset_t));
+  if(ret != sizeof(sigset_t))
+    sigemptyset(&set);
+
+  sigaddset(&set, sig);
+  ret = write(sig_pipe_fds[1], &set, sizeof(sigset_t));
+}
+
+
+int signal_init()
+{
+  if(pipe(sig_pipe_fds)) {
+    log_printf(ERROR, "signal handling init failed (pipe error: %s)", strerror(errno));
+    return -1;
+  }
+
+  int i;
+  for(i=0; i<2; ++i) {
+    int fd_flags = fcntl(sig_pipe_fds[i], F_GETFL);
+    if(fd_flags == -1) {
+      log_printf(ERROR, "signal handling init failed (pipe fd[%d] read flags error: %s)", i, strerror(errno));
+      return -1;
+    }
+    if(fcntl(sig_pipe_fds[i], F_SETFL, fd_flags | O_NONBLOCK) == -1){
+      log_printf(ERROR, "signal handling init failed (pipe fd[%d] write flags error: %s)", i, strerror(errno));
+      return -1;
+    }
+  }
+
+  struct sigaction act;
+  act.sa_handler = sig_handler;
+  sigfillset(&act.sa_mask);
+  act.sa_flags = 0;
+
+  if((sigaction(SIGINT, &act, NULL) < 0) ||
+     (sigaction(SIGQUIT, &act, NULL) < 0) ||
+     (sigaction(SIGTERM, &act, NULL) < 0) ||
+     (sigaction(SIGHUP, &act, NULL) < 0) ||
+     (sigaction(SIGUSR1, &act, NULL) < 0) ||
+     (sigaction(SIGUSR2, &act, NULL) < 0)) {
+
+    log_printf(ERROR, "signal handling init failed (sigaction error: %s)", strerror(errno));
+    close(sig_pipe_fds[0]);
+    close(sig_pipe_fds[1]);
+  }
+
+  return sig_pipe_fds[0];
 }
 
-void handle_signal(int sig)
+int signal_handle()
 {
-  switch(sig) {
-  case SIGINT: log_printf(NOTICE, "SIG-Int caught, exitting"); signal_exit = 1; break;
-  case SIGQUIT: log_printf(NOTICE, "SIG-Quit caught, exitting"); signal_exit = 1; break;
-  case SIGTERM: log_printf(NOTICE, "SIG-Term caught, exitting"); signal_exit = 1; break;
-  case SIGHUP: log_printf(NOTICE, "SIG-Hup caught"); break;
-  case SIGUSR1: log_printf(NOTICE, "SIG-Usr1 caught"); break;
-  case SIGUSR2: log_printf(NOTICE, "SIG-Usr2 caught"); break;
-  default: log_printf(NOTICE, "Signal %d caught, ignoring", sig); break;
+  sigset_t set, oldset, tmpset;
+
+  sigemptyset(&tmpset);
+  sigaddset(&tmpset, SIGINT);
+  sigaddset(&tmpset, SIGQUIT);
+  sigaddset(&tmpset, SIGTERM);
+  sigaddset(&tmpset, SIGHUP);
+  sigaddset(&tmpset, SIGUSR1);
+  sigaddset(&tmpset, SIGUSR2);
+  sigprocmask(SIG_BLOCK, &tmpset, &oldset);
+
+  int ret = read(sig_pipe_fds[0], &set, sizeof(sigset_t));
+  if(ret != sizeof(sigset_t))
+    sigemptyset(&set);
+
+  int return_value = 0;
+  int sig;
+  for(sig=1; sig < _NSIG; ++sig) {
+    if(sigismember(&set, sig)) {
+      switch(sig) {
+      case SIGINT: log_printf(NOTICE, "SIG-Int caught, exitting"); return_value = 1; break;
+      case SIGQUIT: log_printf(NOTICE, "SIG-Quit caught, exitting"); return_value = 1; break;
+      case SIGTERM: log_printf(NOTICE, "SIG-Term caught, exitting"); return_value = 1; break;
+      case SIGHUP: log_printf(NOTICE, "SIG-Hup caught"); break;
+      case SIGUSR1: log_printf(NOTICE, "SIG-Usr1 caught"); break;
+      case SIGUSR2: log_printf(NOTICE, "SIG-Usr2 caught"); break;
+      default: log_printf(WARNING, "unknown signal %d caught, ignoring", sig); break;
+      }
+      sigdelset(&set, sig);
+    }
   }
+
+  sigprocmask(SIG_SETMASK, &oldset, NULL);
+  return return_value;
+}
+
+void signal_stop()
+{
+  struct sigaction act;
+  act.sa_handler = SIG_DFL;
+  sigemptyset(&act.sa_mask);
+  act.sa_flags = 0;
+
+  sigaction(SIGINT, &act, NULL);
+  sigaction(SIGQUIT, &act, NULL);
+  sigaction(SIGTERM, &act, NULL);
+  sigaction(SIGHUP, &act, NULL);
+  sigaction(SIGUSR1, &act, NULL);
+  sigaction(SIGUSR2, &act, NULL);
+
+  close(sig_pipe_fds[0]);
+  close(sig_pipe_fds[1]);
 }
index a7779be..9fd6386 100644 (file)
@@ -37,9 +37,8 @@
 
 #include <signal.h>
 
-extern volatile sig_atomic_t signal_exit;
-
-void signal_init();
-void handle_signal(int sig);
+int signal_init();
+int signal_handle();
+void signal_stop();
 
 #endif