* Why does zsh un-ignores SIGQUIT? @ 2019-04-24 8:13 Stephane Chazelas 2019-04-24 16:13 ` Peter Stephenson 0 siblings, 1 reply; 5+ messages in thread From: Stephane Chazelas @ 2019-04-24 8:13 UTC (permalink / raw) To: Zsh hackers list $ (trap '' QUIT; grep SigIgn /proc/self/status; ./Src/zsh -c 'grep SigIgn /proc/self/status') SigIgn: 0000000000000004 SigIgn: 0000000000000000 That only seems to be happening for SIGQUIT. (that's from the current git HEAD) -- Stephane ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Why does zsh un-ignores SIGQUIT? 2019-04-24 8:13 Why does zsh un-ignores SIGQUIT? Stephane Chazelas @ 2019-04-24 16:13 ` Peter Stephenson 2019-04-25 21:17 ` Stephane Chazelas 0 siblings, 1 reply; 5+ messages in thread From: Peter Stephenson @ 2019-04-24 16:13 UTC (permalink / raw) To: zsh-workers On Wed, 2019-04-24 at 09:13 +0100, Stephane Chazelas wrote: > $ (trap '' QUIT; grep SigIgn /proc/self/status; ./Src/zsh -c 'grep SigIgn /proc/self/status') > SigIgn: 0000000000000004 > SigIgn: 0000000000000000 > > That only seems to be happening for SIGQUIT. > > (that's from the current git HEAD) SIGQUIT is ignored internally within the shell, visible below the patched code. The shell knows if you've explicitly ignored SIGQUIT, but not if it's ignored by inheritance when the shell starts. The flag is tested in entersubsh(). pws diff --git a/Src/init.c b/Src/init.c index e7e62e2f7..2d5c3296d 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1234,6 +1234,15 @@ init_signals(void) intr(); +#ifdef POSIX_SIGNALS + { + struct sigaction act; + if (!sigaction(SIGQUIT, NULL, &act) && + act.sa_handler == SIG_IGN) + sigtrapped[SIGQUIT] = ZSIG_IGNORED; + } +#endif + #ifndef QDEBUG signal_ignore(SIGQUIT); #endif ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Why does zsh un-ignores SIGQUIT? 2019-04-24 16:13 ` Peter Stephenson @ 2019-04-25 21:17 ` Stephane Chazelas 2019-04-26 13:42 ` Peter Stephenson 0 siblings, 1 reply; 5+ messages in thread From: Stephane Chazelas @ 2019-04-25 21:17 UTC (permalink / raw) To: Peter Stephenson; +Cc: zsh-workers 2019-04-24 17:13:51 +0100, Peter Stephenson: > On Wed, 2019-04-24 at 09:13 +0100, Stephane Chazelas wrote: > > $ (trap '' QUIT; grep SigIgn /proc/self/status; ./Src/zsh -c 'grep SigIgn /proc/self/status') > > SigIgn: 0000000000000004 > > SigIgn: 0000000000000000 > > > > That only seems to be happening for SIGQUIT. > > > > (that's from the current git HEAD) > > SIGQUIT is ignored internally within the shell, visible below the patched > code. The shell knows if you've explicitly ignored SIGQUIT, but not if > it's ignored by inheritance when the shell starts. The flag is tested > in entersubsh(). [...patch skipped...] Thanks, that change seems to introduce a new inconsistency though. See below. POSIX does require that signals that were ignored upon startup of the shell remain ignored. POSIX> Signals that were ignored on entry to a non-interactive POSIX> shell cannot be trapped or reset, although no error need POSIX> be reported when attempting to do so. An interactive POSIX> shell may reset or catch signals ignored on entry. zsh, thankfully ignores that requirement. That's an annoying requirement that probably has its origin on systems that didn't have terminal job control (tcsetpgrp()...) and is usually a nuisance today. In zsh trap handler INT Installs the "handler" on SIGINT even if SIGINT was ignored on startup. What I found out recently though (https://unix.stackexchange.com/questions/513781/regain-ability-to-use-c-to-close-backgrounded-then-effectively-foregrounded-p/515159#515159) is that it does seem to honour the POSIX requirement when it comes to "resetting" the signal disposition (to its default). In zsh trap - INT Does not reset the default signal disposition of SIGINT if SIGINT was ignored upon startup. $ (trap "" INT; zsh -c 'trap - INT; grep SigIgn /proc/self/status') SigIgn: 0000000000000002 One can work around that by setting a trap first: $ (trap "" INT; zsh -c 'trap : INT; trap - INT; grep SigIgn /proc/self/status') SigIgn: 0000000000000000 Even explicitely ignoring it will do: $ (trap "" INT; zsh -c 'trap "" INT; trap - INT; grep SigIgn /proc/self/status') SigIgn: 0000000000000000 Which brings us to this change, which means SIGQUIT is now treated specially in this regard: $ (trap "" INT QUIT; ./Src/zsh -c 'trap - INT QUIT; grep SigIgn /proc/self/status') SigIgn: 0000000000000002 (with the diff applied) I was able to reset the default handler for SIGQUIT but not for SIGINT. I wonder what the rationale is for why zsh will happily install a handler on an ignored signal but not reset to default. I can understand where the POSIX requirement is coming from. When you do myscript & on a system that doesn't have job control, you don't want processes started by the script to be killed when you press ^C. Or when you do: nohup myscript You want myscript and all the processes it spawns to be immune to hang-ups. But I don't understand why zsh would let me set a handler but not reset to default. It would make more sense to me if it was the reverse. If I want to reset the default handler without having set one in the first place, surely I know what I'm doing and what I ask should be honoured. Here, unless someone can think of a good reason why zsh behaves the way it does, I'd suggest zsh ignore the POSIX requirement altogether and honours what the user wants: apply the traps as requested regardless of whether the signal was ignored on startup or not, at least in zsh emulation. Maybe honour the POSIX requirements in sh emulation. While I'm at it, there's another related POSIX requirement that I often find annoying: In non-interactive shells. cmd & is meant to run cmd with SIGINT and SIGQUIT ignored (some form of crude and ancient uncalled for job control). That's actually more annoying than the other POSIX requirement mentioned earlier. When you do: (cmd1 & cmd2) | cmd3 There's no reason cmd1 should not also be killed by SIGINT when you press ^C. That's where being able to cancel that ignoring of SIGINT can come handy. zsh does honour that latter requirement though. What's the sentiment of zsh developer about potentially ignoring that POSIX requirement as well? What can that break? -- Stephane ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Why does zsh un-ignores SIGQUIT? 2019-04-25 21:17 ` Stephane Chazelas @ 2019-04-26 13:42 ` Peter Stephenson 2019-04-26 14:03 ` Peter Stephenson 0 siblings, 1 reply; 5+ messages in thread From: Peter Stephenson @ 2019-04-26 13:42 UTC (permalink / raw) To: zsh-workers On Thu, 2019-04-25 at 22:17 +0100, Stephane Chazelas wrote: > I wonder what the rationale is for why zsh will happily install a > handler on an ignored signal but not reset to default. I think it's simply this in the removetrap() code... trapped = sigtrapped[sig]; ... if (!trapped) { unqueue_signals(); return NULL; } If the signal was ignored on entry, it stays ignored (because that's down in the OS), but zsh doesn't mark it as handled specially. So when we get the request to unset it we execute this code, shrugging our shoulders and doing nothing. For SIGQUIT we now do mark it as handled specially. Instead of laboriously setting up records for all signals, maybe we could add a call to set the default signal handler in the "if" above? At worst that should have no effect, probably. pws ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Why does zsh un-ignores SIGQUIT? 2019-04-26 13:42 ` Peter Stephenson @ 2019-04-26 14:03 ` Peter Stephenson 0 siblings, 0 replies; 5+ messages in thread From: Peter Stephenson @ 2019-04-26 14:03 UTC (permalink / raw) To: zsh-workers On Fri, 2019-04-26 at 14:42 +0100, Peter Stephenson wrote: > On Thu, 2019-04-25 at 22:17 +0100, Stephane Chazelas wrote: > > > > I wonder what the rationale is for why zsh will happily install a > > handler on an ignored signal but not reset to default. > I think it's simply this in the removetrap() code... > > trapped = sigtrapped[sig]; > ... > if (!trapped) { > unqueue_signals(); > return NULL; > } > > If the signal was ignored on entry, it stays ignored (because that's > down in the OS), but zsh doesn't mark it as handled specially. So > when we get the request to unset it we execute this code, shrugging our > shoulders and doing nothing. For SIGQUIT we now do mark it as > handled specially. > > Instead of laboriously setting up records for all signals, maybe we > could add a call to set the default signal handler in the "if" above? > At worst that should have no effect, probably. Reading through, I think simply omitting that block should have the right effect --- all the specific internal effects later in the function are protected by their own "if"s, so this has the desired effect of only fixing up the OS state. I'm not going to commit this immediately. diff --git a/Src/signals.c b/Src/signals.c index f294049c2..14218177a 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -1011,10 +1011,6 @@ removetrap(int sig) (!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT))) dosavetrap(sig, locallevel); - if (!trapped) { - unqueue_signals(); - return NULL; - } if (sigtrapped[sig] & ZSIG_TRAPPED) nsigtrapped--; sigtrapped[sig] = 0; ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2019-04-26 14:03 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-04-24 8:13 Why does zsh un-ignores SIGQUIT? Stephane Chazelas 2019-04-24 16:13 ` Peter Stephenson 2019-04-25 21:17 ` Stephane Chazelas 2019-04-26 13:42 ` Peter Stephenson 2019-04-26 14:03 ` Peter Stephenson
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).