Re: [PATCH v4] Allow trap to un-ignore SIGINT/SIGQUIT in async subshells
Herbert Xu <[email protected]>
| Newsgroups | org.kernel.vger.dash |
|---|---|
| Message-ID | <[email protected]> |
On Sat, May 18, 2024 at 10:38:30AM +0200, Johannes Altmanninger wrote:
> Unlike in Bash or Zsh, this asynchronous job ignores SIGINT, despite
> builtin trap explicitly resetting the SIGINT handler.
>
> dash -c '( trap - INT; sleep inf ) & read _'
>
> POSIX Section 2.11 on [Signals] and Error Handling says about
> background execution:
>
> > If job control is disabled (see the description of set -m) when
> > the shell executes an asynchronous list, the commands in the list
> > shall inherit from the shell a signal action of ignored (SIG_IGN)
> > for the SIGINT and SIGQUIT signals.
>
> Builtin [trap] has this requirement:
>
> > Signals that were ignored on entry to a non-interactive shell
> > cannot be trapped or reset, although no error need be reported when
> > attempting to do so.
>
> Apparently this only applies to signals that were inherited as ignored,
> not to the special case of SIGINT/SIGQUIT begin ignored in asynchronous
> subshells.
>
> Make it so. This means that either of
>
> trap - INT; trap - QUIT
> set -i
>
> in a backgrounded subshell will now un-ignore SIGINT and SIGQUIT.
>
> [Signals]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
> [trap]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap
>
> {{{ Test cases:
>
> shell=src/dash
>
> set -e
>
> SubshellWith() {
> parent_pid=$(setsid "$shell" -c "( $1; sleep 99 ) </dev/null >/dev/null 2>&1 & echo \$\$")
> sleep 1
> subshell_pid=$(ps -o pid= -$parent_pid | tail -n 1)
> }
>
> trap 'kill -TERM -$parent_pid 2>/dev//null ||:' EXIT # Tear down after a failure.
>
> echo Scenario 0: '"set -i"' makes a subshell un-ignore SIGINT.
> SubshellWith 'set -i'
> kill -INT $subshell_pid
> ! ps -p $subshell_pid | grep sleep || exit 1
> kill -TERM -$parent_pid 2>/dev//null ||: # Tear down.
>
> echo Scenario 1: resetting SIGINT handler.
> SubshellWith 'trap - INT'
> kill -INT -$parent_pid # kill the whole process group since that's the my use case
> ! ps -p $subshell_pid | grep sleep || exit 1
> kill -TERM -$parent_pid 2>/dev//null ||: # Tear down.
>
> echo Scenario 2: ignoring SIGINT.
> SubshellWith 'trap "" INT'
> kill -INT $subshell_pid
> ps -p $subshell_pid | grep sleep || exit 1
> kill -TERM -$parent_pid 2>/dev//null ||: # Tear down.
>
> }}}
>
> {{{ Backstory/motivation:
>
> The Kakoune[1] editor likes to run noninteractive shell commands that
> boil down to
>
> mkfifo /tmp/fifo
> (
> trap - INT
> make
> ) >/tmp/fifo 2>&1 &
>
> On Control-C, the editor sends SIGINT to its process group,
> which should terminate the subshell running make[2].
>
> We experimented with sending SIGTERM instead but found issues,
> specifically if the editor is invoked (without exec) from a wrapper
> script, sending SIGTERM to the whole process group would kill the
> wrapper script, which in turn makes it send SIGTERM to the editor,
> which then terminates.
>
> [1]: https://kakoune.org/
> [2]: https://lists.sr.ht/~mawww/kakoune/%[email protected]%3E
>
> }}}
> ---
> src/trap.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
Patch applied. Thanks.
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt