From 7ed1022cf41cd1b0111a7c280528324527fc8570 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 26 May 2019 18:04:03 -0700 Subject: [PATCH] Latch signal handlers Now that our interactive signal handlers are a strict superset of non-interactive ones, there is no reason to "reset" signals or take action when becoming non-interactive. Clean up how signal handlers get installed. --- src/fish_tests.cpp | 2 +- src/proc.cpp | 5 +---- src/reader.cpp | 2 +- src/signal.cpp | 12 ++++++++++-- src/signal.h | 8 +++++++- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index b993e2386..3c99e2c56 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -1012,7 +1012,7 @@ static void test_cancellation() { // Enable fish's signal handling here. We need to make this interactive for fish to install its // signal handlers. proc_push_interactive(1); - signal_set_handlers(); + signal_set_handlers(true); // This tests that we can correctly ctrl-C out of certain loop constructs, and that nothing gets // printed if we do. diff --git a/src/proc.cpp b/src/proc.cpp index 302d33520..9df9fa3fa 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -942,18 +942,15 @@ void proc_sanity_check(const parser_t &parser) { void proc_push_interactive(int value) { ASSERT_IS_MAIN_THREAD(); - int old = is_interactive; interactive_stack.push_back(is_interactive); is_interactive = value; - if (old != value) signal_set_handlers(); + signal_set_handlers_once(is_interactive); } void proc_pop_interactive() { ASSERT_IS_MAIN_THREAD(); - int old = is_interactive; is_interactive = interactive_stack.back(); interactive_stack.pop_back(); - if (is_interactive != old) signal_set_handlers(); } void proc_wait_any(parser_t &parser) { diff --git a/src/reader.cpp b/src/reader.cpp index 10f9ee04e..bdefa3e6e 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1738,7 +1738,7 @@ static void reader_interactive_init() { } } - signal_set_handlers(); + signal_set_handlers(shell_is_interactive()); } // It shouldn't be necessary to place fish in its own process group and force control diff --git a/src/signal.cpp b/src/signal.cpp index 946961454..117cf1343 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -325,7 +325,7 @@ static void set_interactive_handlers() { } /// Sets up appropriate signal handlers. -void signal_set_handlers() { +void signal_set_handlers(bool interactive) { struct sigaction act; act.sa_flags = 0; sigemptyset(&act.sa_mask); @@ -354,11 +354,19 @@ void signal_set_handlers() { FATAL_EXIT(); } - if (shell_is_interactive()) { + if (interactive) { set_interactive_handlers(); } } +void signal_set_handlers_once(bool interactive) { + static std::once_flag s_noninter_once; + std::call_once(s_noninter_once, signal_set_handlers, false); + + static std::once_flag s_inter_once; + if (interactive) std::call_once(s_inter_once, set_interactive_handlers); +} + void signal_handle(int sig, int do_handle) { struct sigaction act; diff --git a/src/signal.h b/src/signal.h index be0011203..3aa8316f6 100644 --- a/src/signal.h +++ b/src/signal.h @@ -17,7 +17,13 @@ const wchar_t *signal_get_desc(int sig); void signal_reset_handlers(); /// Set signal handlers to fish default handlers. -void signal_set_handlers(); +/// If \p interactive is set, apply interactive handlers as well. +/// Note interactive handlers, once applied, are not cleared; they are a strict superset of +/// non-interactive handlers. +void signal_set_handlers(bool interactive); + +/// Latch function. This sets signal handlers, but only the first time it is called. +void signal_set_handlers_once(bool interactive); /// Tell fish what to do on the specified signal. ///