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