From 464065f42959abc655b8e680572c08793dd0c56e Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 25 Sep 2018 19:25:10 +0100 Subject: 43543: Further improvements to fg/bg of superjob/subjob. Attempt to keep STAT_STOPPED correct for superjob, rendering additional "stopped = 1" unnecessary. Wait for subjob before superjob. --- Src/jobs.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'Src') diff --git a/Src/jobs.c b/Src/jobs.c index c399f1d3e..f64b46b74 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -459,19 +459,29 @@ update_job(Job jn) jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo)); gettyinfo(jn->ty); } - if (jn->stat & STAT_STOPPED) { - if (jn->stat & STAT_SUBJOB) { - /* If we have `cat foo|while read a; grep $a bar;done' - * and have hit ^Z, the sub-job is stopped, but the - * super-job may still be running, waiting to be stopped - * or to exit. So we have to send it a SIGTSTP. */ - int i; - - if ((i = super_job(job))) - killpg(jobtab[i].gleader, SIGTSTP); + if (jn->stat & STAT_SUBJOB) { + /* If we have `cat foo|while read a; grep $a bar;done' + * and have hit ^Z, the sub-job is stopped, but the + * super-job may still be running, waiting to be stopped + * or to exit. So we have to send it a SIGTSTP. */ + int i; + + if ((i = super_job(job))) { + killpg(jobtab[i].gleader, SIGTSTP); + /* + * Job may already be stopped if it consists of only the + * forked shell waiting for the subjob -- so mark as + * stopped immediately. This ensures we send it (and, + * crucially, the subjob, as the visible job used with + * fg/bg is the superjob) a SIGCONT if we need it. + */ + jobtab[i].stat |= STAT_CHANGED | STAT_STOPPED; } + jn->stat |= STAT_CHANGED | STAT_STOPPED; return; } + if (jn->stat & STAT_STOPPED) + return; } { /* job is done or stopped, remember return value */ lastval2 = val; @@ -1608,10 +1618,11 @@ waitjobs(void) Job jn = jobtab + thisjob; DPUTS(thisjob == -1, "No valid job in waitjobs."); - waitonejob(jn); + /* If there's a subjob, it should finish first. */ if (jn->stat & STAT_SUPERJOB) waitonejob(jobtab + jn->other); - + waitonejob(jn); + thisjob = -1; } @@ -2407,17 +2418,9 @@ bin_fg(char *name, char **argv, Options ops, int func) ((!jobtab[job].procs->next || (jobtab[job].stat & STAT_SUBLEADER) || killpg(jobtab[job].gleader, 0) == -1)) && - jobtab[jobtab[job].other].gleader) { + jobtab[jobtab[job].other].gleader) attachtty(jobtab[jobtab[job].other].gleader); - /* - * In case stopped by putting in background. - * Usually that's visible to the user, who - * can restart, but with a superjob this is done - * behind the scenes, so do it here. Should - * be harmless if not needed. - */ - stopped = 1; - } else + else attachtty(jobtab[job].gleader); } } -- cgit 1.4.1