Pablo Greco 48fc63
From 64d0115dcda445a5b1c069f696a363730f654425 Mon Sep 17 00:00:00 2001
Pablo Greco 48fc63
From: David Tardon <dtardon@redhat.com>
Pablo Greco 48fc63
Date: Thu, 2 May 2019 12:55:04 +0200
Pablo Greco 48fc63
Subject: [PATCH] avoid possible hang if our child process hangs
Pablo Greco 48fc63
Pablo Greco 48fc63
If there is one or more unexpected child processes that terminate, but
Pablo Greco 48fc63
the "main" child process hangs, we will loop through the terminated
Pablo Greco 48fc63
children and then, eventually, get stuck in the waitpid() call. Let's
Pablo Greco 48fc63
repeat the main cycle if that situation happens, as that allows us to
Pablo Greco 48fc63
finish after timeout.
Pablo Greco 48fc63
Pablo Greco 48fc63
Related: #1697909
Pablo Greco 48fc63
---
Pablo Greco 48fc63
 src/udev/udev-event.c | 11 +++++++++--
Pablo Greco 48fc63
 1 file changed, 9 insertions(+), 2 deletions(-)
Pablo Greco 48fc63
Pablo Greco 48fc63
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
Pablo Greco 48fc63
index 5550ec93de..79b8614ec2 100644
Pablo Greco 48fc63
--- a/src/udev/udev-event.c
Pablo Greco 48fc63
+++ b/src/udev/udev-event.c
Pablo Greco 48fc63
@@ -605,6 +605,7 @@ static int spawn_wait(struct udev_event *event,
Pablo Greco 48fc63
                         struct signalfd_siginfo fdsi;
Pablo Greco 48fc63
                         int status, r;
Pablo Greco 48fc63
                         ssize_t size;
Pablo Greco 48fc63
+                        bool wait_again = false;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                         size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
Pablo Greco 48fc63
                         if (size != sizeof(struct signalfd_siginfo))
Pablo Greco 48fc63
@@ -622,15 +623,21 @@ static int spawn_wait(struct udev_event *event,
Pablo Greco 48fc63
                                            In case the PID we wait for also exited the kernel could coalesce SIGCHLDs and we won't get second SIGCHLD
Pablo Greco 48fc63
                                            on the signalfd. We can't know if coalescing happened or not, hence we need to call waitpid() in a loop until
Pablo Greco 48fc63
                                            the PID we care for exits, we if it haven't already. */
Pablo Greco 48fc63
-                                        while (child_exited < 0) {
Pablo Greco 48fc63
-                                                r = waitpid(-1, &status, 0);
Pablo Greco 48fc63
+                                        while (child_exited < 0 && !wait_again) {
Pablo Greco 48fc63
+                                                r = waitpid(-1, &status, WNOHANG);
Pablo Greco 48fc63
                                                 if (r < 0 && errno == EINTR)
Pablo Greco 48fc63
                                                         continue;
Pablo Greco 48fc63
                                                 else if (r < 0)
Pablo Greco 48fc63
                                                         break;
Pablo Greco 48fc63
                                                 else if (r == pid)
Pablo Greco 48fc63
                                                         child_exited = 0;
Pablo Greco 48fc63
+                                                else if (r == 0)
Pablo Greco 48fc63
+                                                        wait_again = true;
Pablo Greco 48fc63
                                         }
Pablo Greco 48fc63
+
Pablo Greco 48fc63
+                                        /* Only unexpected process(es) have been terminated. Continue waiting */
Pablo Greco 48fc63
+                                        if (wait_again)
Pablo Greco 48fc63
+                                                continue;
Pablo Greco 48fc63
                                 }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                                 /* We didn't wait for child yet, let's do that now */