diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2020-04-10 21:03:09 +1000 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2020-04-29 16:04:17 +1000 |
commit | 2a4f8f94a72413997ff98800fc6bf6bc028290a5 (patch) | |
tree | 32bfda5a309821eb10292477c8e9edd04a09d69d /src | |
parent | var: Remove poplocalvars() always-zero argument, make it static (diff) | |
download | dash-2a4f8f94a72413997ff98800fc6bf6bc028290a5.tar.gz dash-2a4f8f94a72413997ff98800fc6bf6bc028290a5.zip |
jobs: Fix infinite loop in waitproc
After we changed the resetting of gotsigchld so that it is only done if jp is NULL, we can now get an infinite loop in waitproc if gotsigchld is set but there is no outstanding child because everything had been waited for previously without gotsigchld being zeroed. This patch fixes it by always zeroing gotsigchld as we did before. The bug that the previous patch was trying to fix is now resolved by switching the blocking mode to DOWAIT_NORMAL after the specified job has been completed so that we really do wait for all outstanding dead children. Reported-by: Harald van Dijk <harald@gigawatt.nl> Fixes: 6c691b3e5099 ("jobs: Only clear gotsigchld when waiting...") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'src')
-rw-r--r-- | src/jobs.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/src/jobs.c b/src/jobs.c index ba77c00..a9e6524 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -1123,15 +1123,28 @@ out: static int dowait(int block, struct job *jp) { - int pid = block == DOWAIT_NONBLOCK ? gotsigchld : 1; + int gotchld = *(volatile int *)&gotsigchld; + int rpid; + int pid; + + if (jp && jp->state != JOBRUNNING) + block = DOWAIT_NONBLOCK; + + if (block == DOWAIT_NONBLOCK && !gotchld) + return 1; - while (jp ? jp->state == JOBRUNNING : pid > 0) { - if (!jp) - gotsigchld = 0; + rpid = 1; + + do { + gotsigchld = 0; pid = waitone(block, jp); - } + rpid &= !!pid; - return pid; + if (!pid || (jp && jp->state != JOBRUNNING)) + block = DOWAIT_NONBLOCK; + } while (pid >= 0); + + return rpid; } /* @@ -1163,7 +1176,10 @@ waitproc(int block, int *status) #endif do { - err = wait3(status, flags, NULL); + do + err = wait3(status, flags, NULL); + while (err < 0 && errno == EINTR); + if (err || (err = -!block)) break; @@ -1173,8 +1189,6 @@ waitproc(int block, int *status) sigsuspend(&oldmask); sigclearmask(); - - err = 0; } while (gotsigchld); return err; |