block all signals before spawning any threads (#19770)
* block all signals before spawning any threads * fix header * fix header again * uniform signals masking * fix log
Costa Tsaousis committed
Mar 4, 2025 at 21:50 UTC
0c5d34d41aefa8ced60c5d57faef68eec90d543a
13 files changed
+81
-57
CMakeLists.txt
+4
-2
@@ -1066,6 +1066,8 @@ set(LIBNETDATA_FILES
1066
src/libnetdata/os/file_lock.h
1067
src/libnetdata/os/mmap_limit.c
1068
src/libnetdata/os/mmap_limit.h
1069
+ src/libnetdata/signals/signals.c
1070
+ src/libnetdata/signals/signals.h
1071
)
1072
1073
list(APPEND LIBNETDATA_FILES ${INICFG_FILES})
@@ -1171,8 +1173,8 @@ set(DAEMON_FILES
1173
src/daemon/environment.c
1174
src/daemon/win_system-info.c
1175
src/daemon/win_system-info.h
1174
- src/daemon/signals.c
1175
- src/daemon/signals.h
1176
+ src/daemon/signal-handler.c
1177
+ src/daemon/signal-handler.h
1178
src/daemon/service.c
1179
src/daemon/daemon-shutdown-watcher.c
1180
src/daemon/daemon-shutdown-watcher.h
src/daemon/common.h
+1
-1
@@ -70,7 +70,7 @@ extern "C" {
70
#include "daemon.h"
71
#include "main.h"
72
#include "static_threads.h"
73
-#include "signals.h"
73
+#include "signal-handler.h"
74
#include "commands.h"
75
#include "pipename.h"
76
#include "analytics.h"
src/daemon/daemon-shutdown.c
+1
-1
@@ -106,7 +106,7 @@ static void rrdeng_flush_everything_and_wait(bool wait_flush, bool wait_collecto
106
if(!pgc_hot_and_dirty_entries(main_cache))
107
return;
108
109
- nd_log(NDLS_DAEMON, NDLP_INFO, "Flushing DBENGINE dirty pages...");
109
+ nd_log(NDLS_DAEMON, NDLP_INFO, "Flushing DBENGINE hot & dirty pages...");
110
for (size_t tier = 0; tier < nd_profile.storage_tiers; tier++)
111
rrdeng_quiesce(multidb_ctx[tier]);
112
src/daemon/daemon-status-file.c
+8
-7
@@ -819,7 +819,7 @@ void daemon_status_file_check_crash(void) {
819
bool post_crash_report = false;
820
bool disable_crash_report = false;
821
bool dump_json = true;
822
- const char *msg, *cause;
822
+ const char *msg = "", *cause = "";
823
switch(last_session_status.status) {
824
default:
825
case DAEMON_STATUS_NONE:
@@ -1017,12 +1017,13 @@ void daemon_status_file_check_crash(void) {
1017
1018
daemon_status_file_startup_step("startup(post status file)");
1019
1020
- struct post_status_file_thread_data *d = calloc(1, sizeof(*d));
1021
- d->cause = cause;
1022
- d->msg = msg;
1023
- d->status = &last_session_status;
1024
- d->priority = pri.post;
1025
- post_status_file(d);
1020
+ struct post_status_file_thread_data d = {
1021
+ .cause = cause,
1022
+ .msg = msg,
1023
+ .status = &last_session_status,
1024
+ .priority = pri.post,
1025
+ };
1026
+ post_status_file(&d);
1027
1028
// MacOS crashes when starting under launchctl, when we create a thread to post the status file,
1029
// so we post the status file synchronously, with a timeout of 10 seconds.
src/daemon/signal-handler.c
renamed
+1
-20
@@ -80,25 +80,6 @@ static void signal_handler(int signo) {
80
__atomic_sub_fetch(&recurse, 1, __ATOMIC_RELAXED);
81
}
82
83
-
84
-// Mask all signals, to ensure they will only be unmasked at the threads that can handle them.
85
-// This means that all third party libraries (including libuv) cannot use signals anymore.
86
-// The signals they are interested must be unblocked at their corresponding event loops.
87
-static void posix_signals_default_mask(void) {
88
- sigset_t sigset;
89
- sigfillset(&sigset);
90
-
91
- // Don't mask fatal signals - we want these to be handled in any thread
92
- sigdelset(&sigset, SIGBUS);
93
- sigdelset(&sigset, SIGSEGV);
94
- sigdelset(&sigset, SIGFPE);
95
- sigdelset(&sigset, SIGILL);
96
- sigdelset(&sigset, SIGABRT);
97
-
98
- if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) != 0)
99
- netdata_log_error("SIGNAL: cannot apply the default mask for signals");
100
-}
101
-
83
// Unmask all signals the netdata main signal handler uses.
84
// All other signals remain masked.
85
static void posix_unmask_my_signals(void) {
@@ -113,7 +94,7 @@ static void posix_unmask_my_signals(void) {
94
}
95
96
void nd_initialize_signals(void) {
116
- posix_signals_default_mask();
97
+ signals_block_all_except_deadly();
98
99
// Catch signals which we want to use
100
struct sigaction sa;
src/daemon/signal-handler.h
renamed
+3
-3
@@ -1,9 +1,9 @@
1
// SPDX-License-Identifier: GPL-3.0-or-later
2
3
-#ifndef NETDATA_SIGNALS_H
4
-#define NETDATA_SIGNALS_H 1
3
+#ifndef NETDATA_SIGNAL_HANDLER_H
4
+#define NETDATA_SIGNAL_HANDLER_H 1
5
6
void nd_initialize_signals(void);
7
void nd_process_signals(void) NORETURN;
8
9
-#endif //NETDATA_SIGNALS_H
9
+#endif //NETDATA_SIGNAL_HANDLER_H
src/database/engine/rrdengineapi.c
+1
-1
@@ -901,7 +901,7 @@ ALWAYS_INLINE_HOT STORAGE_POINT rrdeng_load_metric_next(struct storage_engine_qu
901
pgdc_get_next_point(&handle->pgdc, handle->position, &sp);
902
903
prepare_for_next_iteration:
904
- internal_fatal(sp.end_time_s < seqh->start_time_s, "DBENGINE: this point is too old for this query");
904
+ // internal_fatal(sp.end_time_s < seqh->start_time_s, "DBENGINE: this point is too old for this query");
905
internal_fatal(sp.end_time_s < handle->now_s, "DBENGINE: this point is too old for this point in time");
906
907
handle->now_s += handle->dt_s;
src/libnetdata/libnetdata.h
+1
@@ -8,6 +8,7 @@ extern "C" {
8
# endif
9
10
#include "common.h"
11
+#include "signals/signals.h"
12
#include "memory/alignment.h"
13
#include "memory/nd-mallocz.h"
14
#include "memory/nd-mmap.h"
src/libnetdata/log/nd_log.c
+1
-1
@@ -518,7 +518,7 @@ void netdata_logger_fatal(const char *file, const char *function, const unsigned
518
snprintfz(action_result, 60, "%s:%s:%s", program_name, tag_to_send, function);
519
520
#ifdef NETDATA_INTERNAL_CHECKS
521
- // abort();
521
+ abort();
522
#endif
523
524
if(nd_log.fatal_final_cb)
src/libnetdata/signals/signals.c
new
+42
@@ -0,0 +1,42 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "../libnetdata.h"
4
+
5
+void signals_block_all(void) {
6
+ sigset_t sigset;
7
+ sigfillset(&sigset);
8
+
9
+ if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) != 0)
10
+ nd_log(NDLS_DAEMON, NDLP_ERR,
11
+ "SIGNALS: cannot apply the default mask for signals");
12
+}
13
+
14
+void signals_unblock_one(int signo) {
15
+ sigset_t sigset;
16
+ sigemptyset(&sigset); // Initialize the signal set to empty
17
+ sigaddset(&sigset, signo); // Add our signal to the set
18
+
19
+ if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) != 0)
20
+ nd_log(NDLS_COLLECTORS, NDLP_ERR,
21
+ "SIGNALS: cannot unmask signal %d", signo);
22
+}
23
+
24
+void signals_unblock(int signals[], size_t count) {
25
+ sigset_t sigset;
26
+ sigemptyset(&sigset); // Initialize the signal set to empty
27
+
28
+ // Add each signal from the array to the signal set
29
+ for (size_t i = 0; i < count; i++)
30
+ sigaddset(&sigset, signals[i]);
31
+
32
+ // Unblock all signals in the set
33
+ if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) != 0)
34
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "SIGNALS: cannot unmask signals");
35
+}
36
+
37
+void signals_block_all_except_deadly(void) {
38
+ signals_block_all();
39
+
40
+ int deadly_signals[] = {SIGBUS, SIGSEGV, SIGFPE, SIGILL, SIGABRT};
41
+ signals_unblock(deadly_signals, _countof(deadly_signals));
42
+}
src/libnetdata/signals/signals.h
new
+14
@@ -0,0 +1,14 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_SIGNALS_H
4
+#define NETDATA_SIGNALS_H
5
+
6
+#include "../common.h"
7
+
8
+void signals_block_all_except_deadly(void);
9
+void signals_block_all(void);
10
+
11
+void signals_unblock_one(int signo);
12
+void signals_unblock(int signals[], size_t count);
13
+
14
+#endif //NETDATA_SIGNALS_H
src/libnetdata/spawn_server/spawn_server_libuv.c
+1
-10
@@ -98,15 +98,6 @@ int uv_errno_to_errno(int uv_err) {
98
}
99
}
100
101
-static void posix_unmask_sigchld_on_thread(void) {
102
- sigset_t sigset;
103
- sigemptyset(&sigset); // Initialize the signal set to empty
104
- sigaddset(&sigset, SIGCHLD); // Add SIGCHLD to the set
105
-
106
- if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) != 0)
107
- netdata_log_error("SPAWN SERVER: cannot unmask SIGCHLD");
108
-}
109
-
101
static void server_thread(void *arg) {
102
SPAWN_SERVER *server = (SPAWN_SERVER *)arg;
103
nd_log(NDLS_COLLECTORS, NDLP_ERR,
@@ -114,7 +105,7 @@ static void server_thread(void *arg) {
105
106
// this thread needs to process SIGCHLD (by libuv)
107
// otherwise the on_exit() callback is never run
117
- posix_unmask_sigchld_on_thread();
108
+ signals_unblock_one(SIGCHLD);
109
110
// run the event loop
111
uv_run(server->loop, UV_RUN_DEFAULT);
src/libnetdata/spawn_server/spawn_server_nofork.c
+3
-11
@@ -830,21 +830,13 @@ static void spawn_server_process_sigchld(void) {
830
}
831
}
832
833
-static void posix_unmask_sigchld_on_thread(void) {
834
- sigset_t sigset;
835
- sigemptyset(&sigset); // Initialize the signal set to empty
836
- sigaddset(&sigset, SIGCHLD); // Add SIGCHLD to the set
837
-
838
- if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) != 0)
839
- nd_log(NDLS_COLLECTORS, NDLP_ERR,
840
- "SPAWN SERVER: cannot unmask SIGCHLD");
841
-}
842
-
833
static int spawn_server_event_loop(SPAWN_SERVER *server) {
834
int pipe_fd = server->pipe[1];
835
close(server->pipe[0]); server->pipe[0] = -1;
836
847
- posix_unmask_sigchld_on_thread();
837
+ signals_block_all();
838
+ int wanted_signals[] = {SIGTERM, SIGCHLD};
839
+ signals_unblock(wanted_signals, _countof(wanted_signals));
840
841
// Set up the signal handler for SIGCHLD and SIGTERM
842
struct sigaction sa;