]> arthur.barton.de Git - netdata.git/commitdiff
Make signal handling save.
authorSimon Nagl <simonnagl@aim.com>
Tue, 10 May 2016 17:59:30 +0000 (19:59 +0200)
committerSimon Nagl <simonnagl@aim.com>
Wed, 11 May 2016 16:07:21 +0000 (18:07 +0200)
Only call reentrant functions in signal handlers.
Block signals except on the main thread.
Quit savely only on functions specified for this purpose.
Optimize main loop.
Restore signals for external plugins.
Ignore SIGPIPE

src/daemon.c
src/main.c
src/main.h
src/popen.c

index 6b671bee1fa7a6f4b1ea7bed26576202e1ebe0b9..2b972c5ae507aa3fbb81acb3118986443ca48203 100644 (file)
@@ -30,49 +30,7 @@ int pidfd = -1;
 
 void sig_handler(int signo)
 {
-       switch(signo) {
-               case SIGILL:
-               case SIGABRT:
-               case SIGFPE:
-               case SIGSEGV:
-               case SIGBUS:
-               case SIGSYS:
-               case SIGTRAP:
-               case SIGXCPU:
-               case SIGXFSZ:
-                       infoerr("Death signaled exit (signal %d).", signo);
-                       signal(signo, SIG_DFL);
-                       break;
-
-               case SIGKILL:
-               case SIGTERM:
-               case SIGQUIT:
-               case SIGINT:
-               case SIGHUP:
-               case SIGUSR1:
-               case SIGUSR2:
-                       infoerr("Signaled exit (signal %d).", signo);
-                       signal(SIGPIPE, SIG_IGN);
-                       signal(SIGTERM, SIG_IGN);
-                       signal(SIGQUIT, SIG_IGN);
-                       signal(SIGHUP,  SIG_IGN);
-                       signal(SIGINT,  SIG_IGN);
-                       signal(SIGCHLD, SIG_IGN);
-                       netdata_cleanup_and_exit(1);
-                       break;
-
-               case SIGPIPE:
-                       infoerr("Signaled PIPE (signal %d).", signo);
-                       // this is received when web clients send a reset
-                       // no need to log it.
-                       // infoerr("Ignoring signal %d.", signo);
-                       break;
-
-               default:
-                       info("Signal %d received. Falling back to default action for it.", signo);
-                       signal(signo, SIG_DFL);
-                       break;
-       }
+       netdata_exit = 1;
 }
 
 int become_user(const char *username)
@@ -247,10 +205,6 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
                }
        }
 
-       signal(SIGCHLD,  SIG_IGN);
-       signal(SIGHUP,   SIG_IGN);
-       signal(SIGWINCH, SIG_IGN);
-
        // fork() again
        if(!dont_fork) {
                int i = fork();
index 760ab641d47bc17ae5d99131ad06697ec992b3f9..d323b7559e764a8a9d146cc1d95bfc139a77fbea 100644 (file)
@@ -39,7 +39,7 @@
 
 extern void *cgroups_main(void *ptr);
 
-int netdata_exit = 0;
+volatile sig_atomic_t netdata_exit = 0;
 
 void netdata_cleanup_and_exit(int ret)
 {
@@ -122,19 +122,7 @@ int killpid(pid_t pid, int sig)
        }
        else {
                errno = 0;
-
-               void (*old)(int);
-               old = signal(sig, SIG_IGN);
-               if(old == SIG_ERR) {
-                       error("Cannot overwrite signal handler for signal %d", sig);
-                       old = sig_handler;
-               }
-
                ret = kill(pid, sig);
-
-               if(signal(sig, old) == SIG_ERR)
-                       error("Cannot restore signal handler for signal %d", sig);
-
                if(ret == -1) {
                        switch(errno) {
                                case ESRCH:
@@ -410,6 +398,41 @@ int main(int argc, char **argv)
 
                // --------------------------------------------------------------------
 
+               // block signals while initializing threads.
+               // this causes the threads to block signals.
+               sigset_t sigset;
+               sigfillset(&sigset);
+
+               if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1) {
+                       error("Could not block signals for threads");
+               }
+
+               // Catch signals which we want to use to quit savely
+               struct sigaction sa;
+               sigemptyset(&sa.sa_mask);
+               sigaddset(&sa.sa_mask, SIGHUP);
+               sigaddset(&sa.sa_mask, SIGINT);
+               sigaddset(&sa.sa_mask, SIGTERM);
+               sa.sa_handler = sig_handler;
+               if(sigaction(SIGHUP, &sa, NULL) == -1) {
+                       error("Failed to change signal handler for SIGHUP");
+               }
+               if(sigaction(SIGINT, &sa, NULL) == -1) {
+                       error("Failed to change signal handler for SIGINT");
+               }
+               if(sigaction(SIGTERM, &sa, NULL) == -1) {
+                       error("Failed to change signal handler for SIGTERM");
+               }
+               // Ignore SIGPIPE completely.
+               // INFO: If we add signals here we have to unblock them
+               // at popen.c when running a external plugin.
+               sa.sa_handler = SIG_IGN;
+               if(sigaction(SIGPIPE, &sa, NULL) == -1) {
+                       error("Failed to change signal handler for SIGTERM");
+               }
+
+               // --------------------------------------------------------------------
+
                i = pthread_attr_init(&attr);
                if(i != 0)
                        fatal("pthread_attr_init() failed with code %d.", i);
@@ -490,24 +513,6 @@ int main(int argc, char **argv)
        info("NetData started on pid %d", getpid());
 
 
-       // catch all signals
-       for (i = 1 ; i < 65 ;i++) {
-               switch(i) {
-                       case SIGKILL: // not catchable
-                       case SIGSTOP: // not catchable
-                               break;
-
-                       case SIGSEGV:
-                       case SIGFPE:
-                       case SIGCHLD:
-                               signal(i, SIG_DFL);
-                               break;
-
-                       default:
-                               signal(i,  sig_handler);
-                               break;
-               }
-       }
 
        // ------------------------------------------------------------------------
        // get default pthread stack size
@@ -542,18 +547,22 @@ int main(int argc, char **argv)
                else info("Not starting thread %s.", st->name);
        }
 
-       // for future use - the main thread
-       while(1) {
-               if(netdata_exit != 0) {
-                       netdata_exit++;
+       // ------------------------------------------------------------------------
+       // block signals while initializing threads.
+       sigset_t sigset;
+       sigfillset(&sigset);
 
-                       if(netdata_exit > 5) {
-                               netdata_cleanup_and_exit(0);
-                               exit(0);
-                       }
-               }
-               sleep(2);
+       if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
+               error("Could not unblock signals for threads");
        }
 
-       exit(0);
+       // Handle flags set in the signal handler.
+       while(1) {
+               pause();
+               if(netdata_exit) {
+                       info("Exit main loop of netdata.");
+                       netdata_cleanup_and_exit(0);
+                       exit(0);
+               }
+       }
 }
index 6a90efd9d42f6f9e47915af081963b4da4fa4a2b..d9edda58e6c71574c3fe78dc05ccfbf486431f31 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef NETDATA_MAIN_H
 #define NETDATA_MAIN_H 1
 
-extern int netdata_exit;
+#include <signal.h>
+
+extern volatile sig_atomic_t netdata_exit;
 
 extern void kill_childs(void);
 extern int killpid(pid_t pid, int signal);
index 882a4cc5a6ba88537327cd4f53d8b0413d71ca43..d4e86607bc9130f1523d5fa35d902cb67f9cfbd6 100644 (file)
@@ -114,10 +114,26 @@ FILE *mypopen(const char *command, pid_t *pidptr)
 #endif
 
        // reset all signals
-       for (i = 1 ; i < 65 ;i++) if(i != SIGSEGV) signal(i, SIG_DFL);
+       {
+               sigset_t sigset;
+               sigfillset(&sigset);
+
+               if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
+                       error("Could not block signals for threads");
+               }
+               // We only need to reset ignored signals.
+               // Signals with signal handlers are reset by default.
+               struct sigaction sa;
+               sigemptyset(&sa.sa_mask);
+               sa.sa_handler = SIG_DFL;
+               if(sigaction(SIGPIPE, &sa, NULL) == -1) {
+                       error("Failed to change signal handler for SIGTERM");
+               }
+       }
+
 
        info("executing command: '%s' on pid %d.", command, getpid());
-       execl("/bin/sh", "sh", "-c", command, NULL);
+       execl("/bin/sh", "sh", "-c", command, NULL);
        exit(1);
 }