]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #400 from simonnagl/feature/polling
authorCosta Tsaousis <costa@tsaousis.gr>
Thu, 12 May 2016 00:48:47 +0000 (03:48 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Thu, 12 May 2016 00:48:47 +0000 (03:48 +0300)
Make signal handling safe.

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);
 }