Switch the interrupt handler from a global to an instance variable

"The" interrupt handler is used when we get a signal while waiting at the
prompt. Switch it from a global function pointer to an std::function. This
is a mild refactoring which itself will be replaced soon.
This commit is contained in:
ridiculousfish 2021-04-06 20:01:32 -07:00
parent 060ce4f7da
commit 78147abe8a
4 changed files with 49 additions and 40 deletions

View file

@ -272,28 +272,6 @@ void input_mapping_set_t::add(wcstring sequence, const wchar_t *command, const w
input_mapping_set_t::add(std::move(sequence), &command, 1, mode, sets_mode, user);
}
/// Handle interruptions to key reading by reaping finished jobs and propagating the interrupt to
/// the reader.
static maybe_t<char_event_t> interrupt_handler() {
// Fire any pending events.
// TODO: eliminate this principal_parser().
auto &parser = parser_t::principal_parser();
event_fire_delayed(parser);
// Reap stray processes, including printing exit status messages.
// TODO: shouldn't need this parser here.
if (job_reap(parser, true)) reader_schedule_prompt_repaint();
// Tell the reader an event occurred.
if (reader_reading_interrupted()) {
auto vintr = shell_modes.c_cc[VINTR];
if (vintr == 0) {
return none();
}
return char_event_t{vintr};
}
return char_event_t{char_event_type_t::check_exit};
}
static relaxed_atomic_bool_t s_input_initialized{false};
/// Set up arrays used by readch to detect escape sequences for special keys and perform related
@ -303,7 +281,6 @@ void init_input() {
if (s_input_initialized) return;
s_input_initialized = true;
input_common_init(&interrupt_handler);
s_terminfo_mappings = create_input_terminfo();
auto input_mapping = input_mappings();
@ -338,7 +315,35 @@ void init_input() {
}
}
inputter_t::inputter_t(parser_t &parser, int in) : event_queue_(in), parser_(parser.shared()) {}
inputter_t::inputter_t(parser_t &parser, int in)
: parser_(parser.shared()), event_queue_(in, get_interrupt_handler()) {}
/// Handle interruptions to key reading by reaping finished jobs and propagating the interrupt to
/// the reader.
maybe_t<char_event_t> inputter_t::handle_interrupt() {
// Fire any pending events.
auto &parser = *this->parser_;
event_fire_delayed(parser);
// Reap stray processes, including printing exit status messages.
if (job_reap(parser, true)) reader_schedule_prompt_repaint();
// Tell the reader an event occurred.
if (reader_reading_interrupted()) {
auto vintr = shell_modes.c_cc[VINTR];
if (vintr == 0) {
return none();
}
return char_event_t{vintr};
}
return char_event_t{char_event_type_t::check_exit};
}
interrupt_handler_t inputter_t::get_interrupt_handler() {
// It's OK to capture 'this' by value because we use this to populate one of our instance
// variables.
interrupt_handler_t func = [this] { return this->handle_interrupt(); };
return func;
}
void inputter_t::function_push_arg(wchar_t arg) { input_function_args_.push_back(arg); }

View file

@ -57,12 +57,17 @@ class inputter_t {
wchar_t function_pop_arg();
private:
// We need a parser to evaluate bindings.
const std::shared_ptr<parser_t> parser_;
input_event_queue_t event_queue_;
std::vector<wchar_t> input_function_args_{};
bool function_status_{false};
// We need a parser to evaluate bindings.
const std::shared_ptr<parser_t> parser_;
// A function called when select() is interrupted by a signal.
// See interrupt_handler_t.
maybe_t<char_event_t> handle_interrupt();
interrupt_handler_t get_interrupt_handler();
void function_push_arg(wchar_t arg);
void function_push_args(readline_cmd_t code);

View file

@ -36,10 +36,8 @@
#define WAIT_ON_ESCAPE_DEFAULT 30
static int wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
/// Callback function for handling interrupts on reading.
static interrupt_func_t interrupt_handler;
void input_common_init(interrupt_func_t func) { interrupt_handler = func; }
input_event_queue_t::input_event_queue_t(int in, interrupt_handler_t handler)
: in_(in), interrupt_handler_(std::move(handler)) {}
/// Internal function used by input_common_readch to read one byte from fd 0. This function should
/// only be called by input_common_readch().
@ -73,8 +71,8 @@ char_event_t input_event_queue_t::readb() {
if (notifier.poll()) {
env_universal_barrier();
}
if (interrupt_handler) {
if (auto interrupt_evt = interrupt_handler()) {
if (interrupt_handler_) {
if (auto interrupt_evt = interrupt_handler_()) {
return *interrupt_evt;
} else if (auto mc = try_pop()) {
return *mc;

View file

@ -176,21 +176,19 @@ class char_event_t {
}
};
/// A type of function invoked on interrupt.
/// \return the event which is to be returned to the reader loop, or none if VINTR is 0.
using interrupt_func_t = maybe_t<char_event_t> (*)();
/// Init the library with an interrupt function.
void input_common_init(interrupt_func_t func);
/// Adjust the escape timeout.
class environment_t;
void update_wait_on_escape_ms(const environment_t& vars);
/// A function type called when select() is interrupted by a signal.
/// The function maybe returns an event which is propagated back to the caller.
using interrupt_handler_t = std::function<maybe_t<char_event_t>()>;
/// A class which knows how to produce a stream of input events.
class input_event_queue_t {
public:
explicit input_event_queue_t(int in = 0) : in_(in) {}
/// Construct from a file descriptor \p in, and an interrupt handler \p handler.
explicit input_event_queue_t(int in = STDIN_FILENO, interrupt_handler_t handler = {});
/// Function used by input_readch to read bytes from stdin until enough bytes have been read to
/// convert them to a wchar_t. Conversion is done using mbrtowc. If a character has previously
@ -225,9 +223,12 @@ class input_event_queue_t {
/// \return the next event in the queue, or none if the queue is empty.
maybe_t<char_event_t> try_pop();
/// Read at most one byte from stdin, and return the event.
/// If select() is interrupted by a signal, then invoke the interrupt handler.
char_event_t readb();
int in_{0};
const interrupt_handler_t interrupt_handler_;
std::deque<char_event_t> queue_;
};