| 133 | } |
| 134 | |
| 135 | ~Impl() { |
| 136 | #ifdef BOOST_PROCESS_AVAILABLE |
| 137 | # ifdef BOOST_PROCESS_USE_V2 |
| 138 | // V2 doesn't provide process group support yet: |
| 139 | // https://github.com/boostorg/process/issues/259 |
| 140 | // |
| 141 | // So we try graceful shutdown (SIGTERM + waitpid()) before |
| 142 | // immediate shutdown (SIGKILL). This assumes that the target |
| 143 | // executable such as "python3 -m testbench" terminates all related |
| 144 | // processes by graceful shutdown. |
| 145 | boost::system::error_code error_code; |
| 146 | if (process_ && process_->running(error_code)) { |
| 147 | process_->request_exit(error_code); |
| 148 | if (!error_code) { |
| 149 | auto timeout = std::chrono::seconds(3); |
| 150 | std::chrono::time_point<std::chrono::steady_clock> end = |
| 151 | std::chrono::steady_clock::now() + timeout; |
| 152 | while (process_->running(error_code) && std::chrono::steady_clock::now() < end) { |
| 153 | std::this_thread::sleep_for(std::chrono::milliseconds(20)); |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | # else |
| 158 | process_group_ = nullptr; |
| 159 | # endif |
| 160 | process_ = nullptr; |
| 161 | #endif |
| 162 | } |
| 163 | |
| 164 | Status SetExecutable(const std::string& name) { |
| 165 | #ifdef BOOST_PROCESS_AVAILABLE |