summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xCMakeLists.txt7
-rw-r--r--src/Makefile.am2
-rw-r--r--src/common.h1
-rw-r--r--src/daemon.c39
-rw-r--r--src/daemon.h5
-rw-r--r--src/main.c64
-rw-r--r--src/popen.c34
-rw-r--r--src/signals.c165
-rw-r--r--src/signals.h15
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