ash: eval: Reap zombies after built-in commands and functions
Upstream commit: Date: Mon, 26 Mar 2018 23:55:50 +0800 eval: Reap zombies after built-in commands and functions Currently dash does not reap dead children after built-in commands or functions. This means that if you construct a loop consisting of solely built-in commands and functions, then zombies can hang around indefinitely. This patch fixes this by reaping when necessary after each built-in command and function. Reported-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
22c75924da
commit
d81af7216b
26
shell/ash.c
26
shell/ash.c
@ -5355,10 +5355,10 @@ waitforjob(struct job *jp)
|
|||||||
{
|
{
|
||||||
int st;
|
int st;
|
||||||
|
|
||||||
TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
|
TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
|
||||||
|
|
||||||
INT_OFF;
|
INT_OFF;
|
||||||
while (jp->state == JOBRUNNING) {
|
while ((jp && jp->state == JOBRUNNING) || got_sigchld) {
|
||||||
/* 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.
|
||||||
@ -5393,6 +5393,8 @@ waitforjob(struct job *jp)
|
|||||||
}
|
}
|
||||||
INT_ON;
|
INT_ON;
|
||||||
|
|
||||||
|
if (!jp)
|
||||||
|
return exitstatus;
|
||||||
st = getstatus(jp);
|
st = getstatus(jp);
|
||||||
#if JOBS
|
#if JOBS
|
||||||
if (jp->jobctl) {
|
if (jp->jobctl) {
|
||||||
@ -10311,6 +10313,8 @@ evalcommand(union node *cmd, int flags)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jp = NULL;
|
||||||
|
|
||||||
/* Execute the command. */
|
/* Execute the command. */
|
||||||
switch (cmdentry.cmdtype) {
|
switch (cmdentry.cmdtype) {
|
||||||
default: {
|
default: {
|
||||||
@ -10365,7 +10369,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 */
|
||||||
status = waitforjob(jp);
|
|
||||||
INT_ON;
|
INT_ON;
|
||||||
TRACE(("forked child exited with %d\n", status));
|
TRACE(("forked child exited with %d\n", status));
|
||||||
break;
|
break;
|
||||||
@ -10384,33 +10387,24 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tight loop with builtins only:
|
|
||||||
* "while kill -0 $child; do true; done"
|
|
||||||
* will never exit even if $child died, unless we do this
|
|
||||||
* to reap the zombie and make kill detect that it's gone: */
|
|
||||||
dowait(DOWAIT_NONBLOCK, NULL);
|
|
||||||
|
|
||||||
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
|
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
|
||||||
if (exception_type == EXERROR && spclbltin <= 0) {
|
if (exception_type == EXERROR && spclbltin <= 0) {
|
||||||
FORCE_INT_ON;
|
FORCE_INT_ON;
|
||||||
goto readstatus;
|
break;
|
||||||
}
|
}
|
||||||
raise:
|
raise:
|
||||||
longjmp(exception_handler->loc, 1);
|
longjmp(exception_handler->loc, 1);
|
||||||
}
|
}
|
||||||
goto readstatus;
|
break;
|
||||||
|
|
||||||
case CMDFUNCTION:
|
case CMDFUNCTION:
|
||||||
/* See above for the rationale */
|
|
||||||
dowait(DOWAIT_NONBLOCK, NULL);
|
|
||||||
if (evalfun(cmdentry.u.func, argc, argv, flags))
|
if (evalfun(cmdentry.u.func, argc, argv, flags))
|
||||||
goto raise;
|
goto raise;
|
||||||
readstatus:
|
|
||||||
status = exitstatus;
|
|
||||||
break;
|
break;
|
||||||
} /* switch */
|
} /* switch */
|
||||||
|
|
||||||
|
status = waitforjob(jp);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (cmd->ncmd.redirect)
|
if (cmd->ncmd.redirect)
|
||||||
popredir(/*drop:*/ cmd_is_exec);
|
popredir(/*drop:*/ cmd_is_exec);
|
||||||
|
Loading…
Reference in New Issue
Block a user