about summary refs log tree commit diff
path: root/Src/exec.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2016-09-15 11:42:28 +0100
committerPeter Stephenson <pws@zsh.org>2016-09-16 09:39:33 +0100
commit01ae64c0d74c17e36bfe6f52394a59754b8e8c92 (patch)
tree5c76926c158e8ef5460b86b1c5abc7dbc61a9151 /Src/exec.c
parentd523ddaba2cd160343b54d3e38ea001c63a87dc6 (diff)
downloadzsh-01ae64c0d74c17e36bfe6f52394a59754b8e8c92.tar.gz
zsh-01ae64c0d74c17e36bfe6f52394a59754b8e8c92.tar.xz
zsh-01ae64c0d74c17e36bfe6f52394a59754b8e8c92.zip
39331: Reparent subjob on fork with exited superjob.
Fixes case of
  v() { { vim - } always { true } }
  ls | v
  ^Z
  fg

Tentative fix: still a race at exit where zsh forked by ^Z
is stopped when restarted.
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/Src/exec.c b/Src/exec.c
index cfd633add..21270c82d 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1570,6 +1570,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 
 	    if (nowait) {
 		if(!pline_level) {
+		    int jobsub;
 		    struct process *pn, *qn;
 
 		    curjob = newjob;
@@ -1582,6 +1583,20 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 		    if (!jn->procs->next || lpforked == 2) {
 			jn->gleader = list_pipe_pid;
 			jn->stat |= STAT_SUBLEADER;
+			/*
+			 * Pick up any subjob that's still lying around
+			 * as it's now our responsibility.
+			 * If we find it we're a SUPERJOB.
+			 */
+			for (jobsub = 1; jobsub <= maxjob; jobsub++) {
+			    Job jnsub = jobtab + jobsub;
+			    if (jnsub->stat & STAT_SUBJOB_ORPHANED) {
+				jn->other = jobsub;
+				jn->stat |= STAT_SUPERJOB;
+				jnsub->stat &= ~STAT_SUBJOB_ORPHANED;
+				jnsub->other = list_pipe_pid;
+			    }
+			}
 		    }
 		    for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
 			if (WIFSTOPPED(pn->status))
@@ -1593,7 +1608,8 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 		    }
 
 		    jn->stat &= ~(STAT_DONE | STAT_NOPRINT);
-		    jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED;
+		    jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED |
+			STAT_INUSE;
 		    printjob(jn, !!isset(LONGLISTJOBS), 1);
 		}
 		else if (newjob != list_pipe_job)
@@ -1669,6 +1685,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 			    jobtab[list_pipe_job].stat |= STAT_SUPERJOB;
 			    jn->stat |= STAT_SUBJOB | STAT_NOPRINT;
 			    jn->other = pid;
+			    jn->gleader = jobtab[list_pipe_job].gleader;
 			}
 			if ((list_pipe || last1) && hasprocs(list_pipe_job))
 			    killpg(jobtab[list_pipe_job].gleader, SIGSTOP);