zsh-workers
 help / color / mirror / code / Atom feed
* Possible bug in signal handling
@ 2015-11-02 10:10 Dima Kogan
  2015-11-04  4:16 ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Dima Kogan @ 2015-11-02 10:10 UTC (permalink / raw)
  To: zsh-workers

Hi. I'm seeing a suspicious behavior in zsh that isn't present in bash
or dash. I'm not 100% sure the way this is supposed to work, so maybe
zsh is still correct here, but filing this report just in case.

The behavior is concerned with the user invoking a pipeline in zsh, then
hitting Ctrl-C to kill it. One of the processes in the pipeline
overrides SIGINT to ignore the first Ctrl-C; I would expect all the
processes in the pipeline to die at the first Ctrl-C, except the
overriding process. I would expect zsh to recognize the one still-alive
process, and to not put up another prompt. When the user hits Ctrl-C a
second time, the overriding process dies in response, and zsh should
detect this, and prompt for a new command. This does happen most of the
time in zsh, but I'm hitting a case where it doesn't:

I have a /tmp/tst.sh script:

   awk '{print; fflush()}' | \
       perl -e 'BEGIN { $SIG{INT} = sub { $SIG{INT} = undef; }; } while(<>) {sleep 1;} sleep 10000;'

This script has a pass-through awk feeding a perl command that overrides
SIGINT, and ignores the first SIGINT that comes in.

I invoke this script thusly:

$ seq 5000 | perl -nE 'say "xxx"; sleep(1)' | zsh /tmp/tst.sh

So it's a mostly do-nothing pipeline. When the user hits Ctrl-C the
first time, I expect everything but the inner zsh and the inner perl
processes to die, and the outer zsh to NOT display another prompt until
a second Ctrl-C. Instead I see everything except the inner perl die
(inner zsh dies too), and the prompt is returned immediately. This
effectively disowns the inner perl, so it cannot be killed
interactively.

If I replace the inner zsh with bash or dash, things work the way I
expect. Things also work the way I expect if I get rid of the awk or if
I get rid of the inner zsh, putting the whole pipeline on the
commandline.

Is this a zsh bug? If not a bug, can this be made to work the way I
expect it to?

Thanks! This is a bit convoluted, but hopefully it was clear enough.

dima


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Possible bug in signal handling
  2015-11-02 10:10 Possible bug in signal handling Dima Kogan
@ 2015-11-04  4:16 ` Bart Schaefer
  2015-11-04  4:27   ` Dima Kogan
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2015-11-04  4:16 UTC (permalink / raw)
  To: zsh-workers

On Nov 2,  2:10am, Dima Kogan wrote:
}
} I have a /tmp/tst.sh script:
} 
}    awk '{print; fflush()}' | \
}        perl -e 'BEGIN { $SIG{INT} = sub { $SIG{INT} = undef; }; } while(<>) {sleep 1;} sleep 10000;'
} 
} I invoke this script thusly:
} 
} $ seq 5000 | perl -nE 'say "xxx"; sleep(1)' | zsh /tmp/tst.sh
} 
} So it's a mostly do-nothing pipeline. When the user hits Ctrl-C the
} first time, I expect everything but the inner zsh and the inner perl
} processes to die, and the outer zsh to NOT display another prompt until
} a second Ctrl-C. Instead I see everything except the inner perl die
} (inner zsh dies too), and the prompt is returned immediately.

I'm able to get bash to orphan that perl process sometimes, too, just
not reliably.

The difference seems to be that bash calls waitpid() whereas zsh uses
sigpause() and doesn't do the wait*() until the SIGCHLD arrives.  The
order of arrival of the CHLD and INT signals may therefore determine
whether the shell continues waiting or not.

Changing the script to this --

   trap '' INT
   { trap - INT; awk '{print; fflush()}'; } | \
          perl -e 'BEGIN { $g = getpgrp($$); print "$g\n"; $SIG{INT} = sub {
$SIG{INT} = undef; }; } while(<>)
          {sleep 1;} sleep 10000;'

-- gets both shells to wait for perl to exit before the script exits.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Possible bug in signal handling
  2015-11-04  4:16 ` Bart Schaefer
@ 2015-11-04  4:27   ` Dima Kogan
  2015-11-04  4:46     ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Dima Kogan @ 2015-11-04  4:27 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

Bart Schaefer <schaefer@brasslantern.com> writes:

> On Nov 2,  2:10am, Dima Kogan wrote:
> }
> } I have a /tmp/tst.sh script:
> } 
> }    awk '{print; fflush()}' | \
> }        perl -e 'BEGIN { $SIG{INT} = sub { $SIG{INT} = undef; }; } while(<>) {sleep 1;} sleep 10000;'
> } 
> } I invoke this script thusly:
> } 
> } $ seq 5000 | perl -nE 'say "xxx"; sleep(1)' | zsh /tmp/tst.sh
> } 
> } So it's a mostly do-nothing pipeline. When the user hits Ctrl-C the
> } first time, I expect everything but the inner zsh and the inner perl
> } processes to die, and the outer zsh to NOT display another prompt until
> } a second Ctrl-C. Instead I see everything except the inner perl die
> } (inner zsh dies too), and the prompt is returned immediately.
>
> I'm able to get bash to orphan that perl process sometimes, too, just
> not reliably.
>
> The difference seems to be that bash calls waitpid() whereas zsh uses
> sigpause() and doesn't do the wait*() until the SIGCHLD arrives.  The
> order of arrival of the CHLD and INT signals may therefore determine
> whether the shell continues waiting or not.
>
> Changing the script to this --
>
>    trap '' INT
>    { trap - INT; awk '{print; fflush()}'; } | \
>           perl -e 'BEGIN { $g = getpgrp($$); print "$g\n"; $SIG{INT} = sub {
> $SIG{INT} = undef; }; } while(<>)
>           {sleep 1;} sleep 10000;'
>
> -- gets both shells to wait for perl to exit before the script exits.

Thanks for looking at this, Bart. I don't really understand this area in
detail, but should those changes be necessary? Is it not a bug in zsh
(and bash, I guess) that the perl process is orphaned?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Possible bug in signal handling
  2015-11-04  4:27   ` Dima Kogan
@ 2015-11-04  4:46     ` Bart Schaefer
  2015-11-04 14:25       ` Vincent Lefevre
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2015-11-04  4:46 UTC (permalink / raw)
  To: Dima Kogan, zsh-workers

On Nov 3,  8:27pm, Dima Kogan wrote:
}
} Thanks for looking at this, Bart. I don't really understand this area in
} detail, but should those changes be necessary? Is it not a bug in zsh
} (and bash, I guess) that the perl process is orphaned?

That's unclear.  The default response to SIGINT is supposed to be that
the process exits, not that it only exits if it has children that have
not yet exited.  If someone wants to pore over the POSIX spec and point
out where it says that rule is countermanded for the shell, go for it.
Otherwise I'd say it's up to the script to change the signal handling
away from the default.

You could also fix it by using "exec perl ..." which in zsh removes the
"inner zsh" from the process tree entirely (in that particular example;
more generally, "exec" the rightmost thing in the pipeline).


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Possible bug in signal handling
  2015-11-04  4:46     ` Bart Schaefer
@ 2015-11-04 14:25       ` Vincent Lefevre
  2015-11-04 19:01         ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Vincent Lefevre @ 2015-11-04 14:25 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Dima Kogan, zsh-workers

On 2015-11-03 20:46:34 -0800, Bart Schaefer wrote:
> That's unclear.  The default response to SIGINT is supposed to be that
> the process exits, not that it only exits if it has children that have
> not yet exited.

I suppose you meant "if it does not have children...". You're thinking
about IUE (implemented by zsh, unless this has changed in the last few
years), while WCE (implemented by bash) is generally regarded to be
better:

  http://www.cons.org/cracauer/sigint.html

Dima's example may be more complex.

> If someone wants to pore over the POSIX spec and point out where it
> says that rule is countermanded for the shell, go for it.

I don't think that POSIX covers that, otherwise one wouldn't have
the above differences between POSIX shells.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Possible bug in signal handling
  2015-11-04 14:25       ` Vincent Lefevre
@ 2015-11-04 19:01         ` Bart Schaefer
  0 siblings, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2015-11-04 19:01 UTC (permalink / raw)
  To: zsh-workers

On Nov 4,  3:25pm, Vincent Lefevre wrote:
} Subject: Re: Possible bug in signal handling
}
} I suppose you meant "if it does not have children...".

Yes.

} You're thinking about IUE (implemented by zsh, unless this has changed
} in the last few years), while WCE (implemented by bash) is generally
} regarded to be better:
} 
}   http://www.cons.org/cracauer/sigint.html

What zsh does depends on context.  The simple example in that web page
(emacs ...; cp ...) behaves like WCE if emacs opens the terminal, but
behaves like WUE if emacs runs in GUI mode.  For a process at the end
of a pipeline like Dima's original example, zsh does IUE.  Interactive
shells with shinstdin (e.g. not reading a script file) also do W?E.

Most of the time a zsh script is going to perform IUE and an interactive
shell WCE, because that's how we interpreted the "inherited from parent"
signal handling was required to behave.


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-11-04 19:01 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-02 10:10 Possible bug in signal handling Dima Kogan
2015-11-04  4:16 ` Bart Schaefer
2015-11-04  4:27   ` Dima Kogan
2015-11-04  4:46     ` Bart Schaefer
2015-11-04 14:25       ` Vincent Lefevre
2015-11-04 19:01         ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).