Don't generate exit events for jobs created from within event handlers

Add a new job property from_event_handler, and do not create exit events for
such jobs. This prevents easy accidental infinite recursion.
This commit is contained in:
ridiculousfish 2019-06-26 11:28:27 -07:00
parent d7a9bdf5c3
commit f7e2e7d26b
4 changed files with 13 additions and 7 deletions

View file

@ -520,8 +520,6 @@ int main(int argc, char **argv) {
int exit_status = res ? STATUS_CMD_UNKNOWN : parser.get_last_status(); int exit_status = res ? STATUS_CMD_UNKNOWN : parser.get_last_status();
// TODO: The generic process-exit event is useless and unused.
// Remove this in future.
event_fire(parser, event_fire(parser,
proc_create_event(L"PROCESS_EXIT", event_type_t::exit, getpid(), exit_status)); proc_create_event(L"PROCESS_EXIT", event_type_t::exit, getpid(), exit_status));

View file

@ -1243,6 +1243,7 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t<g::job> jo
props.wants_terminal = wants_job_control && !ld.is_event; props.wants_terminal = wants_job_control && !ld.is_event;
props.skip_notification = props.skip_notification =
ld.is_subshell || ld.is_block || ld.is_event || !shell_is_interactive(); ld.is_subshell || ld.is_block || ld.is_event || !shell_is_interactive();
props.from_event_handler = ld.is_event;
shared_ptr<job_t> job = std::make_shared<job_t>(acquire_job_id(), props, block_io, parent_job); shared_ptr<job_t> job = std::make_shared<job_t>(acquire_job_id(), props, block_io, parent_job);
job->tmodes = tmodes; job->tmodes = tmodes;

View file

@ -472,9 +472,11 @@ static bool try_clean_process_in_job(process_t *p, job_t *j, std::vector<event_t
auto s = p->status; auto s = p->status;
// Add an exit event. // Add an exit event if the process did not come from a job handler.
exit_events->push_back(proc_create_event(L"PROCESS_EXIT", event_type_t::exit, p->pid, if (!j->from_event_handler()) {
s.normal_exited() ? s.exit_code() : -1)); exit_events->push_back(proc_create_event(L"PROCESS_EXIT", event_type_t::exit, p->pid,
s.normal_exited() ? s.exit_code() : -1));
}
// Ignore SIGPIPE. We issue it ourselves to the pipe writer when the pipe reader dies. // Ignore SIGPIPE. We issue it ourselves to the pipe writer when the pipe reader dies.
if (!s.signal_exited() || s.signal_code() == SIGPIPE) { if (!s.signal_exited() || s.signal_code() == SIGPIPE) {
@ -600,8 +602,9 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
printed = true; printed = true;
} }
// Prepare events for completed jobs. // Prepare events for completed jobs, except for jobs that themselves came from event
if (j->is_completed()) { // handlers.
if (!j->from_event_handler() && j->is_completed()) {
if (j->pgid != INVALID_PID) { if (j->pgid != INVALID_PID) {
exit_events.push_back( exit_events.push_back(
proc_create_event(L"JOB_EXIT", event_type_t::exit, -j->pgid, 0)); proc_create_event(L"JOB_EXIT", event_type_t::exit, -j->pgid, 0));

View file

@ -296,6 +296,9 @@ class job_t {
/// Whether the job wants to own the terminal when in the foreground. /// Whether the job wants to own the terminal when in the foreground.
bool wants_terminal{}; bool wants_terminal{};
/// Whether this job was created as part of an event handler.
bool from_event_handler{};
}; };
private: private:
@ -421,6 +424,7 @@ class job_t {
return !is_completed() && is_constructed() && !get_flag(job_flag_t::DISOWN_REQUESTED); return !is_completed() && is_constructed() && !get_flag(job_flag_t::DISOWN_REQUESTED);
}; };
bool skip_notification() const { return properties.skip_notification; } bool skip_notification() const { return properties.skip_notification; }
bool from_event_handler() const { return properties.from_event_handler; }
/// \return the parent job, or nullptr. /// \return the parent job, or nullptr.
const std::shared_ptr<job_t> get_parent() const { return parent_job; } const std::shared_ptr<job_t> get_parent() const { return parent_job; }