Ensure that on-process-exit events fire for reaped jobs

This ensures that if a job exits before we have set up the
on-process-exit handler, the handler will still fire.

Fixes #7210
This commit is contained in:
ridiculousfish 2021-05-17 15:22:02 -07:00
parent 60d75e9aa0
commit 6d00ad1045
5 changed files with 37 additions and 3 deletions

View file

@ -45,7 +45,7 @@ Interactive improvements
- Variable ``fish_killring`` containing entries from killring is now available (:issue:`7445`).
- ``fish --private`` prints a note on private mode on startup even if ``$fish_greeting`` is an empty list (:issue:`7974`).
- fish no longer attempts to lock history or universal variable files on remote filesystems, including NFS and SMB. In rare cases, updates to these files may be dropped if separate fish instances modify them simultaneously. (:issue:`7968`).
- ``wait`` works correctly with jobs that have already exited (:issue:`7210`).
- ``wait`` and ``on-process-exit`` work correctly with jobs that have already exited (:issue:`7210`).
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -264,12 +264,30 @@ maybe_t<int> builtin_function(parser_t &parser, io_streams_t &streams,
// Add the function itself.
function_add(function_name, opts.description, props, parser.libdata().current_filename);
// Handle wrap targets by creating the appropriate completions.
for (const wcstring &wt : opts.wrap_targets) {
complete_add_wrapper(function_name, wt);
}
// Add any event handlers.
for (const event_description_t &ed : opts.events) {
event_add_handler(std::make_shared<event_handler_t>(ed, function_name));
}
// Handle wrap targets by creating the appropriate completions.
for (const wcstring &wt : opts.wrap_targets) complete_add_wrapper(function_name, wt);
// If there is an --on-process-exit or --on-job-exit event handler for some pid, and that
// process has already exited, run it immediately (#7210).
for (const event_description_t &ed : opts.events) {
if (ed.type == event_type_t::exit && ed.param1.pid != EVENT_ANY_PID) {
wait_handle_ref_t wh = parser.get_wait_handles().get_by_pid(abs(ed.param1.pid));
if (wh && wh->completed) {
if (ed.param1.pid > 0) {
event_fire(parser, event_t::process_exit(ed.param1.pid, wh->status));
} else {
event_fire(parser, event_t::job_exit(ed.param1.pid));
}
}
}
}
return STATUS_CMD_OK;
}

View file

@ -609,6 +609,7 @@ static void save_wait_handle_for_completed_job(const shared_ptr<job_t> &job,
// Mark all wait handles as complete (but don't create just for this).
for (auto &proc : job->processes) {
if (wait_handle_ref_t wh = proc->get_wait_handle(false /* create */)) {
wh->status = proc->status.status_value();
wh->completed = true;
}
}

View file

@ -27,6 +27,9 @@ struct wait_handle_t {
/// For example if the process is "/bin/sleep" then this will be 'sleep'.
wcstring base_name{};
/// The value appropriate for populating $status, if completed.
int status{0};
/// Set to true when the process is completed.
bool completed{false};
};

View file

@ -24,3 +24,15 @@ end
wait true false
jobs
# CHECK: jobs: There are no jobs
# Ensure on-process-exit works for exited jobs.
command false &
set pid $last_pid
# Ensure it gets reaped
sleep .1
function waiter --on-process-exit $pid
echo exited $argv
end
# CHECK: exited PROCESS_EXIT {{\d+}} 1