diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a5b8dda2c..38b9c34f9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -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 ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/builtin_function.cpp b/src/builtin_function.cpp index 9e09be99d..a24b0399e 100644 --- a/src/builtin_function.cpp +++ b/src/builtin_function.cpp @@ -264,12 +264,30 @@ maybe_t 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(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; } diff --git a/src/proc.cpp b/src/proc.cpp index cc97f8e1b..7f06e1233 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -609,6 +609,7 @@ static void save_wait_handle_for_completed_job(const shared_ptr &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; } } diff --git a/src/wait_handle.h b/src/wait_handle.h index e1afe613d..d0fd79075 100644 --- a/src/wait_handle.h +++ b/src/wait_handle.h @@ -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}; }; diff --git a/tests/checks/wait.fish b/tests/checks/wait.fish index d0222ea82..05f7ae549 100644 --- a/tests/checks/wait.fish +++ b/tests/checks/wait.fish @@ -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