diff options
-rw-r--r-- | shell/ash.c | 122 |
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 | |||
3810 | static unsigned njobs; //4 | 3810 | static unsigned njobs; //4 |
3811 | /* current job */ | 3811 | /* current job */ |
3812 | static struct job *curjob; //lots | 3812 | static struct job *curjob; //lots |
3813 | /* number of presumed living untracked jobs */ | ||
3814 | static 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 | ||
4333 | static int | 4331 | static int |
4334 | dowait(int block, struct job *job) | 4332 | waitone(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 | ||
4457 | static int | ||
4458 | dowait(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 |
4464 | static void | 4472 | static void |
4465 | showjob(struct job *jp, int mode) | 4473 | showjob(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 | |||
5272 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5276 | forkparent(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 |