1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-01-01 05:16:05 +01:00

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.
This commit is contained in:
Peter Stephenson 2016-09-15 11:42:28 +01:00
parent d523ddaba2
commit 01ae64c0d7
4 changed files with 38 additions and 4 deletions

View file

@ -1,3 +1,10 @@
2016-09-16 Peter Stephenson <p.stephenson@samsung.com>
* 39331: Src/exec.c, Src/jobs.c, Src/zsh.h: Partially fix problem
occurring when a subjop in the RHS of a pipeline needs to be
picked up by a forked zsh after ^Z when the original superjob
(LHS of pipeline) has already exited. Still race-prone.
2016-09-16 Daniel Shahaf <d.s@daniel.shahaf.name>
* unposted: Completion/Unix/Command/_postfix: Correct quoting

View file

@ -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);

View file

@ -128,7 +128,7 @@ makerunning(Job jn)
Process pn;
jn->stat &= ~STAT_STOPPED;
for (pn = jn->procs; pn; pn = pn->next)
for (pn = jn->procs; pn; pn = pn->next) {
#if 0
if (WIFSTOPPED(pn->status) &&
(!(jn->stat & STAT_SUPERJOB) || pn->next))
@ -136,6 +136,7 @@ makerunning(Job jn)
#endif
if (WIFSTOPPED(pn->status))
pn->status = SP_RUNNING;
}
if (jn->stat & STAT_SUPERJOB)
makerunning(jobtab + jn->other);
@ -236,7 +237,7 @@ handle_sub(int job, int fg)
if ((sj->stat & STAT_DONE) || (!sj->procs && !sj->auxprocs)) {
struct process *p;
for (p = sj->procs; p; p = p->next)
for (p = sj->procs; p; p = p->next) {
if (WIFSIGNALED(p->status)) {
if (jn->gleader != mypgrp && jn->procs->next)
killpg(jn->gleader, WTERMSIG(p->status));
@ -246,6 +247,7 @@ handle_sub(int job, int fg)
kill(sj->other, WTERMSIG(p->status));
break;
}
}
if (!p) {
int cp;
@ -1316,6 +1318,11 @@ deletejob(Job jn, int disowning)
attachtty(mypgrp);
adjustwinsize(0);
}
if (jn->stat & STAT_SUPERJOB) {
Job jno = jobtab + jn->other;
if (jno->stat & STAT_SUBJOB)
jno->stat |= STAT_SUBJOB_ORPHANED;
}
freejob(jn, 1);
}

View file

@ -983,7 +983,8 @@ struct jobfile {
struct job {
pid_t gleader; /* process group leader of this job */
pid_t other; /* subjob id or subshell pid */
pid_t other; /* subjob id (SUPERJOB)
* or subshell pid (SUBJOB) */
int stat; /* see STATs below */
char *pwd; /* current working dir of shell when *
* this job was spawned */
@ -1015,6 +1016,8 @@ struct job {
#define STAT_SUBLEADER (0x2000) /* is super-job, but leader is sub-shell */
#define STAT_BUILTIN (0x4000) /* job at tail of pipeline is a builtin */
#define STAT_SUBJOB_ORPHANED (0x8000)
/* STAT_SUBJOB with STAT_SUPERJOB exited */
#define SP_RUNNING -1 /* fake status for jobs currently running */