From 914b0febf77c91ae7f20d098f62a5feefc1acdc3 Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Sat, 11 May 2024 12:11:43 +0200 Subject: [PATCH 1/2] libutil: remove the interrupt-blocking code The interrupt-blocking code was originally introduced 20 years ago so that trying to log an error message does not result in an interrupt exception being thrown and then going unhandled (c8d3882cdc8f9e22c58af285c1996265c1af75d5). However, the logging code does not check for interrupts any more (054be5025762c5e1c7e853c4fa5d7eed8da1727f), so this reasoning is no longer applicable. Delete this code so that later interrupts are unblocked again, for example in the next line entered into the repl. Closes: https://git.lix.systems/lix-project/lix/issues/296 Change-Id: I48253f5f4272e75001148c13046e709ef5427fbd --- doc/manual/rl-next/repl-interrupt.md | 8 ++++++++ src/libmain/shared.cc | 11 +---------- src/libutil/signals.cc | 9 +-------- src/libutil/signals.hh | 2 -- 4 files changed, 10 insertions(+), 20 deletions(-) create mode 100644 doc/manual/rl-next/repl-interrupt.md diff --git a/doc/manual/rl-next/repl-interrupt.md b/doc/manual/rl-next/repl-interrupt.md new file mode 100644 index 000000000..61a8ab71e --- /dev/null +++ b/doc/manual/rl-next/repl-interrupt.md @@ -0,0 +1,8 @@ +--- +synopsis: Interrupting builds in the REPL works more than once +cls: 1097 +--- + +Builds in the REPL can be interrupted by pressing Ctrl+C. +Previously, this only worked once per REPL session; further attempts would be ignored. +This issue is now fixed, so that builds can be canceled consistently. diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 9d4dd41ed..96ecbac8f 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -320,16 +320,7 @@ int handleExceptions(const std::string & programName, std::function fun) std::string error = ANSI_RED "error:" ANSI_NORMAL " "; try { - try { - fun(); - } catch (...) { - /* Subtle: we have to make sure that any `interrupted' - condition is discharged before we reach printMsg() - below, since otherwise it will throw an (uncaught) - exception. */ - setInterruptThrown(); - throw; - } + fun(); } catch (Exit & e) { return e.status; } catch (UsageError & e) { diff --git a/src/libutil/signals.cc b/src/libutil/signals.cc index f5c79b325..41fdc9dc8 100644 --- a/src/libutil/signals.cc +++ b/src/libutil/signals.cc @@ -9,21 +9,14 @@ namespace nix { std::atomic _isInterrupted = false; -static thread_local bool interruptThrown = false; thread_local std::function interruptCheck; -void setInterruptThrown() -{ - interruptThrown = true; -} - void _interrupted() { /* Block user interrupts while an exception is being handled. Throwing an exception while another exception is being handled kills the program! */ - if (!interruptThrown && !std::uncaught_exceptions()) { - interruptThrown = true; + if (!std::uncaught_exceptions()) { throw Interrupted("interrupted by the user"); } } diff --git a/src/libutil/signals.hh b/src/libutil/signals.hh index c58dc37cf..71593df95 100644 --- a/src/libutil/signals.hh +++ b/src/libutil/signals.hh @@ -22,8 +22,6 @@ extern std::atomic _isInterrupted; extern thread_local std::function interruptCheck; -void setInterruptThrown(); - void _interrupted(); void inline checkInterrupt() From eeb7e718101fbc5c53d3e070d8987e468047d804 Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Sun, 12 May 2024 16:24:34 +0200 Subject: [PATCH 2/2] repl: clear the interrupt before reading the next line Otherwise, it will be thrown again during exit when the repl is terminated by end-of-input after the last command was interrupted. Change-Id: I8456c47bc36cfb0892efdad5420f318f7e6526d5 --- src/libcmd/repl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 696bb3c12..34de2160a 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -262,6 +262,8 @@ ReplExitStatus NixRepl::mainLoop() std::string input; while (true) { + _isInterrupted = false; + // When continuing input from previous lines, don't print a prompt, just align to the same // number of chars as the prompt. if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) { @@ -424,8 +426,6 @@ ProcessLineResult NixRepl::processLine(std::string line) if (line.empty()) return ProcessLineResult::PromptAgain; - _isInterrupted = false; - std::string command, arg; if (line[0] == ':') {