@cryptotaxi247 / netdata-1 / commits / 788ae9a44

spawn server improvements (#18115)

* spawn server improvements * fixed message

Costa Tsaousis committed Jul 11, 2024 at 16:52 UTC 788ae9a44d059d2ed66239d248bd791a9a453a0d
8 files changed +162 -135
src/daemon/main.c
+5 -17
@@ -324,6 +324,8 @@ static bool service_wait_exit(SERVICE_TYPE service, usec_t timeout_ut) {
324 void web_client_cache_destroy(void);
325
326 void netdata_cleanup_and_exit(int ret, const char *action, const char *action_result, const char *action_data) {
327 + netdata_exit = 1;
328 +
329 watcher_shutdown_begin();
330
331 nd_log_limits_unlimited();
@@ -344,6 +346,9 @@ void netdata_cleanup_and_exit(int ret, const char *action, const char *action_re
346 (void) rename(agent_crash_file, agent_incomplete_shutdown_file);
347 watcher_step_complete(WATCHER_STEP_ID_CREATE_SHUTDOWN_FILE);
348
349 + netdata_main_spawn_server_cleanup();
350 + watcher_step_complete(WATCHER_STEP_ID_DESTROY_MAIN_SPAWN_SERVER);
351 +
352 #ifdef ENABLE_DBENGINE
353 if(dbengine_enabled) {
354 for (size_t tier = 0; tier < storage_tiers; tier++)
@@ -486,9 +491,6 @@ void netdata_cleanup_and_exit(int ret, const char *action, const char *action_re
491 #endif
492 watcher_step_complete(WATCHER_STEP_ID_FREE_OPENSSL_STRUCTURES);
493
489 - netdata_main_spawn_server_cleanup();
490 - watcher_step_complete(WATCHER_STEP_ID_DESTROY_MAIN_SPAWN_SERVER);
491 -
494 (void) unlink(agent_incomplete_shutdown_file);
495 watcher_step_complete(WATCHER_STEP_ID_REMOVE_INCOMPLETE_SHUTDOWN_FILE);
496
@@ -667,8 +669,6 @@ void cancel_main_threads() {
669 }
670 }
671
670 - netdata_exit = 1;
671 -
672 while(found && max > 0) {
673 max -= step;
674 netdata_log_info("Waiting %d threads to finish...", found);
@@ -2179,18 +2179,6 @@ int netdata_main(int argc, char **argv) {
2179 delta_startup_time("initialize registry");
2180 registry_init();
2181
2182 - // fork the spawn server
2183 - delta_startup_time("fork the spawn server");
2184 -
2185 - /*
2186 - * Libuv uv_spawn() uses SIGCHLD internally:
2187 - * https://github.com/libuv/libuv/blob/cc51217a317e96510fbb284721d5e6bc2af31e33/src/unix/process.c#L485
2188 - * and inadvertently replaces the netdata signal handler which was setup during initialization.
2189 - * Thusly, we must explicitly restore the signal handler for SIGCHLD.
2190 - * Warning: extreme care is needed when mixing and matching POSIX and libuv.
2191 - */
2192 - signals_restore_SIGCHLD();
2193 -
2182 // ------------------------------------------------------------------------
2183 // initialize rrd, registry, health, rrdpush, etc.
2184
src/daemon/signals.c
+6 -60
@@ -2,6 +2,12 @@
2
3 #include "common.h"
4
5 +/*
6 + * IMPORTANT: Libuv uv_spawn() uses SIGCHLD internally:
7 + * https://github.com/libuv/libuv/blob/cc51217a317e96510fbb284721d5e6bc2af31e33/src/unix/process.c#L485
8 + * Extreme care is needed when mixing and matching POSIX and libuv.
9 + */
10 +
11 typedef enum signal_action {
12 NETDATA_SIGNAL_END_OF_LIST,
13 NETDATA_SIGNAL_IGNORE,
@@ -9,7 +15,6 @@ typedef enum signal_action {
15 NETDATA_SIGNAL_REOPEN_LOGS,
16 NETDATA_SIGNAL_RELOAD_HEALTH,
17 NETDATA_SIGNAL_FATAL,
12 - NETDATA_SIGNAL_CHILD,
18 } SIGNAL_ACTION;
19
20 static struct {
@@ -25,7 +30,6 @@ static struct {
30 { SIGHUP, "SIGHUP", 0, NETDATA_SIGNAL_REOPEN_LOGS },
31 { SIGUSR2, "SIGUSR2", 0, NETDATA_SIGNAL_RELOAD_HEALTH },
32 { SIGBUS, "SIGBUS", 0, NETDATA_SIGNAL_FATAL },
28 - { SIGCHLD, "SIGCHLD", 0, NETDATA_SIGNAL_CHILD },
33
34 // terminator
35 { 0, "NONE", 0, NETDATA_SIGNAL_END_OF_LIST }
@@ -93,18 +97,6 @@ void signals_init(void) {
97 }
98 }
99
96 -void signals_restore_SIGCHLD(void)
97 -{
98 - struct sigaction sa;
99 -
100 - sa.sa_flags = 0;
101 - sigfillset(&sa.sa_mask);
102 - sa.sa_handler = signal_handler;
103 -
104 - if(sigaction(SIGCHLD, &sa, NULL) == -1)
105 - netdata_log_error("SIGNAL: Failed to change signal handler for: SIGCHLD");
106 -}
107 -
100 void signals_reset(void) {
101 struct sigaction sa;
102 sigemptyset(&sa.sa_mask);
@@ -118,48 +110,6 @@ void signals_reset(void) {
110 }
111 }
112
121 -static void sigchild_handle() {
122 - int status;
123 - pid_t pid;
124 -
125 - // Loop to check for exited child processes
126 - while ((pid = waitpid((pid_t)(-1), &status, WNOHANG)) != 0) {
127 - if(pid == -1)
128 - break;
129 -
130 - if(WIFEXITED(status)) {
131 - nd_log(NDLS_DAEMON, NDLP_INFO,
132 - "DAEMON: child with pid %d exited normally with exit code %d",
133 - pid, WEXITSTATUS(status));
134 - }
135 - else if(WIFSIGNALED(status)) {
136 - if(WCOREDUMP(status))
137 - nd_log(NDLS_DAEMON, NDLP_INFO,
138 - "DAEMON: child with pid %d coredump'd due to signal %d",
139 - pid, WTERMSIG(status));
140 - else
141 - nd_log(NDLS_DAEMON, NDLP_INFO,
142 - "DAEMON: child with pid %d killed by signal %d",
143 - pid, WTERMSIG(status));
144 - }
145 - else if(WIFSTOPPED(status)) {
146 - nd_log(NDLS_DAEMON, NDLP_INFO,
147 - "DAEMON: child with pid %d stopped due to signal %d",
148 - pid, WSTOPSIG(status));
149 - }
150 - else if(WIFCONTINUED(status)) {
151 - nd_log(NDLS_DAEMON, NDLP_INFO,
152 - "DAEMON: child with pid %d continued due to signal %d",
153 - pid, SIGCONT);
154 - }
155 - else {
156 - nd_log(NDLS_COLLECTORS, NDLP_INFO,
157 - "DAEMON: child with pid %d reports unhandled status",
158 - pid);
159 - }
160 - }
161 -}
162 -
113 void signals_handle(void) {
114 while(1) {
115
@@ -211,10 +161,6 @@ void signals_handle(void) {
161 fatal("SIGNAL: Received %s. netdata now exits.", name);
162 break;
163
214 - case NETDATA_SIGNAL_CHILD:
215 - sigchild_handle();
216 - break;
217 -
164 default:
165 netdata_log_info("SIGNAL: Received %s. No signal handler configured. Ignoring it.", name);
166 break;
src/daemon/signals.h
-1
@@ -6,7 +6,6 @@
6 void signals_init(void);
7 void signals_block(void);
8 void signals_unblock(void);
9 -void signals_restore_SIGCHLD(void);
9 void signals_reset(void);
10 void signals_handle(void) NORETURN;
11
src/daemon/watcher.c
+3 -2
@@ -65,6 +65,7 @@ void *watcher_main(void *arg)
65 usec_t shutdown_start_time = now_monotonic_usec();
66
67 watcher_wait_for_step(WATCHER_STEP_ID_CREATE_SHUTDOWN_FILE);
68 + watcher_wait_for_step(WATCHER_STEP_ID_DESTROY_MAIN_SPAWN_SERVER);
69 watcher_wait_for_step(WATCHER_STEP_ID_DBENGINE_EXIT_MODE);
70 watcher_wait_for_step(WATCHER_STEP_ID_CLOSE_WEBRTC_CONNECTIONS);
71 watcher_wait_for_step(WATCHER_STEP_ID_DISABLE_MAINTENANCE_NEW_QUERIES_NEW_WEB_REQUESTS_NEW_STREAMING_CONNECTIONS_AND_ACLK);
@@ -105,6 +106,8 @@ void watcher_thread_start() {
106
107 watcher_steps[WATCHER_STEP_ID_CREATE_SHUTDOWN_FILE].msg =
108 "create shutdown file";
109 + watcher_steps[WATCHER_STEP_ID_DESTROY_MAIN_SPAWN_SERVER].msg =
110 + "destroy main spawn server";
111 watcher_steps[WATCHER_STEP_ID_DBENGINE_EXIT_MODE].msg =
112 "dbengine exit mode";
113 watcher_steps[WATCHER_STEP_ID_CLOSE_WEBRTC_CONNECTIONS].msg =
@@ -151,8 +154,6 @@ void watcher_thread_start() {
154 "remove pid file";
155 watcher_steps[WATCHER_STEP_ID_FREE_OPENSSL_STRUCTURES].msg =
156 "free openssl structures";
154 - watcher_steps[WATCHER_STEP_ID_DESTROY_MAIN_SPAWN_SERVER].msg =
155 - "destroy main spawn server";
157 watcher_steps[WATCHER_STEP_ID_REMOVE_INCOMPLETE_SHUTDOWN_FILE].msg =
158 "remove incomplete shutdown file";
159
src/daemon/watcher.h
+1 -1
@@ -7,6 +7,7 @@
7
8 typedef enum {
9 WATCHER_STEP_ID_CREATE_SHUTDOWN_FILE = 0,
10 + WATCHER_STEP_ID_DESTROY_MAIN_SPAWN_SERVER,
11 WATCHER_STEP_ID_DBENGINE_EXIT_MODE,
12 WATCHER_STEP_ID_CLOSE_WEBRTC_CONNECTIONS,
13 WATCHER_STEP_ID_DISABLE_MAINTENANCE_NEW_QUERIES_NEW_WEB_REQUESTS_NEW_STREAMING_CONNECTIONS_AND_ACLK,
@@ -30,7 +31,6 @@ typedef enum {
31 WATCHER_STEP_ID_CLOSE_SQL_DATABASES,
32 WATCHER_STEP_ID_REMOVE_PID_FILE,
33 WATCHER_STEP_ID_FREE_OPENSSL_STRUCTURES,
33 - WATCHER_STEP_ID_DESTROY_MAIN_SPAWN_SERVER,
34 WATCHER_STEP_ID_REMOVE_INCOMPLETE_SHUTDOWN_FILE,
35
36 // Always keep this as the last enum value
src/libnetdata/spawn_server/spawn_popen.c
+9 -5
@@ -3,14 +3,14 @@
3 #include "spawn_popen.h"
4
5 SPAWN_SERVER *netdata_main_spawn_server = NULL;
6 +static SPINLOCK netdata_main_spawn_server_spinlock = NETDATA_SPINLOCK_INITIALIZER;
7
8 bool netdata_main_spawn_server_init(const char *name, int argc, const char **argv) {
9 if(netdata_main_spawn_server == NULL) {
9 - static SPINLOCK spinlock = NETDATA_SPINLOCK_INITIALIZER;
10 - spinlock_lock(&spinlock);
10 + spinlock_lock(&netdata_main_spawn_server_spinlock);
11 if(netdata_main_spawn_server == NULL)
12 netdata_main_spawn_server = spawn_server_create(SPAWN_SERVER_OPTION_EXEC, name, NULL, argc, argv);
13 - spinlock_unlock(&spinlock);
13 + spinlock_unlock(&netdata_main_spawn_server_spinlock);
14 }
15
16 return netdata_main_spawn_server != NULL;
@@ -18,8 +18,12 @@ bool netdata_main_spawn_server_init(const char *name, int argc, const char **arg
18
19 void netdata_main_spawn_server_cleanup(void) {
20 if(netdata_main_spawn_server) {
21 - spawn_server_destroy(netdata_main_spawn_server);
22 - netdata_main_spawn_server = NULL;
21 + spinlock_lock(&netdata_main_spawn_server_spinlock);
22 + if(netdata_main_spawn_server) {
23 + spawn_server_destroy(netdata_main_spawn_server);
24 + netdata_main_spawn_server = NULL;
25 + }
26 + spinlock_unlock(&netdata_main_spawn_server_spinlock);
27 }
28 }
29
src/libnetdata/spawn_server/spawn_server.c
+137 -49
@@ -471,7 +471,7 @@ static void spawn_server_run_child(SPAWN_SERVER *server, SPAWN_REQUEST *request)
471 // Encoding and decoding of spawn server request argv type of data
472
473 // Function to encode argv or envp
474 -static void* encode_argv(const char **argv, size_t *out_size) {
474 +static void* argv_encode(const char **argv, size_t *out_size) {
475 size_t buffer_size = 1024; // Initial buffer size
476 size_t buffer_used = 0;
477 char *buffer = mallocz(buffer_size);
@@ -505,7 +505,7 @@ static void* encode_argv(const char **argv, size_t *out_size) {
505 }
506
507 // Function to decode argv or envp
508 -static const char** decode_argv(const char *buffer, size_t size) {
508 +static const char** argv_decode(const char *buffer, size_t size) {
509 size_t count = 0;
510 const char *ptr = buffer;
511 while (ptr < buffer + size) {
@@ -529,6 +529,54 @@ static const char** decode_argv(const char *buffer, size_t size) {
529 return argv;
530 }
531
532 +static BUFFER *argv_to_cmdline_buffer(const char **argv) {
533 + BUFFER *wb = buffer_create(0, NULL);
534 +
535 + for(size_t i = 0; argv[i] ;i++) {
536 + const char *s = argv[i];
537 + size_t len = strlen(s);
538 + buffer_need_bytes(wb, len * 2 + 1);
539 +
540 + bool needs_quotes = false;
541 + for(const char *c = s; !needs_quotes && *c ; c++) {
542 + switch(*c) {
543 + case ' ':
544 + case '\v':
545 + case '\t':
546 + case '\n':
547 + case '"':
548 + needs_quotes = true;
549 + break;
550 +
551 + default:
552 + break;
553 + }
554 + }
555 +
556 + if(needs_quotes && buffer_strlen(wb))
557 + buffer_strcat(wb, " \"");
558 + else
559 + buffer_putc(wb, ' ');
560 +
561 + for(const char *c = s; *c ; c++) {
562 + switch(*c) {
563 + case '"':
564 + buffer_putc(wb, '\\');
565 + // fall through
566 +
567 + default:
568 + buffer_putc(wb, *c);
569 + break;
570 + }
571 + }
572 +
573 + if(needs_quotes)
574 + buffer_strcat(wb, "\"");
575 + }
576 +
577 + return wb;
578 +}
579 +
580 // --------------------------------------------------------------------------------------------------------------------
581 // Sending and receiving requests
582
@@ -600,12 +648,12 @@ static bool spawn_server_send_request(ND_UUID *magic, SPAWN_REQUEST *request) {
648 bool ret = false;
649
650 size_t env_size = 0;
603 - void *encoded_env = encode_argv(request->environment, &env_size);
651 + void *encoded_env = argv_encode(request->environment, &env_size);
652 if (!encoded_env)
653 goto cleanup;
654
655 size_t argv_size = 0;
608 - void *encoded_argv = encode_argv(request->argv, &argv_size);
656 + void *encoded_argv = argv_encode(request->argv, &argv_size);
657 if (!encoded_argv)
658 goto cleanup;
659
@@ -684,6 +732,19 @@ cleanup:
732 return ret;
733 }
734
735 +static void request_free(SPAWN_REQUEST *rq) {
736 + if(rq->fds[0] != -1) close(rq->fds[0]);
737 + if(rq->fds[1] != -1) close(rq->fds[1]);
738 + if(rq->fds[2] != -1) close(rq->fds[2]);
739 + if(rq->fds[3] != -1) close(rq->fds[3]);
740 + if(rq->socket != -1) close(rq->socket);
741 + freez((void *)rq->argv);
742 + freez((void *)rq->environment);
743 + freez((void *)rq->data);
744 + freez((void *)rq->cmdline);
745 + freez((void *)rq);
746 +}
747 +
748 static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
749 struct msghdr msg = {0};
750 struct iovec iov[7];
@@ -695,7 +756,7 @@ static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
756 ND_UUID magic = UUID_ZERO;
757 SPAWN_INSTANCE_TYPE type;
758 char cmsgbuf[CMSG_SPACE(sizeof(int) * SPAWN_SERVER_TRANSFER_FDS)];
698 - char *envp = NULL, *argv = NULL, *data = NULL;
759 + char *envp_encoded = NULL, *argv_encoded = NULL, *data = NULL;
760 int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1, custom_fd = -1;
761
762 // First recvmsg() to read sizes and control message
@@ -791,14 +852,13 @@ static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
852 nd_log(NDLS_COLLECTORS, NDLP_ERR,
853 "SPAWN SERVER: invalid file descriptors received, stdin = %d, stdout = %d, stderr = %d",
854 stdin_fd, stdout_fd, stderr_fd);
794 - close(sock);
855 goto cleanup;
856 }
857
858 // Second recvmsg() to read buffer contents
799 - iov[0].iov_base = envp = mallocz(env_size);
859 + iov[0].iov_base = envp_encoded = mallocz(env_size);
860 iov[0].iov_len = env_size;
801 - iov[1].iov_base = argv = mallocz(argv_size);
861 + iov[1].iov_base = argv_encoded = mallocz(argv_size);
862 iov[1].iov_len = argv_size;
863 iov[2].iov_base = data = mallocz(data_size);
864 iov[2].iov_len = data_size;
@@ -811,15 +871,14 @@ static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
871 ssize_t total_bytes_received = recvmsg(sock, &msg, 0);
872 if (total_bytes_received < 0) {
873 nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: failed to recvmsg() the second part of the request.");
814 - close(sock);
874 goto cleanup;
875 }
876
877 // fprintf(stderr, "SPAWN SERVER: received request %zu (fds: %d, %d, %d, %d)\n", request_id,
878 // stdin_fd, stdout_fd, stderr_fd, custom_fd);
879
821 - SPAWN_REQUEST *request = mallocz(sizeof(*request));
822 - *request = (SPAWN_REQUEST){
880 + SPAWN_REQUEST *rq = mallocz(sizeof(*rq));
881 + *rq = (SPAWN_REQUEST){
882 .pid = 0,
883 .request_id = request_id,
884 .socket = sock,
@@ -829,50 +888,78 @@ static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
888 [2] = stderr_fd,
889 [3] = custom_fd,
890 },
832 - .environment = decode_argv(envp, env_size),
833 - .argv = decode_argv(argv, argv_size),
891 + .environment = argv_decode(envp_encoded, env_size),
892 + .argv = argv_decode(argv_encoded, argv_size),
893 .data = data,
894 .data_size = data_size,
895 .type = type
896 };
897
898 + switch(rq->type) {
899 + case SPAWN_INSTANCE_TYPE_EXEC:
900 + if(rq->argv) {
901 + CLEAN_BUFFER *wb = argv_to_cmdline_buffer(rq->argv);
902 + rq->cmdline = strdupz(buffer_tostring(wb));
903 + }
904 + break;
905 +
906 + case SPAWN_INSTANCE_TYPE_CALLBACK:
907 + rq->cmdline = strdupz("callback() function");
908 + break;
909 +
910 + default:
911 + rq->cmdline = strdupz("[unknown request type]");
912 + break;
913 + }
914 +
915 pid_t pid = fork();
916 if (pid == 0) {
917 // the child
842 - spawn_server_run_child(server, request);
918 + spawn_server_run_child(server, rq);
919 exit(63);
920 }
921 else if (pid > 0) {
922 // the parent
847 - request->environment = NULL; // will be free'd at cleanup
848 - request->argv = NULL; // will be free'd at cleanup
849 - request->data = NULL; // will be free'd at cleanup
850 - request->data_size = 0;
851 - request->pid = pid;
852 - request->fds[0] = -1;
853 - request->fds[1] = -1;
854 - request->fds[2] = -1;
855 - request->fds[3] = -1;
856 - DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(spawn_server_requests, request, prev, next);
923 + rq->pid = pid;
924 +
925 + // do not keep data we don't need at the parent
926 + freez(envp_encoded); freez((void *)rq->environment); rq->environment = NULL;
927 + freez(argv_encoded); freez((void *)rq->argv); rq->argv = NULL;
928 + freez((void *)rq->data); rq->data = NULL;
929 + rq->data_size = 0;
930 +
931 + // do not keep fds we don't need at the parent
932 + if(rq->fds[0] != -1) { close(rq->fds[0]); rq->fds[0] = -1; }
933 + if(rq->fds[1] != -1) { close(rq->fds[1]); rq->fds[1] = -1; }
934 + if(rq->fds[2] != -1) { close(rq->fds[2]); rq->fds[2] = -1; }
935 + if(rq->fds[3] != -1) { close(rq->fds[3]); rq->fds[3] = -1; }
936 +
937 + // keep it in the list
938 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(spawn_server_requests, rq, prev, next);
939
940 // do not fork this socket on other children
859 - sock_setcloexec(request->socket);
860 - }
861 - else {
862 - nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Failed to fork() child.");
863 - spawn_server_send_status_failure(stdout_fd);
864 - // the other allocations (envp, argv, data) will be free'd at cleanup
865 - freez((void *)request);
866 - close(sock);
941 + sock_setcloexec(rq->socket);
942 +
943 + // done with this
944 + return;
945 }
946
947 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Failed to fork() child.");
948 + spawn_server_send_status_failure(stdout_fd);
949 + // the other allocations (envp, argv, data) will be free'd at cleanup
950 + request_free(rq);
951 + freez(envp_encoded);
952 + freez(argv_encoded);
953 + return;
954 +
955 cleanup:
956 + close(sock);
957 if(stdin_fd != -1) close(stdin_fd);
958 if(stdout_fd != -1) close(stdout_fd);
959 if(stderr_fd != -1) close(stderr_fd);
960 if(custom_fd != -1) close(custom_fd);
874 - freez(envp);
875 - freez(argv);
961 + freez(envp_encoded);
962 + freez(argv_encoded);
963 freez(data);
964 }
965
@@ -906,6 +993,8 @@ static void spawn_server_process_sigchld(void) {
993 if(pid == -1)
994 break;
995
996 + errno_clear();
997 +
998 SPAWN_REQUEST *rq = find_request_by_pid(pid);
999 size_t request_id = rq ? rq->request_id : 0;
1000 bool send_report_remove_request = false;
@@ -913,45 +1002,44 @@ static void spawn_server_process_sigchld(void) {
1002 if(WIFEXITED(status)) {
1003 if(WEXITSTATUS(status))
1004 nd_log(NDLS_COLLECTORS, NDLP_INFO,
916 - "SPAWN SERVER: child with pid %d (request %zu) exited normally with exit code %d",
917 - pid, request_id, WEXITSTATUS(status));
1005 + "SPAWN SERVER: child with pid %d (request %zu) exited with exit code %d: %s",
1006 + pid, request_id, WEXITSTATUS(status), rq ? rq->cmdline : "[request not found]");
1007 send_report_remove_request = true;
1008 }
1009 else if(WIFSIGNALED(status)) {
1010 if(WCOREDUMP(status))
1011 nd_log(NDLS_COLLECTORS, NDLP_INFO,
923 - "SPAWN SERVER: child with pid %d (request %zu) coredump'd due to signal %d",
924 - pid, request_id, WTERMSIG(status));
1012 + "SPAWN SERVER: child with pid %d (request %zu) coredump'd due to signal %d: %s",
1013 + pid, request_id, WTERMSIG(status), rq ? rq->cmdline : "[request not found]");
1014 else
1015 nd_log(NDLS_COLLECTORS, NDLP_INFO,
927 - "SPAWN SERVER: child with pid %d (request %zu) killed by signal %d",
928 - pid, request_id, WTERMSIG(status));
1016 + "SPAWN SERVER: child with pid %d (request %zu) killed by signal %d: %s",
1017 + pid, request_id, WTERMSIG(status), rq ? rq->cmdline : "[request not found]");
1018 send_report_remove_request = true;
1019 }
1020 else if(WIFSTOPPED(status)) {
1021 nd_log(NDLS_COLLECTORS, NDLP_INFO,
933 - "SPAWN SERVER: child with pid %d (request %zu) stopped due to signal %d",
934 - pid, request_id, WSTOPSIG(status));
1022 + "SPAWN SERVER: child with pid %d (request %zu) stopped due to signal %d: %s",
1023 + pid, request_id, WSTOPSIG(status), rq ? rq->cmdline : "[request not found]");
1024 send_report_remove_request = false;
1025 }
1026 else if(WIFCONTINUED(status)) {
1027 nd_log(NDLS_COLLECTORS, NDLP_INFO,
939 - "SPAWN SERVER: child with pid %d (request %zu) continued due to signal %d",
940 - pid, request_id, SIGCONT);
1028 + "SPAWN SERVER: child with pid %d (request %zu) continued due to signal %d: %s",
1029 + pid, request_id, SIGCONT, rq ? rq->cmdline : "[request not found]");
1030 send_report_remove_request = false;
1031 }
1032 else {
1033 nd_log(NDLS_COLLECTORS, NDLP_INFO,
945 - "SPAWN SERVER: child with pid %d (request %zu) reports unhandled status",
946 - pid, request_id);
1034 + "SPAWN SERVER: child with pid %d (request %zu) reports unhandled status: %s",
1035 + pid, request_id, rq ? rq->cmdline : "[request not found]");
1036 send_report_remove_request = false;
1037 }
1038
1039 if(send_report_remove_request && rq) {
1040 spawn_server_send_status_exit(rq->socket, status);
952 - close(rq->socket);
1041 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(spawn_server_requests, rq, prev, next);
954 - freez(rq);
1042 + request_free(rq);
1043 }
1044 }
1045 }
@@ -961,7 +1049,7 @@ static void signals_unblock(void) {
1049 sigfillset(&sigset);
1050
1051 if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
964 - netdata_log_error("SIGNAL: Could not unblock signals for threads");
1052 + netdata_log_error("SPAWN SERVER: Could not unblock signals for threads");
1053 }
1054 }
1055
src/libnetdata/spawn_server/spawn_server.h
+1
@@ -22,6 +22,7 @@ typedef enum __attribute__((packed)) {
22 // this is only used publicly for SPAWN_INSTANCE_TYPE_CALLBACK
23 // which is not available in Windows
24 typedef struct spawn_request {
25 + const char *cmdline;
26 size_t request_id;
27 pid_t pid;
28 int socket;