@cryptotaxi247 / netdata-1 / commits / 0c5d34d41

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;