mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-30 11:21:15 -03:00
Introduce prepare_to_select, fixing job_summary.py
This concerns printing status messages for background jobs which have stopped or finished. Previously fish would do this from two places: 1. Before running a command (including empty string) 2. If a signal is received during select() So if the job finishes while fish is doing something else (like running an event handler) then we would not print status messages until the user hit return. This caused the job_summary.py test to be flaky. Fix this by splitting the interrupt handler into two parts: a part that handles signals (e.g. triggering exit from the reader), and a part that always runs just before blocking in select(). This second part always reaps jobs and prints their status messages. This narrows the window for a job exit to be "missed" before fish blocks in select, and should make the job_summary.py test more reliable.
This commit is contained in:
@@ -318,14 +318,19 @@ void init_input() {
|
||||
inputter_t::inputter_t(parser_t &parser, int in)
|
||||
: input_event_queue_t(in), parser_(parser.shared()) {}
|
||||
|
||||
/// Handle interruptions to key reading by reaping finished jobs and propagating the interrupt to
|
||||
/// the reader.
|
||||
void inputter_t::select_interrupted() /* override */ {
|
||||
// Fire any pending events.
|
||||
void inputter_t::prepare_to_select() /* override */ {
|
||||
// Fire any pending events and reap stray processes, including printing exit status messages.
|
||||
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();
|
||||
}
|
||||
|
||||
void inputter_t::select_interrupted() /* override */ {
|
||||
// Fire any pending events and reap stray processes, including printing exit status messages.
|
||||
auto &parser = *this->parser_;
|
||||
event_fire_delayed(parser);
|
||||
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];
|
||||
|
||||
@@ -54,6 +54,9 @@ class inputter_t final : private input_event_queue_t {
|
||||
wchar_t function_pop_arg();
|
||||
|
||||
private:
|
||||
// Called right before potentially blocking in select().
|
||||
void prepare_to_select() override;
|
||||
|
||||
// Called when select() is interrupted by a signal.
|
||||
void select_interrupted() override;
|
||||
|
||||
|
||||
@@ -161,6 +161,12 @@ char_event_t input_event_queue_t::readch() {
|
||||
return mevt.acquire();
|
||||
}
|
||||
|
||||
// We are going to block; but first allow any override to inject events.
|
||||
this->prepare_to_select();
|
||||
if (auto mevt = try_pop()) {
|
||||
return mevt.acquire();
|
||||
}
|
||||
|
||||
readb_result_t rr = readb(in_);
|
||||
switch (rr) {
|
||||
case readb_eof:
|
||||
@@ -229,5 +235,6 @@ void input_event_queue_t::push_back(const char_event_t& ch) { queue_.push_back(c
|
||||
|
||||
void input_event_queue_t::push_front(const char_event_t& ch) { queue_.push_front(ch); }
|
||||
|
||||
void input_event_queue_t::prepare_to_select() {}
|
||||
void input_event_queue_t::select_interrupted() {}
|
||||
input_event_queue_t::~input_event_queue_t() = default;
|
||||
|
||||
@@ -213,6 +213,10 @@ class input_event_queue_t {
|
||||
queue_.insert(queue_.begin(), begin, end);
|
||||
}
|
||||
|
||||
/// Override point for when we are about to (potentially) block in select(). The default does
|
||||
/// nothing.
|
||||
virtual void prepare_to_select();
|
||||
|
||||
/// Override point for when when select() is interrupted by a signal. The default does nothing.
|
||||
virtual void select_interrupted();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user