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)
}
}
- signal(SIGCHLD, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- signal(SIGWINCH, SIG_IGN);
-
// fork() again
if(!dont_fork) {
int i = fork();
extern void *cgroups_main(void *ptr);
-int netdata_exit = 0;
+volatile sig_atomic_t netdata_exit = 0;
void netdata_cleanup_and_exit(int ret)
{
}
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:
// --------------------------------------------------------------------
+ // 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);
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
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);
+ }
+ }
}
#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);
}