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.
52 lines
2.9 KiB
52 lines
2.9 KiB
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 */
|
|
|