| 90 | } |
| 91 | |
| 92 | void terminate_process_group(boost::process::v1::child &proc, boost::process::v1::group &group, std::chrono::seconds exit_timeout) { |
| 93 | if (group.valid() && platf::process_group_running((std::uintptr_t) group.native_handle())) { |
| 94 | if (exit_timeout.count() > 0) { |
| 95 | // Request processes in the group to exit gracefully |
| 96 | if (platf::request_process_group_exit((std::uintptr_t) group.native_handle())) { |
| 97 | // If the request was successful, wait for a little while for them to exit. |
| 98 | BOOST_LOG(info) << "Successfully requested the app to exit. Waiting up to "sv << exit_timeout.count() << " seconds for it to close."sv; |
| 99 | |
| 100 | // group::wait_for() and similar functions are broken and deprecated, so we use a simple polling loop |
| 101 | while (platf::process_group_running((std::uintptr_t) group.native_handle()) && (--exit_timeout).count() >= 0) { |
| 102 | std::this_thread::sleep_for(1s); |
| 103 | } |
| 104 | |
| 105 | if (exit_timeout.count() < 0) { |
| 106 | BOOST_LOG(warning) << "App did not fully exit within the timeout. Terminating the app's remaining processes."sv; |
| 107 | } else { |
| 108 | BOOST_LOG(info) << "All app processes have successfully exited."sv; |
| 109 | } |
| 110 | } else { |
| 111 | BOOST_LOG(info) << "App did not respond to a graceful termination request. Forcefully terminating the app's processes."sv; |
| 112 | } |
| 113 | } else { |
| 114 | BOOST_LOG(info) << "No graceful exit timeout was specified for this app. Forcefully terminating the app's processes."sv; |
| 115 | } |
| 116 | |
| 117 | // We always call terminate() even if we waited successfully for all processes above. |
| 118 | // This ensures the process group state is consistent with the OS in boost. |
| 119 | std::error_code ec; |
| 120 | group.terminate(ec); |
| 121 | group.detach(); |
| 122 | } |
| 123 | |
| 124 | if (proc.valid()) { |
| 125 | // avoid zombie process |
| 126 | proc.detach(); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | boost::filesystem::path find_working_directory(const std::string &cmd, const boost::process::v1::environment &env) { |
| 131 | // Parse the raw command string into parts to get the actual command portion |
no test coverage detected