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

Re: "echo | ps -j $(:) | cat | cat | cat" runs components in different process groups

On Sat, 24 Mar 2018 15:09:44 -0700
Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> On Mar 23, 10:05pm, Joey Pabalinas wrote:
> }
> } > It could be I just haven't constructed the right test.
> } 
> } It's kind of an *incredibly* unlikely edge-case but FWIW:
> } 
> } > $ echo | ps -j $(: $(cat)) | cat | cat | cat
> } 
> } The shell _seems_ to completely lock up after applying your patch;
> on } my zsh 5.4.2 release version there are no problems (aside from
> the } original process group leader issues).
> Hmm.  The parent shell has received a SIGTTIN signal during
> readoutput() even though the descriptor from which it is reading is
> not a TTY.
> This is because the tty process group is still that of the deceased
> job leader, and $(cat) is in the new process group owned by the
> parent, so when $(cat) is stopped the process group stops as well.
> The parent needs to reattach to the terminal when reaping the group
> leader, so that $(cat) doesn't get SIGTTYIN and so that the parent
> begins receiving tty interrupts etc. again.

The following is all a bit tentative...

If we allow a simpler version of the patch I just posted --- where we
always make the next process to start the new process group leader and
shrug our shoulders over anything that's started so far --- then
reattaching looks simple enough.  The following's probably not
sophisticated enough yet since we should only take back the terminal if
the exited group leader was in the foreground.

But looking at ps output while ^C is failing to have any effect suggests
things are worse than that.  I think at this point the parent shell
hasn't actually reaped the echo (it's <defunct>), so hasn't executed
this chunk of code.  That's got something to do with the fact that it's
got child reaping blocked while trying to read output from the the $(:
...) process --- it's executing the same code as the forked shell
waiting for the cat.  However, even simple-minded child unblocking
didn't seem to cause the zombie to go away, at which point I got stuck.

(The following change isn't going anyway near the main repository at the
moment, obviously.)


diff --git a/Src/signals.c b/Src/signals.c
index 94f379e..f86ae54 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -537,6 +537,11 @@ wait_for_processes(void)
 		update_process(pn, status);
+		if (pn->pid == jn->gleader) {
+		    jn->gleader = 0;
+		    /* HERE: check this was actually in foreground... */
+		    attachtty(mypgrp);
+		}
 	} else if (findproc(pid, &jn, &pn, 1)) {

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