ash: jobs - Do not block when waiting on SIGCHLD
Upstream comment: Date: Mon, 7 May 2018 00:40:34 +0800 jobs - Do not block when waiting on SIGCHLD Because of the nature of SIGCHLD, the process may have already been waited on and therefore we must be prepared for the case that wait may block. So ensure that it doesn't by using WNOHANG. Furthermore, multiple jobs may have exited when gotsigchld is set. Therefore we need to wait until there are no zombies left. Lastly, waitforjob needs to be called with interrupts off and the original patch broke that. Fixes: 03876c0743a5 ("eval: Reap zombies after built-in...") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> While at it, removed INT_ON/OFF in waitforjob() - it must be called from INT_OFF region anyway. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
d81af7216b
commit
97edfc42f1
25
shell/ash.c
25
shell/ash.c
@ -5357,8 +5357,16 @@ waitforjob(struct job *jp)
|
|||||||
|
|
||||||
TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
|
TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
|
||||||
|
|
||||||
INT_OFF;
|
if (!jp) {
|
||||||
while ((jp && jp->state == JOBRUNNING) || got_sigchld) {
|
int pid = got_sigchld;
|
||||||
|
|
||||||
|
while (pid > 0)
|
||||||
|
pid = dowait(DOWAIT_NONBLOCK, NULL);
|
||||||
|
|
||||||
|
return exitstatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (jp->state == JOBRUNNING) {
|
||||||
/* In non-interactive shells, we _can_ get
|
/* In non-interactive shells, we _can_ get
|
||||||
* a keyboard signal here and be EINTRed,
|
* a keyboard signal here and be EINTRed,
|
||||||
* but we just loop back, waiting for command to complete.
|
* but we just loop back, waiting for command to complete.
|
||||||
@ -5391,10 +5399,7 @@ waitforjob(struct job *jp)
|
|||||||
*/
|
*/
|
||||||
dowait(DOWAIT_BLOCK, jp);
|
dowait(DOWAIT_BLOCK, jp);
|
||||||
}
|
}
|
||||||
INT_ON;
|
|
||||||
|
|
||||||
if (!jp)
|
|
||||||
return exitstatus;
|
|
||||||
st = getstatus(jp);
|
st = getstatus(jp);
|
||||||
#if JOBS
|
#if JOBS
|
||||||
if (jp->jobctl) {
|
if (jp->jobctl) {
|
||||||
@ -10369,7 +10374,6 @@ evalcommand(union node *cmd, int flags)
|
|||||||
jp = makejob(/*cmd,*/ 1);
|
jp = makejob(/*cmd,*/ 1);
|
||||||
if (forkshell(jp, cmd, FORK_FG) != 0) {
|
if (forkshell(jp, cmd, FORK_FG) != 0) {
|
||||||
/* parent */
|
/* parent */
|
||||||
INT_ON;
|
|
||||||
TRACE(("forked child exited with %d\n", status));
|
TRACE(("forked child exited with %d\n", status));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -10387,11 +10391,9 @@ evalcommand(union node *cmd, int flags)
|
|||||||
if (cmd_is_exec && argc > 1)
|
if (cmd_is_exec && argc > 1)
|
||||||
listsetvar(varlist.list, VEXPORT);
|
listsetvar(varlist.list, VEXPORT);
|
||||||
}
|
}
|
||||||
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
|
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
|
||||||
if (exception_type == EXERROR && spclbltin <= 0) {
|
&& !(exception_type == EXERROR && spclbltin <= 0)
|
||||||
FORCE_INT_ON;
|
) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
raise:
|
raise:
|
||||||
longjmp(exception_handler->loc, 1);
|
longjmp(exception_handler->loc, 1);
|
||||||
}
|
}
|
||||||
@ -10404,6 +10406,7 @@ evalcommand(union node *cmd, int flags)
|
|||||||
} /* switch */
|
} /* switch */
|
||||||
|
|
||||||
status = waitforjob(jp);
|
status = waitforjob(jp);
|
||||||
|
FORCE_INT_ON;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (cmd->ncmd.redirect)
|
if (cmd->ncmd.redirect)
|
||||||
|
Loading…
Reference in New Issue
Block a user