Mercurial > hg > gpsynth
comparison third_party/boost/process/stream_behavior.hpp @ 0:add35537fdbb tip
Initial import
author | irh <ian.r.hobson@gmail.com> |
---|---|
date | Thu, 25 Aug 2011 11:05:55 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:add35537fdbb |
---|---|
1 // | |
2 // Boost.Process | |
3 // ~~~~~~~~~~~~~ | |
4 // | |
5 // Copyright (c) 2006, 2007 Julio M. Merino Vidal | |
6 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling | |
7 // Copyright (c) 2009 Boris Schaeling | |
8 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling | |
9 // | |
10 // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
11 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
12 // | |
13 | |
14 /** | |
15 * \file boost/process/stream_behavior.hpp | |
16 * | |
17 * Includes the declaration of stream behavior classes. | |
18 */ | |
19 | |
20 #ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP | |
21 #define BOOST_PROCESS_STREAM_BEHAVIOR_HPP | |
22 | |
23 #include <boost/process/config.hpp> | |
24 | |
25 #if defined(BOOST_POSIX_API) | |
26 # include <sys/stat.h> | |
27 # include <fcntl.h> | |
28 # include <unistd.h> | |
29 #elif defined(BOOST_WINDOWS_API) | |
30 # include <windows.h> | |
31 # include <rpc.h> | |
32 #endif | |
33 | |
34 #include <boost/process/stream_ends.hpp> | |
35 #include <boost/process/stream_type.hpp> | |
36 #include <boost/process/handle.hpp> | |
37 #include <string> | |
38 #include <algorithm> | |
39 | |
40 namespace boost { | |
41 namespace process { | |
42 namespace behavior { | |
43 | |
44 /** | |
45 * Stream behavior to close streams of a child process. | |
46 * | |
47 * A child process will not be able to use the stream. | |
48 */ | |
49 class close | |
50 { | |
51 public: | |
52 stream_ends operator()(stream_type) const | |
53 { | |
54 return stream_ends(); | |
55 } | |
56 }; | |
57 | |
58 /** | |
59 * Stream behavior to make a child process inherit streams. | |
60 * | |
61 * A child process will use the very same stream of its parent process. | |
62 */ | |
63 class inherit | |
64 { | |
65 public: | |
66 inherit(handle::native_type h) | |
67 : h_(h, handle::dont_close) | |
68 { | |
69 #if defined(BOOST_WINDOWS_API) | |
70 if (h != INVALID_HANDLE_VALUE) | |
71 { | |
72 if (!SetHandleInformation(h_.native(), HANDLE_FLAG_INHERIT, | |
73 HANDLE_FLAG_INHERIT)) | |
74 { | |
75 HANDLE proc = GetCurrentProcess(); | |
76 HANDLE dup; | |
77 if (!DuplicateHandle(proc, h_.native(), proc, &dup, 0, | |
78 TRUE, DUPLICATE_SAME_ACCESS)) | |
79 { | |
80 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( | |
81 "DuplicateHandle() failed"); | |
82 } | |
83 h_ = dup; | |
84 } | |
85 } | |
86 #endif | |
87 } | |
88 | |
89 stream_ends operator()(stream_type) const | |
90 { | |
91 return stream_ends(h_, handle()); | |
92 } | |
93 | |
94 private: | |
95 handle h_; | |
96 }; | |
97 | |
98 /** | |
99 * Stream behavior to redirect streams with a pipe. | |
100 * | |
101 * A child process will be able to communicate with its parent process. | |
102 */ | |
103 class pipe | |
104 { | |
105 public: | |
106 #if defined(BOOST_POSIX_API) | |
107 pipe() | |
108 : stype_(unknown_stream) | |
109 { | |
110 } | |
111 | |
112 pipe(stream_type stype) | |
113 : stype_(stype) | |
114 { | |
115 } | |
116 #endif | |
117 | |
118 stream_ends operator()(stream_type stype) const | |
119 { | |
120 handle::native_type ends[2]; | |
121 #if defined(BOOST_POSIX_API) | |
122 if (::pipe(ends) == -1) | |
123 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("pipe(2) failed"); | |
124 if (stype_ != unknown_stream) | |
125 stype = stype_; | |
126 #elif defined(BOOST_WINDOWS_API) | |
127 SECURITY_ATTRIBUTES sa; | |
128 ZeroMemory(&sa, sizeof(sa)); | |
129 sa.nLength = sizeof(sa); | |
130 sa.lpSecurityDescriptor = NULL; | |
131 sa.bInheritHandle = FALSE; | |
132 if (!CreatePipe(&ends[0], &ends[1], &sa, 0)) | |
133 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreatePipe() failed"); | |
134 #endif | |
135 handle child_end = ends[stype == input_stream ? 0 : 1]; | |
136 handle parent_end = ends[stype == input_stream ? 1 : 0]; | |
137 #if defined(BOOST_WINDOWS_API) | |
138 if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT, | |
139 HANDLE_FLAG_INHERIT)) | |
140 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( | |
141 "SetHandleInformation() failed"); | |
142 #endif | |
143 return stream_ends(child_end, parent_end); | |
144 } | |
145 | |
146 #if defined(BOOST_POSIX_API) | |
147 private: | |
148 stream_type stype_; | |
149 #endif | |
150 }; | |
151 | |
152 /** | |
153 * Stream behavior to redirect streams with a named pipe. | |
154 * | |
155 * A child process will be able to communicate with its parent process. | |
156 */ | |
157 class named_pipe | |
158 { | |
159 public: | |
160 named_pipe(const std::string &name) | |
161 : name_(name) | |
162 #if defined(BOOST_POSIX_API) | |
163 , stype_(unknown_stream) | |
164 #endif | |
165 { | |
166 } | |
167 | |
168 #if defined(BOOST_POSIX_API) | |
169 named_pipe(const std::string &name, stream_type stype) | |
170 : name_(name), | |
171 stype_(stype) | |
172 { | |
173 } | |
174 #endif | |
175 | |
176 stream_ends operator()(stream_type stype) const | |
177 { | |
178 #if defined(BOOST_POSIX_API) | |
179 if (mkfifo(name_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) | |
180 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("mkfifo(3) failed"); | |
181 handle child_end = open(name_.c_str(), O_RDONLY | O_NONBLOCK); | |
182 if (!child_end.valid()) | |
183 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed"); | |
184 int opts = fcntl(child_end.native(), F_GETFL); | |
185 if (opts == -1) | |
186 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed"); | |
187 opts ^= O_NONBLOCK; | |
188 if (fcntl(child_end.native(), F_SETFL, opts) == -1) | |
189 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed"); | |
190 handle parent_end = open(name_.c_str(), O_WRONLY); | |
191 if (!parent_end.valid()) | |
192 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed"); | |
193 if (stype_ != unknown_stream) | |
194 stype = stype_; | |
195 #elif defined(BOOST_WINDOWS_API) | |
196 SECURITY_ATTRIBUTES sa; | |
197 ZeroMemory(&sa, sizeof(sa)); | |
198 sa.nLength = sizeof(sa); | |
199 sa.lpSecurityDescriptor = NULL; | |
200 sa.bInheritHandle = TRUE; | |
201 handle child_end = CreateNamedPipeA(name_.c_str(), PIPE_ACCESS_INBOUND | | |
202 FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa); | |
203 if (!child_end.valid()) | |
204 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateNamedPipe() failed"); | |
205 handle parent_end = CreateFileA(name_.c_str(), GENERIC_WRITE, 0, NULL, | |
206 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); | |
207 if (!parent_end.valid()) | |
208 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed"); | |
209 #endif | |
210 if (stype == output_stream) | |
211 std::swap(child_end, parent_end); | |
212 #if defined(BOOST_WINDOWS_API) | |
213 if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT, | |
214 HANDLE_FLAG_INHERIT)) | |
215 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( | |
216 "SetHandleInformation() failed"); | |
217 #endif | |
218 return stream_ends(child_end, parent_end); | |
219 } | |
220 | |
221 private: | |
222 std::string name_; | |
223 | |
224 #if defined(BOOST_POSIX_API) | |
225 stream_type stype_; | |
226 #endif | |
227 }; | |
228 | |
229 /** | |
230 * Stream behavior to redirect streams with a pipe which supports asynchronous | |
231 * I/O. | |
232 * | |
233 * As platforms require different types of pipes for asynchronous I/O this | |
234 * stream behavior is provided for convenience. It uses the minimum required | |
235 * pipe type on a platform in order to be able to use asynchronous I/O. | |
236 */ | |
237 #if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) | |
238 typedef pipe async_pipe; | |
239 #elif defined(BOOST_WINDOWS_API) | |
240 class async_pipe | |
241 { | |
242 public: | |
243 stream_ends operator()(stream_type stype) const | |
244 { | |
245 UUID uuid; | |
246 RPC_STATUS s = UuidCreateSequential(&uuid); | |
247 if (s != RPC_S_OK && s != RPC_S_UUID_LOCAL_ONLY) | |
248 BOOST_PROCESS_THROW_ERROR(s, "UuidCreateSequential() failed"); | |
249 unsigned char *c; | |
250 s = UuidToStringA(&uuid, &c); | |
251 if (s != RPC_S_OK) | |
252 BOOST_PROCESS_THROW_ERROR(s, "UuidToString() failed"); | |
253 std::string name; | |
254 try | |
255 { | |
256 name = reinterpret_cast<char*>(c); | |
257 } | |
258 catch (...) | |
259 { | |
260 RpcStringFreeA(&c); | |
261 throw; | |
262 } | |
263 RpcStringFreeA(&c); | |
264 named_pipe p("\\\\.\\pipe\\boost_process_" + name); | |
265 return p(stype); | |
266 } | |
267 }; | |
268 #endif | |
269 | |
270 /** | |
271 * Stream behavior to mute streams. | |
272 * | |
273 * A child process will be able to use streams. But data written to an | |
274 * output stream is discarded and data read from an input stream is 0. | |
275 */ | |
276 class null | |
277 { | |
278 public: | |
279 #if defined(BOOST_POSIX_API) | |
280 null() | |
281 : stype_(unknown_stream) | |
282 { | |
283 } | |
284 | |
285 null(stream_type stype) | |
286 : stype_(stype) | |
287 { | |
288 } | |
289 #endif | |
290 | |
291 stream_ends operator()(stream_type stype) const | |
292 { | |
293 #if defined(BOOST_POSIX_API) | |
294 if (stype_ != unknown_stream) | |
295 stype = stype_; | |
296 std::string filename = (stype == input_stream) ? "/dev/zero" : | |
297 "/dev/null"; | |
298 int flag = (stype == input_stream) ? O_RDONLY : O_WRONLY; | |
299 handle child_end = open(filename.c_str(), flag); | |
300 if (!child_end.valid()) | |
301 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed"); | |
302 #elif defined(BOOST_WINDOWS_API) | |
303 DWORD access = (stype == input_stream) ? GENERIC_READ : GENERIC_WRITE; | |
304 handle child_end = CreateFileA("NUL", access, 0, NULL, OPEN_EXISTING, | |
305 FILE_ATTRIBUTE_NORMAL, NULL); | |
306 if (!child_end.valid()) | |
307 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed"); | |
308 if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT, | |
309 HANDLE_FLAG_INHERIT)) | |
310 BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR( | |
311 "SetHandleInformation() failed"); | |
312 #endif | |
313 return stream_ends(child_end, handle()); | |
314 } | |
315 | |
316 #if defined(BOOST_POSIX_API) | |
317 private: | |
318 stream_type stype_; | |
319 #endif | |
320 }; | |
321 | |
322 } | |
323 } | |
324 } | |
325 | |
326 #endif |