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