mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-14 17:07:44 +00:00
Be more disciplined about cancellation signals
Rather than storing a "should cancel" flag in the parser, store the actual signal which triggered cancellation.
This commit is contained in:
parent
a7442207c2
commit
7e1270ae70
6 changed files with 20 additions and 22 deletions
|
@ -189,7 +189,7 @@ maybe_t<eval_result_t> parse_execution_context_t::check_end_execution() const {
|
|||
if (shell_is_exiting()) {
|
||||
return eval_result_t::cancelled;
|
||||
}
|
||||
if (parser && parser->cancellation_requested) {
|
||||
if (parser && parser->cancellation_signal) {
|
||||
return eval_result_t::cancelled;
|
||||
}
|
||||
const auto &ld = parser->libdata();
|
||||
|
@ -643,7 +643,7 @@ eval_result_t parse_execution_context_t::report_error(const parse_node_t &node,
|
|||
}
|
||||
|
||||
eval_result_t parse_execution_context_t::report_errors(const parse_error_list_t &error_list) const {
|
||||
if (!parser->cancellation_requested) {
|
||||
if (!parser->cancellation_signal) {
|
||||
if (error_list.empty()) {
|
||||
FLOG(error, L"Error reported but no error text found.");
|
||||
}
|
||||
|
|
|
@ -102,10 +102,9 @@ parser_t &parser_t::principal_parser() {
|
|||
return *principal;
|
||||
}
|
||||
|
||||
void parser_t::skip_all_blocks() {
|
||||
// Tell all blocks to skip.
|
||||
// This may be called from a signal handler!
|
||||
principal->cancellation_requested = true;
|
||||
void parser_t::cancel_requested(int sig) {
|
||||
assert(sig != 0 && "Signal must not be 0");
|
||||
principal->cancellation_signal = sig;
|
||||
}
|
||||
|
||||
// Given a new-allocated block, push it onto our block list, acquiring ownership.
|
||||
|
@ -648,11 +647,11 @@ eval_result_t parser_t::eval_node(const parsed_source_ref_t &ps, tnode_t<T> node
|
|||
// Handle cancellation requests. If our block stack is currently empty, then we already did
|
||||
// successfully cancel (or there was nothing to cancel); clear the flag. If our block stack is
|
||||
// not empty, we are still in the process of cancelling; refuse to evaluate anything.
|
||||
if (this->cancellation_requested) {
|
||||
if (this->cancellation_signal) {
|
||||
if (!block_list.empty()) {
|
||||
return eval_result_t::cancelled;
|
||||
}
|
||||
this->cancellation_requested = false;
|
||||
this->cancellation_signal = 0;
|
||||
}
|
||||
|
||||
// Only certain blocks are allowed.
|
||||
|
|
|
@ -201,8 +201,8 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
|
|||
friend class parse_execution_context_t;
|
||||
|
||||
private:
|
||||
/// Indication that we should skip all blocks.
|
||||
volatile sig_atomic_t cancellation_requested = false;
|
||||
/// If not zero, the signal triggering cancellation.
|
||||
volatile sig_atomic_t cancellation_signal = 0;
|
||||
/// The current execution context.
|
||||
std::unique_ptr<parse_execution_context_t> execution_context;
|
||||
/// The jobs associated with this parser.
|
||||
|
@ -248,9 +248,8 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
|
|||
/// Get the "principal" parser, whatever that is.
|
||||
static parser_t &principal_parser();
|
||||
|
||||
/// Indicates that execution of all blocks in the principal parser should stop. This is called
|
||||
/// from signal handlers!
|
||||
static void skip_all_blocks();
|
||||
/// Indicates that we should stop execution due to the given signal.
|
||||
static void cancel_requested(int sig);
|
||||
|
||||
/// Global event blocks.
|
||||
event_blockage_list_t global_event_blocks;
|
||||
|
|
|
@ -249,7 +249,7 @@ static void handle_child_status(process_t *proc, proc_status_t status) {
|
|||
if (session_interactivity() != session_interactivity_t::not_interactive) {
|
||||
// In an interactive session, tell the principal parser to skip all blocks we're
|
||||
// executing so control-C returns control to the user.
|
||||
parser_t::skip_all_blocks();
|
||||
parser_t::cancel_requested(sig);
|
||||
} else {
|
||||
// Deliver the SIGINT or SIGQUIT signal to ourself since we're not interactive.
|
||||
struct sigaction act;
|
||||
|
|
|
@ -489,7 +489,7 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
void remove_backward();
|
||||
};
|
||||
|
||||
/// This variable is set to true by the signal handler when ^C is pressed.
|
||||
/// This variable is set to a signal by the signal handler when ^C is pressed.
|
||||
static volatile sig_atomic_t interrupted = 0;
|
||||
|
||||
// Prototypes for a bunch of functions defined later on.
|
||||
|
@ -686,8 +686,8 @@ void reader_data_t::kill(editable_line_t *el, size_t begin_idx, size_t length, i
|
|||
|
||||
// This is called from a signal handler!
|
||||
void reader_handle_sigint() {
|
||||
parser_t::skip_all_blocks();
|
||||
interrupted = 1;
|
||||
parser_t::cancel_requested(SIGINT);
|
||||
interrupted = SIGINT;
|
||||
}
|
||||
|
||||
/// Make sure buffers are large enough to hold the current string length.
|
||||
|
@ -849,12 +849,12 @@ bool reader_test_should_cancel() {
|
|||
}
|
||||
}
|
||||
|
||||
bool reader_test_and_clear_interrupted() {
|
||||
int reader_test_and_clear_interrupted() {
|
||||
int res = interrupted;
|
||||
if (res) {
|
||||
interrupted = 0;
|
||||
}
|
||||
return res != 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
void reader_write_title(const wcstring &cmd, parser_t &parser, bool reset_cursor_position) {
|
||||
|
@ -3411,7 +3411,7 @@ int reader_reading_interrupted() {
|
|||
reader_data_t *data = current_data_or_null();
|
||||
if (res && data && data->exit_on_interrupt) {
|
||||
reader_set_end_loop(true);
|
||||
parser_t::skip_all_blocks();
|
||||
parser_t::cancel_requested(res);
|
||||
// We handled the interrupt ourselves, our caller doesn't need to handle it.
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -121,8 +121,8 @@ bool reader_get_selection(size_t *start, size_t *len);
|
|||
bool reader_test_should_cancel();
|
||||
|
||||
/// Return the value of the interrupted flag, which is set by the sigint handler, and clear it if it
|
||||
/// was set.
|
||||
bool reader_test_and_clear_interrupted();
|
||||
/// was set. In practice this will return 0 or SIGINT.
|
||||
int reader_test_and_clear_interrupted();
|
||||
|
||||
/// Clear the interrupted flag unconditionally without handling anything. The flag could have been
|
||||
/// set e.g. when an interrupt arrived just as we were ending an earlier \c reader_readline
|
||||
|
|
Loading…
Reference in a new issue