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