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

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



> 2022/11/07 4:12, Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> 
> On Fri, Nov 4, 2022 at 5:09 PM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
>> 
>> Second patch attached, replaces the one from workers/50862.
> 
> This "works for me" so I'm going to push it to encourage wider testing.

[1] ( zsh -fc 'print a few words; /bin/sleep 10'; )
[2] { sleep 10; sleep 11; } | { sleep 20; sleep 21; }
[3] dir () { ls | less; }; dir

Now both ^C and ^Z/fg fork for [1], ^C works for [2],
and ^Z/fg works for [3] ({3] can't be killed by ^C but it's OK).

But ^Z/fg still doesn't work for [2]; the pipeline never finishes.
This was not working in zsh-5.8.1, zsh-5.9 and zsh-5.9.1-test (before
worker/50874), so this is not a regression.


worker/50803⁩
> 2022/10/22 6:22, Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> 
> On Fri, Oct 21, 2022 at 12:41 AM Jun T <takimoto-j@xxxxxxxxxxxxxxxxx> wrote:
>> 
>> The subshell have missed the SIGCHLD?
> 
> The subshell will never get the SIGCHLD, because it is a sibling of
> the pipeline, not its parent.

Do you mean the subshell for the right hand side of the pipe?

In the case of [2], the main zsh (zsh0) always fork() a subshell (zsh1)
for the left hand side of the pipe, and zsh1 fork/exec 'sleep 10'.
By hitting ^Z, zsh0 fork() another subshell (zsh2) for the right hand
side of the pipe, but it seems zsh2 is not causing the problem.
After 'fg', zsh1 (not zsh2) is using 100% of a CPU core, and
when 'sleep 10' exits it is left as "defunct" (not waited for).

Strace output suggests that zsh1 does not receive SIGCHLD when
'sleep 10' finishes. Maybe SIGCHLD is blocked?? (I'm not sure).

zsh1 is repeatedly calling hasprocs(list_pid_job) at line 1790 in
exec.c:

1789                 if (!updated &&
1790                     list_pipe_job && hasprocs(list_pipe_job) &&
1791                     !(jobtab[list_pipe_job].stat & STAT_STOPPED)) {
1792                     int q = queue_signal_level();
1793                     child_unblock();
1794                     child_block();
1795                     dont_queue_signals();
1796                     restore_queue_signals(q);
1797                 }

When zsh1 is executing this code, thisjob=2 and list_pipe_job=1,
and hasprocs(list_pipe_job) returns 0 because jobtab[1].procs is NULL.
I guess 'sleep 10' is in thisjob.

If I blindly replace the line 1790 by

1790                     list_pipe_job &&

then 'sleep 10' does not left as "defunct" and the pipeline finishes when
all the sleeps exit. But zsh1 still uses 100% of CPU before 'sleep 10'
exits (replace 'sleep 10' by 'sleep 30' to see this more easily),
so this is obviously not the correct solution.

# I haven't yet understood (and maybe will never understand) the
# list_pipe_xxxx.





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