From 788faac41b56f8b08e60f3456ad56c5a36fffa4c Mon Sep 17 00:00:00 2001 From: Pavel Raiskup Date: Tue, 27 Jan 2015 07:05:26 +0100 Subject: [PATCH 16/16] tcsh: fix 'wait' hang Make sure that SIGCHLD is blocked before we call handle_pending_signals() for the first time and before we actually check for pp->p_flags & PRUNNING to make sure that the SIGCHLD is not leaked meanwhile. Resolves: rhbz#1181685 --- Fixes | 4 ++++ sh.proc.c | 26 +++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Fixes b/Fixes index 8eac9d4..56915a9 100644 --- a/Fixes +++ b/Fixes @@ -1,3 +1,7 @@ + 29. Pavel Raiskup fix hang with: + while (1) + ( date & ; wait ) + end 6. V6.18.01 - 20120214 5. fix interruptible wait again 4. ignore bogus compiler overflow message diff --git a/sh.proc.c b/sh.proc.c index e32ebda..0c5fc25 100644 --- a/sh.proc.c +++ b/sh.proc.c @@ -593,22 +593,44 @@ void dowait(Char **v, struct command *c) { struct process *pp; + + /* the current block mask to be able to restore */ + sigset_t old_mask; + + /* block mask for critical section: OLD_MASK U {SIGCHLD} */ + sigset_t block_mask; + + /* ignore those during blocking sigsuspend: + OLD_MASK / {SIGCHLD, possibly(SIGINT)} */ sigset_t pause_mask; + int opintr_disabled, gotsig; USE(c); USE(v); pjobs++; + sigprocmask(SIG_BLOCK, NULL, &pause_mask); sigdelset(&pause_mask, SIGCHLD); if (setintr) sigdelset(&pause_mask, SIGINT); + + /* critical section, block also SIGCHLD */ + sigprocmask(SIG_BLOCK, NULL, &block_mask); + sigaddset(&block_mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &block_mask, &old_mask); + + /* detect older SIGCHLDs and remove PRUNNING flag from proclist */ + (void)handle_pending_signals(); + loop: for (pp = proclist.p_next; pp; pp = pp->p_next) if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ pp->p_flags & PRUNNING) { - (void)handle_pending_signals(); + /* wait for (or pick up alredy blocked) SIGCHLD */ sigsuspend(&pause_mask); + + /* make the 'wait' interuptable by CTRL-C */ opintr_disabled = pintr_disabled; pintr_disabled = 0; gotsig = handle_pending_signals(); @@ -618,6 +640,8 @@ loop: goto loop; } pjobs = 0; + + sigprocmask(SIG_SETMASK, &old_mask, NULL); } /* -- 2.1.0