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