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>
This commit is contained in:
parent
97edfc42f1
commit
47eb979404
54
shell/ash.c
54
shell/ash.c
@ -3810,8 +3810,6 @@ static struct job *jobtab; //5
|
||||
static unsigned njobs; //4
|
||||
/* current job */
|
||||
static struct job *curjob; //lots
|
||||
/* number of presumed living untracked jobs */
|
||||
static int jobless; //4
|
||||
|
||||
#if 0
|
||||
/* Bash has a feature: it restores termios after a successful wait for
|
||||
@ -4331,7 +4329,7 @@ wait_block_or_sig(int *status)
|
||||
#endif
|
||||
|
||||
static int
|
||||
dowait(int block, struct job *job)
|
||||
waitone(int block, struct job *job)
|
||||
{
|
||||
int pid;
|
||||
int status;
|
||||
@ -4432,10 +4430,6 @@ dowait(int block, struct job *job)
|
||||
goto out;
|
||||
}
|
||||
/* The process wasn't found in job list */
|
||||
#if JOBS
|
||||
if (!WIFSTOPPED(status))
|
||||
jobless--;
|
||||
#endif
|
||||
out:
|
||||
INT_ON;
|
||||
|
||||
@ -4460,6 +4454,20 @@ dowait(int block, struct job *job)
|
||||
return pid;
|
||||
}
|
||||
|
||||
static int
|
||||
dowait(int block, struct job *jp)
|
||||
{
|
||||
int pid = block == DOWAIT_NONBLOCK ? got_sigchld : 1;
|
||||
|
||||
while (jp ? jp->state == JOBRUNNING : pid > 0) {
|
||||
if (!jp)
|
||||
got_sigchld = 0;
|
||||
pid = waitone(block, jp);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
#if JOBS
|
||||
static void
|
||||
showjob(struct job *jp, int mode)
|
||||
@ -4548,8 +4556,7 @@ showjobs(int mode)
|
||||
TRACE(("showjobs(0x%x) called\n", mode));
|
||||
|
||||
/* Handle all finished jobs */
|
||||
while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
|
||||
continue;
|
||||
dowait(DOWAIT_NONBLOCK, NULL);
|
||||
|
||||
for (jp = curjob; jp; jp = jp->prev_job) {
|
||||
if (!(mode & SHOW_CHANGED) || jp->changed) {
|
||||
@ -4705,11 +4712,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
|
||||
job = getjob(*argv, 0);
|
||||
}
|
||||
/* loop until process terminated or stopped */
|
||||
while (job->state == JOBRUNNING) {
|
||||
dowait(DOWAIT_BLOCK_OR_SIG, NULL);
|
||||
if (pending_sig)
|
||||
goto sigout;
|
||||
}
|
||||
job->waited = 1;
|
||||
retval = getstatus(job);
|
||||
repeat: ;
|
||||
@ -5261,7 +5266,6 @@ forkchild(struct job *jp, union node *n, int mode)
|
||||
#endif
|
||||
for (jp = curjob; jp; jp = jp->prev_job)
|
||||
freejob(jp);
|
||||
jobless = 0;
|
||||
}
|
||||
|
||||
/* Called after fork(), in parent */
|
||||
@ -5272,13 +5276,8 @@ static void
|
||||
forkparent(struct job *jp, union node *n, int mode, pid_t pid)
|
||||
{
|
||||
TRACE(("In parent shell: child = %d\n", pid));
|
||||
if (!jp) {
|
||||
/* jp is NULL when called by openhere() for heredoc support */
|
||||
while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
|
||||
continue;
|
||||
jobless++;
|
||||
if (!jp) /* jp is NULL when called by openhere() for heredoc support */
|
||||
return;
|
||||
}
|
||||
#if JOBS
|
||||
if (mode != FORK_NOJOB && jp->jobctl) {
|
||||
int pgrp;
|
||||
@ -5357,19 +5356,9 @@ waitforjob(struct job *jp)
|
||||
|
||||
TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
|
||||
|
||||
if (!jp) {
|
||||
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
|
||||
* a keyboard signal here and be EINTRed,
|
||||
* but we just loop back, waiting for command to complete.
|
||||
* a keyboard signal here and be EINTRed, but we just loop
|
||||
* inside dowait(), waiting for command to complete.
|
||||
*
|
||||
* man bash:
|
||||
* "If bash is waiting for a command to complete and receives
|
||||
@ -5397,8 +5386,9 @@ waitforjob(struct job *jp)
|
||||
* ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
|
||||
* $ _
|
||||
*/
|
||||
dowait(DOWAIT_BLOCK, jp);
|
||||
}
|
||||
dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
|
||||
if (!jp)
|
||||
return exitstatus;
|
||||
|
||||
st = getstatus(jp);
|
||||
#if JOBS
|
||||
|
Loading…
Reference in New Issue
Block a user