diff options
-rwxr-xr-x | CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/common.h | 1 | ||||
-rw-r--r-- | src/daemon.c | 39 | ||||
-rw-r--r-- | src/daemon.h | 5 | ||||
-rw-r--r-- | src/main.c | 64 | ||||
-rw-r--r-- | src/popen.c | 34 | ||||
-rw-r--r-- | src/signals.c | 165 | ||||
-rw-r--r-- | src/signals.h | 15 |
9 files changed, 200 insertions, 132 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d926c189d..bc6e162b4e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,7 +152,12 @@ set(NETDATA_SOURCE_FILES src/web_client.h src/web_server.c src/web_server.h - src/locks.h src/statsd.c src/statsd.h src/statistical.c src/statistical.h src/backend_prometheus.c src/backend_prometheus.h) + src/locks.h + src/statsd.c src/statsd.h + src/statistical.c src/statistical.h + src/backend_prometheus.c src/backend_prometheus.h + src/signals.c src/signals.h + ) set(APPS_PLUGIN_SOURCE_FILES src/appconfig.c diff --git a/src/Makefile.am b/src/Makefile.am index 87a947bfa3..feddc326dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -121,6 +121,8 @@ netdata_SOURCES = \ rrdset.c \ rrdsetvar.c \ rrdvar.c \ + signals.c \ + signals.h \ simple_pattern.c \ simple_pattern.h \ socket.c \ diff --git a/src/common.h b/src/common.h index 918176b3e2..51d2bba551 100644 --- a/src/common.h +++ b/src/common.h @@ -216,6 +216,7 @@ #include "web_client.h" #include "web_server.h" #include "registry.h" +#include "signals.h" #include "daemon.h" #include "main.h" #include "unit_test.h" diff --git a/src/daemon.c b/src/daemon.c index 21d28c5702..5c5333a36e 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -3,45 +3,6 @@ char pidfile[FILENAME_MAX + 1] = ""; -void sig_handler_exit(int signo) -{ - if(signo) { - error_log_limit_unlimited(); - error("Received signal %d. Exiting...", signo); - netdata_exit = 1; - } -} - -void sig_handler_logrotate(int signo) -{ - if(signo) { - error_log_limit_unlimited(); - info("Received signal %d to re-open the log files", signo); - reopen_all_log_files(); - error_log_limit_reset(); - } -} - -void sig_handler_save(int signo) -{ - if(signo) { - error_log_limit_unlimited(); - info("Received signal %d to save the database...", signo); - rrdhost_save_all(); - error_log_limit_reset(); - } -} - -void sig_handler_reload_health(int signo) -{ - if(signo) { - error_log_limit_unlimited(); - info("Received signal %d to reload health configuration...", signo); - health_reload(); - error_log_limit_reset(); - } -} - static void chown_open_file(int fd, uid_t uid, gid_t gid) { if(fd == -1) return; diff --git a/src/daemon.h b/src/daemon.h index b193602d68..150d74e3a6 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -1,11 +1,6 @@ #ifndef NETDATA_DAEMON_H #define NETDATA_DAEMON_H 1 -extern void sig_handler_exit(int signo); -extern void sig_handler_save(int signo); -extern void sig_handler_logrotate(int signo); -extern void sig_handler_reload_health(int signo); - extern int become_user(const char *username, int pid_fd); extern int become_daemon(int dont_fork, const char *user); diff --git a/src/main.c b/src/main.c index 4300e788db..89ca828a13 100644 --- a/src/main.c +++ b/src/main.c @@ -855,47 +855,10 @@ 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"); + signals_block(); - // Catch signals which we want to use - struct sigaction sa; - sa.sa_flags = 0; - - // ingore all signals while we run in a signal handler - sigfillset(&sa.sa_mask); - - // INFO: If we add signals here we have to unblock them - // at popen.c when running a external plugin. - - // Ignore SIGPIPE completely. - sa.sa_handler = SIG_IGN; - if(sigaction(SIGPIPE, &sa, NULL) == -1) - error("Failed to change signal handler for SIGPIPE"); - - sa.sa_handler = sig_handler_exit; - if(sigaction(SIGINT, &sa, NULL) == -1) - error("Failed to change signal handler for SIGINT"); - - sa.sa_handler = sig_handler_exit; - if(sigaction(SIGTERM, &sa, NULL) == -1) - error("Failed to change signal handler for SIGTERM"); - - sa.sa_handler = sig_handler_logrotate; - if(sigaction(SIGHUP, &sa, NULL) == -1) - error("Failed to change signal handler for SIGHUP"); - - // save database on SIGUSR1 - sa.sa_handler = sig_handler_save; - if(sigaction(SIGUSR1, &sa, NULL) == -1) - error("Failed to change signal handler for SIGUSR1"); - - // reload health configuration on SIGUSR2 - sa.sa_handler = sig_handler_reload_health; - if(sigaction(SIGUSR2, &sa, NULL) == -1) - error("Failed to change signal handler for SIGUSR2"); + // setup the signals we want to use + signals_init(); // -------------------------------------------------------------------- @@ -1026,21 +989,12 @@ int main(int argc, char **argv) { // ------------------------------------------------------------------------ - // block signals while initializing threads. - sigset_t sigset; - sigfillset(&sigset); + // unblock signals - if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) { - error("Could not unblock signals for threads"); - } + signals_unblock(); - // Handle flags set in the signal handler. - while(1) { - pause(); - if(netdata_exit) { - debug(D_EXIT, "Exit main loop of netdata."); - netdata_cleanup_and_exit(0); - exit(0); - } - } + // ------------------------------------------------------------------------ + // Handle signals + + signals_handle(); } diff --git a/src/popen.c b/src/popen.c index 8448b7311d..27be617749 100644 --- a/src/popen.c +++ b/src/popen.c @@ -105,38 +105,8 @@ FILE *mypopen(const char *command, pid_t *pidptr) #endif // reset all signals - { - sigset_t sigset; - sigfillset(&sigset); - - if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) - error("pre-execution of command '%s' on pid %d: could not unblock signals for threads.", command, getpid()); - - // 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; - sa.sa_flags = 0; - - if(sigaction(SIGINT, &sa, NULL) == -1) - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGINT.", command, getpid()); - - if(sigaction(SIGTERM, &sa, NULL) == -1) - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGTERM.", command, getpid()); - - if(sigaction(SIGPIPE, &sa, NULL) == -1) - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGPIPE.", command, getpid()); - - if(sigaction(SIGHUP, &sa, NULL) == -1) - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGHUP.", command, getpid()); - - if(sigaction(SIGUSR1, &sa, NULL) == -1) - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR1.", command, getpid()); - - if(sigaction(SIGUSR2, &sa, NULL) == -1) - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR2.", command, getpid()); - } + signals_unblock(); + signals_reset(); debug(D_CHILDS, "executing command: '%s' on pid %d.", command, getpid()); execl("/bin/sh", "sh", "-c", command, NULL); diff --git a/src/signals.c b/src/signals.c new file mode 100644 index 0000000000..8bff5b9f46 --- /dev/null +++ b/src/signals.c @@ -0,0 +1,165 @@ +#include "common.h" + +typedef enum signal_action { + NETDATA_SIGNAL_END_OF_LIST, + NETDATA_SIGNAL_IGNORE, + NETDATA_SIGNAL_EXIT_CLEANLY, + NETDATA_SIGNAL_SAVE_DATABASE, + NETDATA_SIGNAL_LOG_ROTATE, + NETDATA_SIGNAL_RELOAD_HEALTH, + NETDATA_SIGNAL_FATAL, +} SIGNAL_ACTION; + +static struct { + int signo; // the signal + const char *name; // the name of the signal + size_t count; // the number of signals received + SIGNAL_ACTION action; // the action to take +} signals_waiting[] = { + { SIGPIPE, "SIGPIPE", 0, NETDATA_SIGNAL_IGNORE }, + { SIGINT , "SIGINT", 0, NETDATA_SIGNAL_EXIT_CLEANLY }, + { SIGQUIT, "SIGQUIT", 0, NETDATA_SIGNAL_EXIT_CLEANLY }, + { SIGTERM, "SIGTERM", 0, NETDATA_SIGNAL_EXIT_CLEANLY }, + { SIGHUP, "SIGHUP", 0, NETDATA_SIGNAL_LOG_ROTATE }, + { SIGUSR1, "SIGUSR1", 0, NETDATA_SIGNAL_SAVE_DATABASE }, + { SIGUSR2, "SIGUSR2", 0, NETDATA_SIGNAL_RELOAD_HEALTH }, + { SIGBUS, "SIGBUS", 0, NETDATA_SIGNAL_FATAL }, + + // terminator + { 0, "NONE", 0, NETDATA_SIGNAL_END_OF_LIST } +}; + +static void signal_handler(int signo) { + // find the entry in the list + int i; + for(i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST ; i++) { + if(unlikely(signals_waiting[i].signo == signo)) { + signals_waiting[i].count++; + + if(signals_waiting[i].action == NETDATA_SIGNAL_FATAL) { + char buffer[200 + 1]; + snprintfz(buffer, 200, "\nSIGNAL HANLDER: received: %s. Oops! This is bad!\n", signals_waiting[i].name); + write(STDERR_FILENO, buffer, strlen(buffer)); + } + + return; + } + } +} + +void signals_block(void) { + sigset_t sigset; + sigfillset(&sigset); + + if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1) + error("SIGNAL: Could not block signals for threads"); +} + +void signals_unblock(void) { + sigset_t sigset; + sigfillset(&sigset); + + if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) { + error("SIGNAL: Could not unblock signals for threads"); + } +} + +void signals_init(void) { + // Catch signals which we want to use + struct sigaction sa; + sa.sa_flags = 0; + + // ignore all signals while we run in a signal handler + sigfillset(&sa.sa_mask); + + int i; + for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) { + if(signals_waiting[i].action == NETDATA_SIGNAL_IGNORE) + sa.sa_handler = SIG_IGN; + else + sa.sa_handler = signal_handler; + + if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1) + error("SIGNAL: Failed to change signal handler for: %s", signals_waiting[i].name); + } +} + +void signals_reset(void) { + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + + int i; + for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) { + if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1) + error("SIGNAL: Failed to reset signal handler for: %s", signals_waiting[i].name); + } +} + +void signals_handle(void) { + while(1) { + + // pause() causes the calling process (or thread) to sleep until a signal + // is delivered that either terminates the process or causes the invocation + // of a signal-catching function. + if(pause() == -1 && errno == EINTR) { + + // loop once, but keep looping while signals are coming in + // this is needed because a few operations may take some time + // so we need to check for new signals before pausing again + int found = 1; + while(found) { + found = 0; + + // execute the actions of the signals + int i; + for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) { + if (signals_waiting[i].count) { + found = 1; + signals_waiting[i].count = 0; + const char *name = signals_waiting[i].name; + + switch (signals_waiting[i].action) { + case NETDATA_SIGNAL_RELOAD_HEALTH: + error_log_limit_unlimited(); + info("SIGNAL: Received %s. Reloading HEALTH configuration...", name); + health_reload(); + error_log_limit_reset(); + break; + + case NETDATA_SIGNAL_SAVE_DATABASE: + error_log_limit_unlimited(); + info("SIGNAL: Received %s. Saving databases...", name); + rrdhost_save_all(); + info("Databases saved."); + error_log_limit_reset(); + break; + + case NETDATA_SIGNAL_LOG_ROTATE: + error_log_limit_unlimited(); + info("SIGNAL: Received %s. Reopening all log files...", name); + reopen_all_log_files(); + error_log_limit_reset(); + break; + + case NETDATA_SIGNAL_EXIT_CLEANLY: + info("SIGNAL: Received %s. Cleaning up to exit...", name); + netdata_cleanup_and_exit(0); + exit(0); + + case NETDATA_SIGNAL_FATAL: + fatal("SIGNAL: Received %s. netdata now exits.", name); + + default: + info("SIGNAL: Received %s. No signal handler configured. Ignoring it.", name); + break; + } + } + } + } + } + else + error("SIGNAL: pause() returned but it was not interrupted by a signal."); + } +} diff --git a/src/signals.h b/src/signals.h new file mode 100644 index 0000000000..44b05c66c8 --- /dev/null +++ b/src/signals.h @@ -0,0 +1,15 @@ +#ifndef NETDATA_SIGNALS_H +#define NETDATA_SIGNALS_H + +extern void sig_handler_exit(int signo); +extern void sig_handler_save(int signo); +extern void sig_handler_logrotate(int signo); +extern void sig_handler_reload_health(int signo); + +extern void signals_init(void); +extern void signals_block(void); +extern void signals_unblock(void); +extern void signals_handle(void); +extern void signals_reset(void); + +#endif //NETDATA_SIGNALS_H |