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

Re: [PATCH] problem with 'ls | less' shell function



> 2022/11/04 15:09, Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> 
> Unfortunately, that leaves us with  another example in 50105 still unfixed:
> 
> ( zsh -fc 'print a few words; /bin/sleep 10' ) | { head -n 1 }

The main zsh (zsh0, pid=pgid=100) forks two times;
the 1st one exec 'zsh -fc' (zsh1, pid=101), the 2nd one 'head' (pid=102).
Both are in the process group pgid=101, and the group becomes foreground.
But it seems these two are in different jobs (because of { head } ?).
Then zsh1 exec 'sleep 100' (without forking). Now 'sleep 100' has pid=101
and pgid=101.
When 'head' exits, zsh0 calls update_job(). In this function:

548         /* is this job in the foreground of an interactive shell? */
549         if (mypgrp != pgrp && inforeground &&
550             (jn->gleader == pgrp ||
551              (pgrp > 1 &&                             
552               (kill(-pgrp, 0) == -1 && errno == ESRCH)))) {

mypgrp=100, pgrp=101, jn->gleader=101, and the if(...) holds, and the line

568                     jn->stat |= STAT_ATTACH;    

is executed. Since { head } is a separate job and head has exited, the
job will be removed, and attachtty(mypgrp=100) will be called when the
job is removed. Then pgid=101 (=sleep 100) lose tty. 

But why just "jn->gleader == pgrp" is enough to assume that the foreground
job has finished? If the line 550 above is replaced by

550             (

then ^C works for
[1] ( zsh -fc 'print a few words; /bin/sleep 10' ) | { head -n 1 }

But now we need two ^C's to kill
[2] { sleep 10; sleep 20; } | { sleep 30; sleep 40; }

Another code that looks suspicious to me is (also in jobs.c)

478         if (pn->pid == jn->gleader)    /* if this process is process group leader */
479             status = pn->status;
480     }

The 'status' is later used at (line numbers after the patch pipejobs.txt):

641     if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) {

When 'sleep 30' is killed, pn->pid=(pid of sleep 30), but it is not equal
to jn->gleader (= probably 'sleep 10'?). Then if() at line 641 does not hold,
and 'sleep 40' will be started.

If the line 478 is replaced by

478         if (WIFSIGNALED(pn->status) || pn->pid == jn->gleader)

then [2] can be killed by a single ^C. But I guess it will have bad side
effects. And ^Z/fg (still) does not work for [2].

Sorry, I have no time now to investigate further.



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