We inherit the signal mask from our parent process, therefore ensure SIGCHLD is not blocked.
If SIGCHLD is blocked, sigsuspend() won't be interrupted when the child process exits and we hang until the timeout (SIGALRM). The issue has been found by an "autotest" testsuite doing high level tests of a custom distribution. One complex test case got stuck 100% of the time. This fixes a regression from commit 2f69dba5df8caaf9eda658c1808b1379e9949f22 Author: Tobias Stoeckmann <tob...@stoeckmann.org> Date: Sun Feb 5 13:23:22 2017 +0100 timeout: fix race possibly terminating wrong process Please CC: comments, I'm not subscribed to the list. Signed-off-by: Thomas Jarosch <thomas.jaro...@intra2net.com> --- src/timeout.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/timeout.c b/src/timeout.c index a58b84f4e..aa2fff7d9 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -323,6 +323,16 @@ parse_duration (const char* str) return duration; } +static void +unblock_signal (int sig) +{ + sigset_t unblock_set; + sigemptyset (&unblock_set); + sigaddset (&unblock_set, sig); + if (sigprocmask (SIG_UNBLOCK, &unblock_set, NULL) != 0) + error (0, errno, _("warning: sigprocmask")); +} + static void install_sigchld (void) { @@ -333,6 +343,10 @@ install_sigchld (void) more likely to work cleanly. */ sigaction (SIGCHLD, &sa, NULL); + + /* we inherit the signal mask from our parent process, + ensure SIGCHLD is not blocked. */ + unblock_signal(SIGCHLD); } static void @@ -369,16 +383,6 @@ block_cleanup (int sigterm, sigset_t *old_set) error (0, errno, _("warning: sigprocmask")); } -static void -unblock_signal (int sig) -{ - sigset_t unblock_set; - sigemptyset (&unblock_set); - sigaddset (&unblock_set, sig); - if (sigprocmask (SIG_UNBLOCK, &unblock_set, NULL) != 0) - error (0, errno, _("warning: sigprocmask")); -} - /* Try to disable core dumps for this process. Return TRUE if successful, FALSE otherwise. */ static bool -- 2.14.1