aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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