summaryrefslogtreecommitdiff
blob: 06e645c1dee9b383e1e12e0c31609ecde48cd806 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# Rework SIGCHLD handler to anticipate multiple children dying while the
# handler is being executed.
#
# Without the patch if multiple SIGCHLD signals are received while the signal
# handler is being executed, the first will be left in pending state and the
# extra discarded. Due to the children processing logic in netplugd, the ones
# which were missed will never be waited, left as zombies.
#
# Implementation of the signal handler is following suggested handling in
# https://www.gnu.org/software/libc/manual/html_node/Merged-Signals.html
#
# The patch strives to change only the children wait logic in the signal
# handler, it doesn't try to enhance write call error handling or the unsafe
# call to exit/do_log. Also the formatting is left as it was in the original
# code.

--- a/main.c
+++ b/main.c
@@ -153,17 +153,29 @@ static int child_handler_pipe[2];
 static void
 child_handler(int sig, siginfo_t *info, void *v)
 {
-    struct child_exit ce;
-    int ret;
-    ssize_t s = 0;
+    int old_errno = errno;
 
     assert(sig == SIGCHLD);
 
-    ce.pid = info->si_pid;
-    ret = waitpid(info->si_pid, &ce.status, 0);
-    if (ret == info->si_pid)
+    while (1)
     {
-        s = write(child_handler_pipe[1], &ce, sizeof(ce));
+        pid_t pid;
+        int status;
+
+        do
+        {
+            errno = 0;
+            pid = waitpid(WAIT_ANY, &status, WNOHANG);
+        } while (pid <= 0 && errno == EINTR);
+
+        if (pid <= 0)
+        {
+            break;
+        }
+
+        struct child_exit ce = { .pid = pid, .status = status };
+
+        ssize_t s = write(child_handler_pipe[1], &ce, sizeof(ce));
 
 	if (s == -1)
 	{
@@ -171,6 +183,9 @@ child_handler(int sig, siginfo_t *info, void *v)
 	    exit(1);
 	}
     }
+
+    errno = old_errno;
+    return;
 }
 
 /* Poll the existing interface state, so we can catch any state