ian@0: // ian@0: // Boost.Process ian@0: // ~~~~~~~~~~~~~ ian@0: // ian@0: // Copyright (c) 2006, 2007 Julio M. Merino Vidal ian@0: // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling ian@0: // Copyright (c) 2009 Boris Schaeling ian@0: // Copyright (c) 2010 Felipe Tanus, Boris Schaeling ian@0: // ian@0: // Distributed under the Boost Software License, Version 1.0. (See accompanying ian@0: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ian@0: // ian@0: ian@0: /** ian@0: * \file boost/process/process.hpp ian@0: * ian@0: * Includes the declaration of the process class. ian@0: */ ian@0: ian@0: #ifndef BOOST_PROCESS_PROCESS_HPP ian@0: #define BOOST_PROCESS_PROCESS_HPP ian@0: ian@0: #include ian@0: ian@0: #if defined(BOOST_POSIX_API) ian@0: # include ian@0: # include ian@0: # include ian@0: # include ian@0: # include ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: # include ian@0: # include ian@0: # include ian@0: #else ian@0: # error "Unsupported platform." ian@0: #endif ian@0: ian@0: #include ian@0: ian@0: namespace boost { ian@0: namespace process { ian@0: ian@0: /** ian@0: * Process class to represent any running process. ian@0: */ ian@0: class process ian@0: { ian@0: public: ian@0: /** ian@0: * Constructs a new process object. ian@0: * ian@0: * Creates a new process object that represents a running process ian@0: * within the system. ian@0: * ian@0: * On Windows the process is opened and a handle saved. This is required ian@0: * to avoid the operating system removing process resources when the ian@0: * process exits. The handle is closed when the process instance (and all ian@0: * of its copies) is destroyed. ian@0: */ ian@0: process(pid_type id) ian@0: : id_(id) ian@0: #if defined(BOOST_WINDOWS_API) ian@0: , handle_(open_process(id)) ian@0: #endif ian@0: { ian@0: } ian@0: ian@0: #if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN) ian@0: /** ian@0: * Constructs a new process object. ian@0: * ian@0: * Creates a new process object that represents a running process ian@0: * within the system. ian@0: * ian@0: * This operation is only available on Windows systems. The handle is ian@0: * closed when the process instance (and all of its copies) is destroyed. ian@0: */ ian@0: process(handle h) ian@0: : id_(GetProcessId(h.native())), ian@0: handle_(h) ian@0: { ian@0: } ian@0: #endif ian@0: ian@0: /** ian@0: * Returns the process identifier. ian@0: */ ian@0: pid_type get_id() const ian@0: { ian@0: return id_; ian@0: } ian@0: ian@0: /** ian@0: * Terminates the process execution. ian@0: * ian@0: * Forces the termination of the process execution. Some platforms ian@0: * allow processes to ignore some external termination notifications ian@0: * or to capture them for a proper exit cleanup. You can set the ian@0: * \a force flag to true to force their termination regardless ian@0: * of any exit handler. ian@0: * ian@0: * After this call, accessing this object can be dangerous because the ian@0: * process identifier may have been reused by a different process. It ian@0: * might still be valid, though, if the process has refused to die. ian@0: * ian@0: * \throw boost::system::system_error If system calls used to terminate the ian@0: * process fail. ian@0: */ ian@0: void terminate(bool force = false) const ian@0: { ian@0: #if defined(BOOST_POSIX_API) ian@0: if (kill(id_, force ? SIGKILL : SIGTERM) == -1) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("kill(2) failed"); ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: #if defined(BOOST_MSVC) ian@0: force; ian@0: #endif ian@0: HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, id_); ian@0: if (h == NULL) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed"); ian@0: if (!TerminateProcess(h, EXIT_FAILURE)) ian@0: { ian@0: CloseHandle(h); ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("TerminateProcess() failed"); ian@0: } ian@0: if (!CloseHandle(h)) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed"); ian@0: #endif ian@0: } ian@0: ian@0: /** ian@0: * Blocks and waits for the process to terminate. ian@0: * ian@0: * Returns an exit code. The process object ceases to be valid after this ian@0: * call. ian@0: * ian@0: * \remark Blocking remarks: This call blocks if the process has not ian@0: * finalized execution and waits until it terminates. ian@0: * ian@0: * \throw boost::system::system_error If system calls used to wait for the ian@0: * process fail. ian@0: */ ian@0: int wait() const ian@0: { ian@0: #if defined(BOOST_POSIX_API) ian@0: pid_t p; ian@0: int status; ian@0: do ian@0: { ian@0: p = waitpid(id_, &status, 0); ian@0: } while (p == -1 && errno == EINTR); ian@0: if (p == -1) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("waitpid(2) failed"); ian@0: return status; ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, ian@0: id_); ian@0: if (h == NULL) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed"); ian@0: if (WaitForSingleObject(h, INFINITE) == WAIT_FAILED) ian@0: { ian@0: CloseHandle(h); ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( ian@0: "WaitForSingleObject() failed"); ian@0: } ian@0: DWORD exit_code; ian@0: if (!GetExitCodeProcess(h, &exit_code)) ian@0: { ian@0: CloseHandle(h); ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( ian@0: "GetExitCodeProcess() failed"); ian@0: } ian@0: if (!CloseHandle(h)) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed"); ian@0: return exit_code; ian@0: #endif ian@0: } ian@0: ian@0: private: ian@0: /** ian@0: * The process identifier. ian@0: */ ian@0: pid_type id_; ian@0: ian@0: #if defined(BOOST_WINDOWS_API) ian@0: /** ian@0: * Opens a process and returns a handle. ian@0: * ian@0: * OpenProcess() returns NULL and not INVALID_HANDLE_VALUE on failure. ian@0: * That's why the return value is manually checked in this helper function ian@0: * instead of simply passing it to the constructor of the handle class. ian@0: */ ian@0: HANDLE open_process(pid_type id) ian@0: { ian@0: HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, id); ian@0: if (h == NULL) ian@0: BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed"); ian@0: return h; ian@0: } ian@0: ian@0: /** ian@0: * The process handle. ian@0: */ ian@0: handle handle_; ian@0: #endif ian@0: }; ian@0: ian@0: } ian@0: } ian@0: ian@0: #endif