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