ian@0
|
1 //
|
ian@0
|
2 // Boost.Process
|
ian@0
|
3 // ~~~~~~~~~~~~~
|
ian@0
|
4 //
|
ian@0
|
5 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
ian@0
|
6 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
ian@0
|
7 // Copyright (c) 2009 Boris Schaeling
|
ian@0
|
8 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
ian@0
|
9 //
|
ian@0
|
10 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
ian@0
|
11 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
ian@0
|
12 //
|
ian@0
|
13
|
ian@0
|
14 /**
|
ian@0
|
15 * \file boost/process/process.hpp
|
ian@0
|
16 *
|
ian@0
|
17 * Includes the declaration of the process class.
|
ian@0
|
18 */
|
ian@0
|
19
|
ian@0
|
20 #ifndef BOOST_PROCESS_PROCESS_HPP
|
ian@0
|
21 #define BOOST_PROCESS_PROCESS_HPP
|
ian@0
|
22
|
ian@0
|
23 #include <boost/process/config.hpp>
|
ian@0
|
24
|
ian@0
|
25 #if defined(BOOST_POSIX_API)
|
ian@0
|
26 # include <unistd.h>
|
ian@0
|
27 # include <sys/types.h>
|
ian@0
|
28 # include <signal.h>
|
ian@0
|
29 # include <sys/wait.h>
|
ian@0
|
30 # include <errno.h>
|
ian@0
|
31 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
32 # include <boost/process/handle.hpp>
|
ian@0
|
33 # include <cstdlib>
|
ian@0
|
34 # include <windows.h>
|
ian@0
|
35 #else
|
ian@0
|
36 # error "Unsupported platform."
|
ian@0
|
37 #endif
|
ian@0
|
38
|
ian@0
|
39 #include <boost/process/pid_type.hpp>
|
ian@0
|
40
|
ian@0
|
41 namespace boost {
|
ian@0
|
42 namespace process {
|
ian@0
|
43
|
ian@0
|
44 /**
|
ian@0
|
45 * Process class to represent any running process.
|
ian@0
|
46 */
|
ian@0
|
47 class process
|
ian@0
|
48 {
|
ian@0
|
49 public:
|
ian@0
|
50 /**
|
ian@0
|
51 * Constructs a new process object.
|
ian@0
|
52 *
|
ian@0
|
53 * Creates a new process object that represents a running process
|
ian@0
|
54 * within the system.
|
ian@0
|
55 *
|
ian@0
|
56 * On Windows the process is opened and a handle saved. This is required
|
ian@0
|
57 * to avoid the operating system removing process resources when the
|
ian@0
|
58 * process exits. The handle is closed when the process instance (and all
|
ian@0
|
59 * of its copies) is destroyed.
|
ian@0
|
60 */
|
ian@0
|
61 process(pid_type id)
|
ian@0
|
62 : id_(id)
|
ian@0
|
63 #if defined(BOOST_WINDOWS_API)
|
ian@0
|
64 , handle_(open_process(id))
|
ian@0
|
65 #endif
|
ian@0
|
66 {
|
ian@0
|
67 }
|
ian@0
|
68
|
ian@0
|
69 #if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN)
|
ian@0
|
70 /**
|
ian@0
|
71 * Constructs a new process object.
|
ian@0
|
72 *
|
ian@0
|
73 * Creates a new process object that represents a running process
|
ian@0
|
74 * within the system.
|
ian@0
|
75 *
|
ian@0
|
76 * This operation is only available on Windows systems. The handle is
|
ian@0
|
77 * closed when the process instance (and all of its copies) is destroyed.
|
ian@0
|
78 */
|
ian@0
|
79 process(handle h)
|
ian@0
|
80 : id_(GetProcessId(h.native())),
|
ian@0
|
81 handle_(h)
|
ian@0
|
82 {
|
ian@0
|
83 }
|
ian@0
|
84 #endif
|
ian@0
|
85
|
ian@0
|
86 /**
|
ian@0
|
87 * Returns the process identifier.
|
ian@0
|
88 */
|
ian@0
|
89 pid_type get_id() const
|
ian@0
|
90 {
|
ian@0
|
91 return id_;
|
ian@0
|
92 }
|
ian@0
|
93
|
ian@0
|
94 /**
|
ian@0
|
95 * Terminates the process execution.
|
ian@0
|
96 *
|
ian@0
|
97 * Forces the termination of the process execution. Some platforms
|
ian@0
|
98 * allow processes to ignore some external termination notifications
|
ian@0
|
99 * or to capture them for a proper exit cleanup. You can set the
|
ian@0
|
100 * \a force flag to true to force their termination regardless
|
ian@0
|
101 * of any exit handler.
|
ian@0
|
102 *
|
ian@0
|
103 * After this call, accessing this object can be dangerous because the
|
ian@0
|
104 * process identifier may have been reused by a different process. It
|
ian@0
|
105 * might still be valid, though, if the process has refused to die.
|
ian@0
|
106 *
|
ian@0
|
107 * \throw boost::system::system_error If system calls used to terminate the
|
ian@0
|
108 * process fail.
|
ian@0
|
109 */
|
ian@0
|
110 void terminate(bool force = false) const
|
ian@0
|
111 {
|
ian@0
|
112 #if defined(BOOST_POSIX_API)
|
ian@0
|
113 if (kill(id_, force ? SIGKILL : SIGTERM) == -1)
|
ian@0
|
114 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("kill(2) failed");
|
ian@0
|
115 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
116 #if defined(BOOST_MSVC)
|
ian@0
|
117 force;
|
ian@0
|
118 #endif
|
ian@0
|
119 HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, id_);
|
ian@0
|
120 if (h == NULL)
|
ian@0
|
121 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
|
ian@0
|
122 if (!TerminateProcess(h, EXIT_FAILURE))
|
ian@0
|
123 {
|
ian@0
|
124 CloseHandle(h);
|
ian@0
|
125 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("TerminateProcess() failed");
|
ian@0
|
126 }
|
ian@0
|
127 if (!CloseHandle(h))
|
ian@0
|
128 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
|
ian@0
|
129 #endif
|
ian@0
|
130 }
|
ian@0
|
131
|
ian@0
|
132 /**
|
ian@0
|
133 * Blocks and waits for the process to terminate.
|
ian@0
|
134 *
|
ian@0
|
135 * Returns an exit code. The process object ceases to be valid after this
|
ian@0
|
136 * call.
|
ian@0
|
137 *
|
ian@0
|
138 * \remark Blocking remarks: This call blocks if the process has not
|
ian@0
|
139 * finalized execution and waits until it terminates.
|
ian@0
|
140 *
|
ian@0
|
141 * \throw boost::system::system_error If system calls used to wait for the
|
ian@0
|
142 * process fail.
|
ian@0
|
143 */
|
ian@0
|
144 int wait() const
|
ian@0
|
145 {
|
ian@0
|
146 #if defined(BOOST_POSIX_API)
|
ian@0
|
147 pid_t p;
|
ian@0
|
148 int status;
|
ian@0
|
149 do
|
ian@0
|
150 {
|
ian@0
|
151 p = waitpid(id_, &status, 0);
|
ian@0
|
152 } while (p == -1 && errno == EINTR);
|
ian@0
|
153 if (p == -1)
|
ian@0
|
154 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("waitpid(2) failed");
|
ian@0
|
155 return status;
|
ian@0
|
156 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
157 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE,
|
ian@0
|
158 id_);
|
ian@0
|
159 if (h == NULL)
|
ian@0
|
160 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
|
ian@0
|
161 if (WaitForSingleObject(h, INFINITE) == WAIT_FAILED)
|
ian@0
|
162 {
|
ian@0
|
163 CloseHandle(h);
|
ian@0
|
164 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
|
ian@0
|
165 "WaitForSingleObject() failed");
|
ian@0
|
166 }
|
ian@0
|
167 DWORD exit_code;
|
ian@0
|
168 if (!GetExitCodeProcess(h, &exit_code))
|
ian@0
|
169 {
|
ian@0
|
170 CloseHandle(h);
|
ian@0
|
171 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
|
ian@0
|
172 "GetExitCodeProcess() failed");
|
ian@0
|
173 }
|
ian@0
|
174 if (!CloseHandle(h))
|
ian@0
|
175 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
|
ian@0
|
176 return exit_code;
|
ian@0
|
177 #endif
|
ian@0
|
178 }
|
ian@0
|
179
|
ian@0
|
180 private:
|
ian@0
|
181 /**
|
ian@0
|
182 * The process identifier.
|
ian@0
|
183 */
|
ian@0
|
184 pid_type id_;
|
ian@0
|
185
|
ian@0
|
186 #if defined(BOOST_WINDOWS_API)
|
ian@0
|
187 /**
|
ian@0
|
188 * Opens a process and returns a handle.
|
ian@0
|
189 *
|
ian@0
|
190 * OpenProcess() returns NULL and not INVALID_HANDLE_VALUE on failure.
|
ian@0
|
191 * That's why the return value is manually checked in this helper function
|
ian@0
|
192 * instead of simply passing it to the constructor of the handle class.
|
ian@0
|
193 */
|
ian@0
|
194 HANDLE open_process(pid_type id)
|
ian@0
|
195 {
|
ian@0
|
196 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, id);
|
ian@0
|
197 if (h == NULL)
|
ian@0
|
198 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
|
ian@0
|
199 return h;
|
ian@0
|
200 }
|
ian@0
|
201
|
ian@0
|
202 /**
|
ian@0
|
203 * The process handle.
|
ian@0
|
204 */
|
ian@0
|
205 handle handle_;
|
ian@0
|
206 #endif
|
ian@0
|
207 };
|
ian@0
|
208
|
ian@0
|
209 }
|
ian@0
|
210 }
|
ian@0
|
211
|
ian@0
|
212 #endif
|