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

Functions registered with zle -F stop being run after a job finishes



Hi,

tl;dr: There appears to be a bug in zsh. When a background job finishes,
functions registered with zle -F stop running until the user presses a key
(say, [enter] or [esc]) or the shell receives a signal (any signal at all).

Assuming the pristine environment granted by zsh -df, consider the
following piece of code.

mkfifo /tmp/fifoexec {fd}<>/tmp/fifo
( for ((i=1;;++i)); do sleep 1; echo $i; done ) >&$fd &
function f() { zle -I && read -eu $fd }
zle -F $fd f
sleep 5&
( sleep 10; kill -WINCH $$ ) &

It creates a fifo, to which a background job writes consecutive numbers
once a second. It then uses zle -F to register a function that gets called
whenever there is something in the fifo. The function reads and prints the
content of the fifo.

This part of the code produces the following output:

adam%
1
adam%
2
adam%
3

And so on, with one line every second. The code also creates a background
job that doesn’t do anything and finishes after 5 seconds. The expected
behavior is that we’ll keep seeing consecutive numbers on the screen after
this job finishes but that’s not what happens. In fact, the output stops.

adam%
4
adam%
[2]  + done       sleep 5
adam%

If we hit [esc] or [enter] at this point, the missing numbers will appear
all at once and the new numbers will continue being printed once a second.

Instead of pressing a key we can send our shell a signal. It’ll have the
same effect. Any signal will do as long as it doesn’t kill the process. For
example, we can define a signal handler for SIGUSR1 and execute kill -USR1
$pid from another shell. Or, like the code snippet does, we can send
SIGWINCH, taking advantage of its having the default handler that does
nothing.

Here’s the complete output where you can see everything in action:

adam% mkfifo /tmp/fifo
exec {fd}<>/tmp/fifo
( for ((i=1;;++i)); do sleep 1; echo $i; done ) >&$fd &
function f() { zle -I && read -eu $fd }
zle -F $fd f
sleep 5&
( sleep 10; kill -WINCH $$ ) &
[1] 9468
[2] 9469
[3] 9471
adam%
1
adam%
2
adam%
3
adam%
4
adam%
[2]  - done       sleep 5
adam%
5
[3]  + done       ( sleep 10; kill -WINCH $$; )
adam% adam%
6
adam%
7
adam%
8
adam%
9
adam%
10
adam%
11
adam%
12
adam%

And so on.

Roman.


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