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