Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: unable to wait on completed job [was: should $! give the pid of subshell?]



On Sun, 29 Nov 2009 21:14:36 -0800
Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> [schaefer@torch]$ (sleep 10; exit 19) &
> [1] 1680
> [schaefer@torch]$ pid=$!
> [schaefer@torch]$ sleep 12; wait $pid
> [1]+  Exit 19                 ( sleep 10; exit 19 )
> bash: wait: pid 1680 is not a child of this shell
>>..
> Apparently POSIX.2 requires "wait" be able to access the exit status
> of an asynchronous job until the next asynchronous job is started.
> Zsh is only able to access that status until the next job (whether
> synchronous or not) completes; the completion of "sleep 12" clears
> the previously-completed "sleep 10 &" from the job table, so "wait"
> is no longer able to see it.

(Moved to zsh-workers.)

If it's only an issue for $! (lastpid internally), I think it's fairly
straightforward to fix.  I tried to make it work even if a new process with
the same PID came along later.

No idea about anything to do with SIGTTOU, however, that's outside my
range.

Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.172
diff -u -r1.172 exec.c
--- Src/exec.c	22 Sep 2009 09:17:10 -0000	1.172
+++ Src/exec.c	30 Nov 2009 18:34:17 -0000
@@ -2727,6 +2727,8 @@
 #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;
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.106
diff -u -r1.106 init.c
--- Src/init.c	12 Jul 2009 15:10:07 -0000	1.106
+++ Src/init.c	30 Nov 2009 18:34:18 -0000
@@ -913,6 +913,7 @@
     bufstack = znewlinklist();
     hsubl = hsubr = NULL;
     lastpid = 0;
+    lastpid_status = -1L;
     bshin = SHIN ? fdopen(SHIN, "r") : stdin;
     if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
 #ifdef _IONBF
Index: Src/jobs.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/jobs.c,v
retrieving revision 1.73
diff -u -r1.73 jobs.c
--- Src/jobs.c	30 Sep 2009 20:32:49 -0000	1.73
+++ Src/jobs.c	30 Nov 2009 18:34:18 -0000
@@ -104,6 +104,15 @@
 /**/
 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 @@
 {
     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,8 @@
 		retval = waitforpid(pid, 1);
 		if (!retval)
 		    retval = lastval2;
+	    } else if (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? */
Index: Src/signals.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/signals.c,v
retrieving revision 1.56
diff -u -r1.56 signals.c
--- Src/signals.c	20 Jul 2009 04:38:56 -0000	1.56
+++ Src/signals.c	30 Nov 2009 18:34:18 -0000
@@ -530,6 +530,7 @@
 	     * 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 @@
 		 */
 		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;
  


-- 
Peter Stephenson <pws@xxxxxxx>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom



Messages sorted by: Reverse Date, Date, Thread, Author