about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/exec.c2
-rw-r--r--Src/init.c1
-rw-r--r--Src/jobs.c20
-rw-r--r--Src/signals.c10
4 files changed, 33 insertions, 0 deletions
diff --git a/Src/exec.c b/Src/exec.c
index 2263bd640..172d302da 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2727,6 +2727,8 @@ execcmd(Estate state, int input, int output, int how, int last1)
 #endif
 	    if (how & Z_ASYNC) {
 		lastpid = (zlong) pid;
+		/* indicate it's possible to set status for lastpid */
+		lastpid_status = -2L;
 	    } else if (!jobtab[thisjob].stty_in_env && varspc) {
 		/* search for STTY=... */
 		Wordcode p = varspc;
diff --git a/Src/init.c b/Src/init.c
index be1055a53..cf5a6074d 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -913,6 +913,7 @@ setupvals(void)
     bufstack = znewlinklist();
     hsubl = hsubr = NULL;
     lastpid = 0;
+    lastpid_status = -1L;
     bshin = SHIN ? fdopen(SHIN, "r") : stdin;
     if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
 #ifdef _IONBF
diff --git a/Src/jobs.c b/Src/jobs.c
index d0916174f..9b7b053ee 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -104,6 +104,15 @@ int prev_errflag, prev_breaks, errbrk_saved;
 /**/
 int numpipestats, pipestats[MAX_PIPESTATS];
 
+/*
+ * The status associated with the process lastpid.
+ * -1 if not set and no associated lastpid
+ * -2 if lastpid is set and status isn't yet
+ * else the value returned by wait().
+ */
+/**/
+long lastpid_status;
+
 /* Diff two timevals for elapsed-time computations */
 
 /**/
@@ -1109,6 +1118,14 @@ addproc(pid_t pid, char *text, int aux, struct timeval *bgtime)
 {
     Process pn, *pnlist;
 
+    if (pid == lastpid && lastpid_status != -2L) {
+	/*
+	 * The status for the previous lastpid is invalid.
+	 * Presumably process numbers have wrapped.
+	 */
+	lastpid_status = -1L;
+    }
+
     DPUTS(thisjob == -1, "No valid job in addproc.");
     pn = (Process) zshcalloc(sizeof *pn);
     pn->pid = pid;
@@ -1845,6 +1862,9 @@ bin_fg(char *name, char **argv, Options ops, int func)
 		retval = waitforpid(pid, 1);
 		if (!retval)
 		    retval = lastval2;
+	    } else if (isset(POSIXJOBS) &&
+		       pid == lastpid && lastpid_status >= 0L) {
+		retval = (int)lastpid_status;
 	    } else {
 		zwarnnam(name, "pid %d is not a child of this shell", pid);
 		/* presumably lastval2 doesn't tell us a heck of a lot? */
diff --git a/Src/signals.c b/Src/signals.c
index 4bc1de016..f67a3e8ca 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -530,6 +530,7 @@ zhandler(int sig)
 	     * Find the process and job containing this pid and
 	     * update it.
 	     */
+	    pn = NULL;
 	    if (findproc(pid, &jn, &pn, 0)) {
 #if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE)
 		struct timezone dummy_tz;
@@ -551,6 +552,15 @@ zhandler(int sig)
 		 */
 		get_usage();
 	    }
+	    /*
+	     * Remember the status associated with $!, so we can
+	     * wait for it even if it's exited.  This value is
+	     * only used if we can't find the PID in the job table,
+	     * so it doesn't matter that the value we save here isn't
+	     * useful until the process has exited.
+	     */
+	    if (pn != NULL && pid == lastpid && lastpid_status != -1L)
+		lastpid_status = lastval2;
 	}
         break;