/** * Blocks and waits for the process to terminate. * * Returns an exit code. The process object ceases to be valid after this * call. * * \remark Blocking remarks: This call blocks if the process has not * finalized execution and waits until it terminates. * * \throw boost::system::system_error If system calls used to wait for the * process fail. */ int wait() const { #if defined(BOOST_POSIX_API) pid_t p; int status; do { p = waitpid(id_, &status, 0); } while (p == -1 && errno == EINTR); if (p == -1) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("waitpid(2) failed"); return status; #elif defined(BOOST_WINDOWS_API) HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, id_); if (h == NULL) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed"); if (WaitForSingleObject(h, INFINITE) == WAIT_FAILED) { CloseHandle(h); BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( "WaitForSingleObject() failed"); } DWORD exit_code; if (!GetExitCodeProcess(h, &exit_code)) { CloseHandle(h); BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( "GetExitCodeProcess() failed"); } if (!CloseHandle(h)) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed"); return exit_code; #endif }
inline DWORD wait_for_exit(const Process &p) { if (::WaitForSingleObject(p.process_handle(), INFINITE) == WAIT_FAILED) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("WaitForSingleObject() failed"); DWORD exit_code; if (!::GetExitCodeProcess(p.process_handle(), &exit_code)) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("GetExitCodeProcess() failed"); return exit_code; }
/** * Opens a process and returns a handle. * * OpenProcess() returns NULL and not INVALID_HANDLE_VALUE on failure. * That's why the return value is manually checked in this helper function * instead of simply passing it to the constructor of the handle class. */ HANDLE open_process(pid_type id) { HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, id); if (h == NULL) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed"); return h; }
inline pipe create_pipe() { HANDLE handles[2]; if (!::CreatePipe(&handles[0], &handles[1], NULL, 0)) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreatePipe() failed"); return make_pipe(handles[0], handles[1]); }
void async_wait(implementation_type &impl, pid_type pid, Handler handler) { #if defined(BOOST_POSIX_API) boost::unique_lock<boost::mutex> lock(work_thread_mutex_); if (++pids_ == 1) { work_.reset(new boost::asio::io_service::work( this->get_io_service())); work_thread_ = boost::thread( &basic_status_service<StatusImplementation>::work_thread, this); } impl->async_wait(pid, this->get_io_service().wrap(handler)); #elif defined(BOOST_WINDOWS_API) HANDLE handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); if (handle == NULL) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed"); boost::unique_lock<boost::mutex> lock(work_thread_mutex_); if (!work_) work_.reset(new boost::asio::io_service::work( this->get_io_service())); interrupt_work_thread(); work_thread_cond_.wait(work_thread_mutex_); handles_.push_back(handle); impl->async_wait(handle, this->get_io_service().wrap(handler)); work_thread_cond_.notify_all(); #endif }
/** * Terminates the process execution. * * Forces the termination of the process execution. Some platforms * allow processes to ignore some external termination notifications * or to capture them for a proper exit cleanup. You can set the * \a force flag to true to force their termination regardless * of any exit handler. * * After this call, accessing this object can be dangerous because the * process identifier may have been reused by a different process. It * might still be valid, though, if the process has refused to die. * * \throw boost::system::system_error If system calls used to terminate the * process fail. */ void terminate(bool force = false) const { #if defined(BOOST_POSIX_API) if (kill(id_, force ? SIGKILL : SIGTERM) == -1) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("kill(2) failed"); #elif defined(BOOST_WINDOWS_API) #if defined(BOOST_MSVC) force; #endif HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, id_); if (h == NULL) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed"); if (!TerminateProcess(h, EXIT_FAILURE)) { CloseHandle(h); BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("TerminateProcess() failed"); } if (!CloseHandle(h)) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed"); #endif }
bool complete(phandle ph, int exit_code) { boost::iterator_range<operations_type::iterator> r = ops_.equal_range(ph); if (r.empty()) return false; for (operations_type::iterator it = r.begin(); it != r.end(); ++it) (*it->second)(exit_code); ops_.erase(r.begin(), r.end()); #if defined(BOOST_WINDOWS_API) if (!CloseHandle(ph)) BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed"); #endif return true; }