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