/// Waits for completion of any forked process. /// /// \return A pointer to an object describing the waited-for subprocess. executor::exit_handle executor::executor_handle::wait_any(void) { signals::check_interrupt(); const process::status status = process::wait_any(); return _pimpl->post_wait(status.dead_pid(), status); }
/// Blocks to wait for completion of any subprocess. /// /// \return The termination status of the child process that terminated. /// /// \throw process::system_error If the call to wait(2) fails. process::status process::wait_any(void) { const process::status status = safe_wait(); { signals::interrupts_inhibiter inhibiter; signals::remove_pid_to_kill(status.dead_pid()); } return status; }
/// Common code to run after any of the wait calls. /// /// \param handle The exec_handle of the terminated subprocess. /// \param status The exit status of the terminated subprocess. /// /// \return A pointer to an object describing the waited-for subprocess. executor::exit_handle post_wait(const executor::exec_handle handle, const process::status& status) { PRE(handle == status.dead_pid()); LI(F("Waited for subprocess with exec_handle %s") % handle); process::terminate_group(status.dead_pid()); const exec_data_map::iterator iter = all_exec_data.find(handle); exec_data_ptr& data = (*iter).second; data->timer.unprogram(); // It is tempting to assert here (and old code did) that, if the timer // has fired, the process has been forcibly killed by us. This is not // always the case though: for short-lived processes and with very short // timeouts (think 1ms), it is possible for scheduling decisions to // allow the subprocess to finish while at the same time cause the timer // to fire. So we do not assert this any longer and just rely on the // timer expiration to check if the process timed out or not. If the // process did finish but the timer expired... oh well, we do not detect // this correctly but we don't care because this should not really // happen. if (!fs::exists(data->stdout_file)) { std::ofstream new_stdout(data->stdout_file.c_str()); } if (!fs::exists(data->stderr_file)) { std::ofstream new_stderr(data->stderr_file.c_str()); } return exit_handle(std::shared_ptr< exit_handle::impl >( new exit_handle::impl( handle, data->timer.fired() ? none : utils::make_optional(status), data->unprivileged_user, data->start_time, datetime::timestamp::now(), data->control_directory, data->stdout_file, data->stderr_file, data->state_owners, all_exec_data))); }