@cryptotaxi247 / netdata-1 / commits / 8368ef121

rewrote the signal handler; added SIGBUS handler; fixes #2727

Costa Tsaousis (ktsaou) committed Sep 16, 2017 at 00:50 UTC 8368ef121ae9c683a76f2451059b338ebf8dd685
9 files changed +200 -132
CMakeLists.txt
+6 -1
@@ -152,7 +152,12 @@ set(NETDATA_SOURCE_FILES
152 src/web_client.h
153 src/web_server.c
154 src/web_server.h
155 - src/locks.h src/statsd.c src/statsd.h src/statistical.c src/statistical.h src/backend_prometheus.c src/backend_prometheus.h)
155 + src/locks.h
156 + src/statsd.c src/statsd.h
157 + src/statistical.c src/statistical.h
158 + src/backend_prometheus.c src/backend_prometheus.h
159 + src/signals.c src/signals.h
160 + )
161
162 set(APPS_PLUGIN_SOURCE_FILES
163 src/appconfig.c
src/Makefile.am
+2
@@ -121,6 +121,8 @@ netdata_SOURCES = \
121 rrdset.c \
122 rrdsetvar.c \
123 rrdvar.c \
124 + signals.c \
125 + signals.h \
126 simple_pattern.c \
127 simple_pattern.h \
128 socket.c \
src/common.h
+1
@@ -216,6 +216,7 @@
216 #include "web_client.h"
217 #include "web_server.h"
218 #include "registry.h"
219 +#include "signals.h"
220 #include "daemon.h"
221 #include "main.h"
222 #include "unit_test.h"
src/daemon.c
-39
@@ -3,45 +3,6 @@
3
4 char pidfile[FILENAME_MAX + 1] = "";
5
6 -void sig_handler_exit(int signo)
7 -{
8 - if(signo) {
9 - error_log_limit_unlimited();
10 - error("Received signal %d. Exiting...", signo);
11 - netdata_exit = 1;
12 - }
13 -}
14 -
15 -void sig_handler_logrotate(int signo)
16 -{
17 - if(signo) {
18 - error_log_limit_unlimited();
19 - info("Received signal %d to re-open the log files", signo);
20 - reopen_all_log_files();
21 - error_log_limit_reset();
22 - }
23 -}
24 -
25 -void sig_handler_save(int signo)
26 -{
27 - if(signo) {
28 - error_log_limit_unlimited();
29 - info("Received signal %d to save the database...", signo);
30 - rrdhost_save_all();
31 - error_log_limit_reset();
32 - }
33 -}
34 -
35 -void sig_handler_reload_health(int signo)
36 -{
37 - if(signo) {
38 - error_log_limit_unlimited();
39 - info("Received signal %d to reload health configuration...", signo);
40 - health_reload();
41 - error_log_limit_reset();
42 - }
43 -}
44 -
6 static void chown_open_file(int fd, uid_t uid, gid_t gid) {
7 if(fd == -1) return;
8
src/daemon.h
-5
@@ -1,11 +1,6 @@
1 #ifndef NETDATA_DAEMON_H
2 #define NETDATA_DAEMON_H 1
3
4 -extern void sig_handler_exit(int signo);
5 -extern void sig_handler_save(int signo);
6 -extern void sig_handler_logrotate(int signo);
7 -extern void sig_handler_reload_health(int signo);
8 -
4 extern int become_user(const char *username, int pid_fd);
5
6 extern int become_daemon(int dont_fork, const char *user);
src/main.c
+9 -55
@@ -855,47 +855,10 @@ int main(int argc, char **argv) {
855
856 // block signals while initializing threads.
857 // this causes the threads to block signals.
858 - sigset_t sigset;
859 - sigfillset(&sigset);
860 - if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1)
861 - error("Could not block signals for threads");
858 + signals_block();
859
863 - // Catch signals which we want to use
864 - struct sigaction sa;
865 - sa.sa_flags = 0;
866 -
867 - // ingore all signals while we run in a signal handler
868 - sigfillset(&sa.sa_mask);
869 -
870 - // INFO: If we add signals here we have to unblock them
871 - // at popen.c when running a external plugin.
872 -
873 - // Ignore SIGPIPE completely.
874 - sa.sa_handler = SIG_IGN;
875 - if(sigaction(SIGPIPE, &sa, NULL) == -1)
876 - error("Failed to change signal handler for SIGPIPE");
877 -
878 - sa.sa_handler = sig_handler_exit;
879 - if(sigaction(SIGINT, &sa, NULL) == -1)
880 - error("Failed to change signal handler for SIGINT");
881 -
882 - sa.sa_handler = sig_handler_exit;
883 - if(sigaction(SIGTERM, &sa, NULL) == -1)
884 - error("Failed to change signal handler for SIGTERM");
885 -
886 - sa.sa_handler = sig_handler_logrotate;
887 - if(sigaction(SIGHUP, &sa, NULL) == -1)
888 - error("Failed to change signal handler for SIGHUP");
889 -
890 - // save database on SIGUSR1
891 - sa.sa_handler = sig_handler_save;
892 - if(sigaction(SIGUSR1, &sa, NULL) == -1)
893 - error("Failed to change signal handler for SIGUSR1");
894 -
895 - // reload health configuration on SIGUSR2
896 - sa.sa_handler = sig_handler_reload_health;
897 - if(sigaction(SIGUSR2, &sa, NULL) == -1)
898 - error("Failed to change signal handler for SIGUSR2");
860 + // setup the signals we want to use
861 + signals_init();
862
863
864 // --------------------------------------------------------------------
@@ -1026,21 +989,12 @@ int main(int argc, char **argv) {
989
990
991 // ------------------------------------------------------------------------
1029 - // block signals while initializing threads.
1030 - sigset_t sigset;
1031 - sigfillset(&sigset);
992 + // unblock signals
993
1033 - if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
1034 - error("Could not unblock signals for threads");
1035 - }
994 + signals_unblock();
995
1037 - // Handle flags set in the signal handler.
1038 - while(1) {
1039 - pause();
1040 - if(netdata_exit) {
1041 - debug(D_EXIT, "Exit main loop of netdata.");
1042 - netdata_cleanup_and_exit(0);
1043 - exit(0);
1044 - }
1045 - }
996 + // ------------------------------------------------------------------------
997 + // Handle signals
998 +
999 + signals_handle();
1000 }
src/popen.c
+2 -32
@@ -105,38 +105,8 @@ FILE *mypopen(const char *command, pid_t *pidptr)
105 #endif
106
107 // reset all signals
108 - {
109 - sigset_t sigset;
110 - sigfillset(&sigset);
111 -
112 - if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1)
113 - error("pre-execution of command '%s' on pid %d: could not unblock signals for threads.", command, getpid());
114 -
115 - // We only need to reset ignored signals.
116 - // Signals with signal handlers are reset by default.
117 - struct sigaction sa;
118 - sigemptyset(&sa.sa_mask);
119 - sa.sa_handler = SIG_DFL;
120 - sa.sa_flags = 0;
121 -
122 - if(sigaction(SIGINT, &sa, NULL) == -1)
123 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGINT.", command, getpid());
124 -
125 - if(sigaction(SIGTERM, &sa, NULL) == -1)
126 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGTERM.", command, getpid());
127 -
128 - if(sigaction(SIGPIPE, &sa, NULL) == -1)
129 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGPIPE.", command, getpid());
130 -
131 - if(sigaction(SIGHUP, &sa, NULL) == -1)
132 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGHUP.", command, getpid());
133 -
134 - if(sigaction(SIGUSR1, &sa, NULL) == -1)
135 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR1.", command, getpid());
136 -
137 - if(sigaction(SIGUSR2, &sa, NULL) == -1)
138 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR2.", command, getpid());
139 - }
108 + signals_unblock();
109 + signals_reset();
110
111 debug(D_CHILDS, "executing command: '%s' on pid %d.", command, getpid());
112 execl("/bin/sh", "sh", "-c", command, NULL);
src/signals.c new
+165
@@ -0,0 +1,165 @@
1 +#include "common.h"
2 +
3 +typedef enum signal_action {
4 + NETDATA_SIGNAL_END_OF_LIST,
5 + NETDATA_SIGNAL_IGNORE,
6 + NETDATA_SIGNAL_EXIT_CLEANLY,
7 + NETDATA_SIGNAL_SAVE_DATABASE,
8 + NETDATA_SIGNAL_LOG_ROTATE,
9 + NETDATA_SIGNAL_RELOAD_HEALTH,
10 + NETDATA_SIGNAL_FATAL,
11 +} SIGNAL_ACTION;
12 +
13 +static struct {
14 + int signo; // the signal
15 + const char *name; // the name of the signal
16 + size_t count; // the number of signals received
17 + SIGNAL_ACTION action; // the action to take
18 +} signals_waiting[] = {
19 + { SIGPIPE, "SIGPIPE", 0, NETDATA_SIGNAL_IGNORE },
20 + { SIGINT , "SIGINT", 0, NETDATA_SIGNAL_EXIT_CLEANLY },
21 + { SIGQUIT, "SIGQUIT", 0, NETDATA_SIGNAL_EXIT_CLEANLY },
22 + { SIGTERM, "SIGTERM", 0, NETDATA_SIGNAL_EXIT_CLEANLY },
23 + { SIGHUP, "SIGHUP", 0, NETDATA_SIGNAL_LOG_ROTATE },
24 + { SIGUSR1, "SIGUSR1", 0, NETDATA_SIGNAL_SAVE_DATABASE },
25 + { SIGUSR2, "SIGUSR2", 0, NETDATA_SIGNAL_RELOAD_HEALTH },
26 + { SIGBUS, "SIGBUS", 0, NETDATA_SIGNAL_FATAL },
27 +
28 + // terminator
29 + { 0, "NONE", 0, NETDATA_SIGNAL_END_OF_LIST }
30 +};
31 +
32 +static void signal_handler(int signo) {
33 + // find the entry in the list
34 + int i;
35 + for(i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST ; i++) {
36 + if(unlikely(signals_waiting[i].signo == signo)) {
37 + signals_waiting[i].count++;
38 +
39 + if(signals_waiting[i].action == NETDATA_SIGNAL_FATAL) {
40 + char buffer[200 + 1];
41 + snprintfz(buffer, 200, "\nSIGNAL HANLDER: received: %s. Oops! This is bad!\n", signals_waiting[i].name);
42 + write(STDERR_FILENO, buffer, strlen(buffer));
43 + }
44 +
45 + return;
46 + }
47 + }
48 +}
49 +
50 +void signals_block(void) {
51 + sigset_t sigset;
52 + sigfillset(&sigset);
53 +
54 + if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1)
55 + error("SIGNAL: Could not block signals for threads");
56 +}
57 +
58 +void signals_unblock(void) {
59 + sigset_t sigset;
60 + sigfillset(&sigset);
61 +
62 + if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
63 + error("SIGNAL: Could not unblock signals for threads");
64 + }
65 +}
66 +
67 +void signals_init(void) {
68 + // Catch signals which we want to use
69 + struct sigaction sa;
70 + sa.sa_flags = 0;
71 +
72 + // ignore all signals while we run in a signal handler
73 + sigfillset(&sa.sa_mask);
74 +
75 + int i;
76 + for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) {
77 + if(signals_waiting[i].action == NETDATA_SIGNAL_IGNORE)
78 + sa.sa_handler = SIG_IGN;
79 + else
80 + sa.sa_handler = signal_handler;
81 +
82 + if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1)
83 + error("SIGNAL: Failed to change signal handler for: %s", signals_waiting[i].name);
84 + }
85 +}
86 +
87 +void signals_reset(void) {
88 + struct sigaction sa;
89 + sigemptyset(&sa.sa_mask);
90 + sa.sa_handler = SIG_DFL;
91 + sa.sa_flags = 0;
92 +
93 + int i;
94 + for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) {
95 + if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1)
96 + error("SIGNAL: Failed to reset signal handler for: %s", signals_waiting[i].name);
97 + }
98 +}
99 +
100 +void signals_handle(void) {
101 + while(1) {
102 +
103 + // pause() causes the calling process (or thread) to sleep until a signal
104 + // is delivered that either terminates the process or causes the invocation
105 + // of a signal-catching function.
106 + if(pause() == -1 && errno == EINTR) {
107 +
108 + // loop once, but keep looping while signals are coming in
109 + // this is needed because a few operations may take some time
110 + // so we need to check for new signals before pausing again
111 + int found = 1;
112 + while(found) {
113 + found = 0;
114 +
115 + // execute the actions of the signals
116 + int i;
117 + for (i = 0; signals_waiting[i].action != NETDATA_SIGNAL_END_OF_LIST; i++) {
118 + if (signals_waiting[i].count) {
119 + found = 1;
120 + signals_waiting[i].count = 0;
121 + const char *name = signals_waiting[i].name;
122 +
123 + switch (signals_waiting[i].action) {
124 + case NETDATA_SIGNAL_RELOAD_HEALTH:
125 + error_log_limit_unlimited();
126 + info("SIGNAL: Received %s. Reloading HEALTH configuration...", name);
127 + health_reload();
128 + error_log_limit_reset();
129 + break;
130 +
131 + case NETDATA_SIGNAL_SAVE_DATABASE:
132 + error_log_limit_unlimited();
133 + info("SIGNAL: Received %s. Saving databases...", name);
134 + rrdhost_save_all();
135 + info("Databases saved.");
136 + error_log_limit_reset();
137 + break;
138 +
139 + case NETDATA_SIGNAL_LOG_ROTATE:
140 + error_log_limit_unlimited();
141 + info("SIGNAL: Received %s. Reopening all log files...", name);
142 + reopen_all_log_files();
143 + error_log_limit_reset();
144 + break;
145 +
146 + case NETDATA_SIGNAL_EXIT_CLEANLY:
147 + info("SIGNAL: Received %s. Cleaning up to exit...", name);
148 + netdata_cleanup_and_exit(0);
149 + exit(0);
150 +
151 + case NETDATA_SIGNAL_FATAL:
152 + fatal("SIGNAL: Received %s. netdata now exits.", name);
153 +
154 + default:
155 + info("SIGNAL: Received %s. No signal handler configured. Ignoring it.", name);
156 + break;
157 + }
158 + }
159 + }
160 + }
161 + }
162 + else
163 + error("SIGNAL: pause() returned but it was not interrupted by a signal.");
164 + }
165 +}
src/signals.h new
+15
@@ -0,0 +1,15 @@
1 +#ifndef NETDATA_SIGNALS_H
2 +#define NETDATA_SIGNALS_H
3 +
4 +extern void sig_handler_exit(int signo);
5 +extern void sig_handler_save(int signo);
6 +extern void sig_handler_logrotate(int signo);
7 +extern void sig_handler_reload_health(int signo);
8 +
9 +extern void signals_init(void);
10 +extern void signals_block(void);
11 +extern void signals_unblock(void);
12 +extern void signals_handle(void);
13 +extern void signals_reset(void);
14 +
15 +#endif //NETDATA_SIGNALS_H