aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-02-18 15:37:43 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-02-18 15:37:43 +0100
commit47eb979404735b9528538968cb5eaac7355a0c5a (patch)
tree3e75d1d7e964b45156c097ce745eee26d004fb9b
parent97edfc42f112a15828aaec886ef7012d24f34d5e (diff)
downloadbusybox-w32-47eb979404735b9528538968cb5eaac7355a0c5a.tar.gz
busybox-w32-47eb979404735b9528538968cb5eaac7355a0c5a.tar.bz2
busybox-w32-47eb979404735b9528538968cb5eaac7355a0c5a.zip
ash: jobs: Only clear gotsigchld when waiting for everything
Upstream commit: Date: Sat, 19 May 2018 02:39:41 +0800 jobs: Only clear gotsigchld when waiting for everything The gotsigchld flag is always cleared in dowait but not all callers of dowait will wait for everything. In particular, when jp is set we only wait until the set job isn't running anymore. This patch fixes this by only clearing gotsigchld if jp is unset. It also changes the waitcmd to actually set jp which corresponds to the behaviour of bash/ksh93/mksh. The only other caller of dowait that doesn't wait for everything is the jobless reaper. This is in fact redundant now that we wait after every simple command. This patch removes it. Finally as every caller of dowait needs to wait until either the given job is not running, or until all terminated jobs have been processed, this patch moves the loop into dowait itself. Fixes: 03876c0743a5 ("eval: Reap zombies after built-in...") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c122
1 files changed, 56 insertions, 66 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 2b1378694..ff594050c 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -3810,8 +3810,6 @@ static struct job *jobtab; //5
3810static unsigned njobs; //4 3810static unsigned njobs; //4
3811/* current job */ 3811/* current job */
3812static struct job *curjob; //lots 3812static struct job *curjob; //lots
3813/* number of presumed living untracked jobs */
3814static int jobless; //4
3815 3813
3816#if 0 3814#if 0
3817/* Bash has a feature: it restores termios after a successful wait for 3815/* Bash has a feature: it restores termios after a successful wait for
@@ -4331,7 +4329,7 @@ wait_block_or_sig(int *status)
4331#endif 4329#endif
4332 4330
4333static int 4331static int
4334dowait(int block, struct job *job) 4332waitone(int block, struct job *job)
4335{ 4333{
4336 int pid; 4334 int pid;
4337 int status; 4335 int status;
@@ -4432,10 +4430,6 @@ dowait(int block, struct job *job)
4432 goto out; 4430 goto out;
4433 } 4431 }
4434 /* The process wasn't found in job list */ 4432 /* The process wasn't found in job list */
4435#if JOBS
4436 if (!WIFSTOPPED(status))
4437 jobless--;
4438#endif
4439 out: 4433 out:
4440 INT_ON; 4434 INT_ON;
4441 4435
@@ -4460,6 +4454,20 @@ dowait(int block, struct job *job)
4460 return pid; 4454 return pid;
4461} 4455}
4462 4456
4457static int
4458dowait(int block, struct job *jp)
4459{
4460 int pid = block == DOWAIT_NONBLOCK ? got_sigchld : 1;
4461
4462 while (jp ? jp->state == JOBRUNNING : pid > 0) {
4463 if (!jp)
4464 got_sigchld = 0;
4465 pid = waitone(block, jp);
4466 }
4467
4468 return pid;
4469}
4470
4463#if JOBS 4471#if JOBS
4464static void 4472static void
4465showjob(struct job *jp, int mode) 4473showjob(struct job *jp, int mode)
@@ -4548,8 +4556,7 @@ showjobs(int mode)
4548 TRACE(("showjobs(0x%x) called\n", mode)); 4556 TRACE(("showjobs(0x%x) called\n", mode));
4549 4557
4550 /* Handle all finished jobs */ 4558 /* Handle all finished jobs */
4551 while (dowait(DOWAIT_NONBLOCK, NULL) > 0) 4559 dowait(DOWAIT_NONBLOCK, NULL);
4552 continue;
4553 4560
4554 for (jp = curjob; jp; jp = jp->prev_job) { 4561 for (jp = curjob; jp; jp = jp->prev_job) {
4555 if (!(mode & SHOW_CHANGED) || jp->changed) { 4562 if (!(mode & SHOW_CHANGED) || jp->changed) {
@@ -4666,10 +4673,10 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4666#else 4673#else
4667 dowait(DOWAIT_BLOCK_OR_SIG, NULL); 4674 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4668#endif 4675#endif
4669 /* if child sends us a signal *and immediately exits*, 4676 /* if child sends us a signal *and immediately exits*,
4670 * dowait() returns pid > 0. Check this case, 4677 * dowait() returns pid > 0. Check this case,
4671 * not "if (dowait() < 0)"! 4678 * not "if (dowait() < 0)"!
4672 */ 4679 */
4673 if (pending_sig) 4680 if (pending_sig)
4674 goto sigout; 4681 goto sigout;
4675#if BASH_WAIT_N 4682#if BASH_WAIT_N
@@ -4705,11 +4712,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4705 job = getjob(*argv, 0); 4712 job = getjob(*argv, 0);
4706 } 4713 }
4707 /* loop until process terminated or stopped */ 4714 /* loop until process terminated or stopped */
4708 while (job->state == JOBRUNNING) { 4715 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4709 dowait(DOWAIT_BLOCK_OR_SIG, NULL); 4716 if (pending_sig)
4710 if (pending_sig) 4717 goto sigout;
4711 goto sigout;
4712 }
4713 job->waited = 1; 4718 job->waited = 1;
4714 retval = getstatus(job); 4719 retval = getstatus(job);
4715 repeat: ; 4720 repeat: ;
@@ -5261,7 +5266,6 @@ forkchild(struct job *jp, union node *n, int mode)
5261#endif 5266#endif
5262 for (jp = curjob; jp; jp = jp->prev_job) 5267 for (jp = curjob; jp; jp = jp->prev_job)
5263 freejob(jp); 5268 freejob(jp);
5264 jobless = 0;
5265} 5269}
5266 5270
5267/* Called after fork(), in parent */ 5271/* Called after fork(), in parent */
@@ -5272,13 +5276,8 @@ static void
5272forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5276forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5273{ 5277{
5274 TRACE(("In parent shell: child = %d\n", pid)); 5278 TRACE(("In parent shell: child = %d\n", pid));
5275 if (!jp) { 5279 if (!jp) /* jp is NULL when called by openhere() for heredoc support */
5276 /* jp is NULL when called by openhere() for heredoc support */
5277 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5278 continue;
5279 jobless++;
5280 return; 5280 return;
5281 }
5282#if JOBS 5281#if JOBS
5283 if (mode != FORK_NOJOB && jp->jobctl) { 5282 if (mode != FORK_NOJOB && jp->jobctl) {
5284 int pgrp; 5283 int pgrp;
@@ -5357,48 +5356,39 @@ waitforjob(struct job *jp)
5357 5356
5358 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0)); 5357 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5359 5358
5360 if (!jp) { 5359 /* In non-interactive shells, we _can_ get
5361 int pid = got_sigchld; 5360 * a keyboard signal here and be EINTRed, but we just loop
5362 5361 * inside dowait(), waiting for command to complete.
5363 while (pid > 0) 5362 *
5364 pid = dowait(DOWAIT_NONBLOCK, NULL); 5363 * man bash:
5365 5364 * "If bash is waiting for a command to complete and receives
5365 * a signal for which a trap has been set, the trap
5366 * will not be executed until the command completes."
5367 *
5368 * Reality is that even if trap is not set, bash
5369 * will not act on the signal until command completes.
5370 * Try this. sleep5intoff.c:
5371 * #include <signal.h>
5372 * #include <unistd.h>
5373 * int main() {
5374 * sigset_t set;
5375 * sigemptyset(&set);
5376 * sigaddset(&set, SIGINT);
5377 * sigaddset(&set, SIGQUIT);
5378 * sigprocmask(SIG_BLOCK, &set, NULL);
5379 * sleep(5);
5380 * return 0;
5381 * }
5382 * $ bash -c './sleep5intoff; echo hi'
5383 * ^C^C^C^C <--- pressing ^C once a second
5384 * $ _
5385 * $ bash -c './sleep5intoff; echo hi'
5386 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5387 * $ _
5388 */
5389 dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5390 if (!jp)
5366 return exitstatus; 5391 return exitstatus;
5367 }
5368
5369 while (jp->state == JOBRUNNING) {
5370 /* In non-interactive shells, we _can_ get
5371 * a keyboard signal here and be EINTRed,
5372 * but we just loop back, waiting for command to complete.
5373 *
5374 * man bash:
5375 * "If bash is waiting for a command to complete and receives
5376 * a signal for which a trap has been set, the trap
5377 * will not be executed until the command completes."
5378 *
5379 * Reality is that even if trap is not set, bash
5380 * will not act on the signal until command completes.
5381 * Try this. sleep5intoff.c:
5382 * #include <signal.h>
5383 * #include <unistd.h>
5384 * int main() {
5385 * sigset_t set;
5386 * sigemptyset(&set);
5387 * sigaddset(&set, SIGINT);
5388 * sigaddset(&set, SIGQUIT);
5389 * sigprocmask(SIG_BLOCK, &set, NULL);
5390 * sleep(5);
5391 * return 0;
5392 * }
5393 * $ bash -c './sleep5intoff; echo hi'
5394 * ^C^C^C^C <--- pressing ^C once a second
5395 * $ _
5396 * $ bash -c './sleep5intoff; echo hi'
5397 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5398 * $ _
5399 */
5400 dowait(DOWAIT_BLOCK, jp);
5401 }
5402 5392
5403 st = getstatus(jp); 5393 st = getstatus(jp);
5404#if JOBS 5394#if JOBS