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

zsh sends SIGCONT to processes that are not suspended



Hello,

I went down the rabbit hole trying to understand why the output
of several concurrent "pv -c" invocations ended up garbled when
run from zsh.

Turned out "pv -c" "re-inits" its cursor positionning handling
upon receiving SIGCONT assuming it has been resumed from
suspend.

While one may argue that pv should check it has been suspended
in the first place (not sure how one would do that reliably
though as SIGSTOP can't be handled), one could also argue that
zsh should not send SIGCONT to non-suspended processes.

Minimum reproducer:

First, create a "report-sigcont" script such as:


#! /usr/bin/perl
use Time::HiRes qw(sleep time);
$start = time; $t = $ARGV[0] // 1;
$SIG{CONT} = sub {
  printf STDERR "[%g] Got SIGCONT after %g seconds\n", $t, time - $start
};
sleep $t;
close STDOUT;
sleep 0.1;

Then:

$ zsh -c '(report-sigcont 1|cat);:'
[1] Got SIGCONT after 1.00086 seconds

gdb backtrace has:

#0  __GI_kill () at ../sysdeps/unix/syscall-template.S:120
#1  0x0000555555610ccb in killjb (jn=0x55555566a4b0, sig=18) at signals.c:601
#2  0x00005555555c5ca5 in zwaitjob (job=2, wait_cmd=0) at jobs.c:1730
#3  0x00005555555c5f81 in waitonejob (jn=0x55555566a4b0) at jobs.c:1751
#4  0x00005555555c602c in waitjobs () at jobs.c:1771
#5  0x0000555555593503 in execpline (state=0x7fffffffd930, slcode=8194, how=18, last1=1) at exec.c:1841
#6  0x0000555555591ed9 in execlist (state=0x7fffffffd930, dont_change_job=0, exiting=1) at exec.c:1498
#7  0x000055555559b6ef in execcmd_exec (state=0x7fffffffd930, eparams=0x7fffffffd530, input=0, output=0, how=2, last1=2, close_if_forked=-1) at exec.c:4352
#8  0x000055555559460e in execpline2 (state=0x7fffffffd930, pcode=131, how=2, input=0, output=0, last1=0) at exec.c:2020
#9  0x0000555555592ddc in execpline (state=0x7fffffffd930, slcode=19458, how=2, last1=0) at exec.c:1745
#10 0x0000555555591ed9 in execlist (state=0x7fffffffd930, dont_change_job=0, exiting=1) at exec.c:1498
#11 0x0000555555591578 in execode (p=0x7ffff7fb9a88, dont_change_job=0, exiting=1, context=0x555555639a35 "cmdarg") at exec.c:1279
#12 0x000055555559144f in execstring (s=0x7fffffffdee3 "(echo; report-sigcont 1|cat);:", dont_change_job=0, exiting=1, context=0x555555639a35 "cmdarg")
    at exec.c:1245
#13 0x00005555555bdab1 in init_misc (cmd=0x7fffffffdee3 "(echo; report-sigcont 1|cat);:", zsh_name=0x7fffffffdedc "zsh") at init.c:1543
#14 0x00005555555bf2a5 in zsh_main (argc=3, argv=0x7fffffffdb48) at init.c:1924
#15 0x000055555556bd69 in main (argc=3, argv=0x7fffffffdb48) at ./main.c:93

And zwaitjob does have:

            if (subsh)
                killjb(jn, SIGCONT);

there indeed, but I can't really judge whether/when it may make
sense or not to do that..

With that particular example, as a work around, I could do:

zsh -c '((report-sigcont 1;:)|cat);:'

When the extra subshell layer shields "report-sigcont" from the
SIGCONT and also here makes sure cat exits after that subshell.

Kind regards,
Stephane




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