diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/stream_behavior.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,326 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/stream_behavior.hpp
+ *
+ * Includes the declaration of stream behavior classes.
+ */
+
+#ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP
+#define BOOST_PROCESS_STREAM_BEHAVIOR_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <sys/stat.h>
+#   include <fcntl.h>
+#   include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#   include <rpc.h>
+#endif
+
+#include <boost/process/stream_ends.hpp>
+#include <boost/process/stream_type.hpp>
+#include <boost/process/handle.hpp>
+#include <string>
+#include <algorithm>
+
+namespace boost {
+namespace process {
+namespace behavior {
+
+/**
+ * Stream behavior to close streams of a child process.
+ *
+ * A child process will not be able to use the stream.
+ */
+class close
+{
+public:
+    stream_ends operator()(stream_type) const
+    {
+        return stream_ends();
+    }
+};
+
+/**
+ * Stream behavior to make a child process inherit streams.
+ *
+ * A child process will use the very same stream of its parent process.
+ */
+class inherit
+{
+public:
+    inherit(handle::native_type h)
+    : h_(h, handle::dont_close)
+    {
+#if defined(BOOST_WINDOWS_API)
+        if (h != INVALID_HANDLE_VALUE)
+        {
+            if (!SetHandleInformation(h_.native(), HANDLE_FLAG_INHERIT,
+                HANDLE_FLAG_INHERIT))
+            {
+                HANDLE proc = GetCurrentProcess();
+                HANDLE dup;
+                if (!DuplicateHandle(proc, h_.native(), proc, &dup, 0,
+                    TRUE, DUPLICATE_SAME_ACCESS))
+                {
+                    BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                        "DuplicateHandle() failed");
+                }
+                h_ = dup;
+            }
+        }
+#endif
+    }
+
+    stream_ends operator()(stream_type) const
+    {
+        return stream_ends(h_, handle());
+    }
+
+private:
+    handle h_;
+};
+
+/**
+ * Stream behavior to redirect streams with a pipe.
+ *
+ * A child process will be able to communicate with its parent process.
+ */
+class pipe
+{
+public:
+#if defined(BOOST_POSIX_API)
+    pipe()
+    : stype_(unknown_stream)
+    {
+    }
+
+    pipe(stream_type stype)
+    : stype_(stype)
+    {
+    }
+#endif
+
+    stream_ends operator()(stream_type stype) const
+    {
+        handle::native_type ends[2];
+#if defined(BOOST_POSIX_API)
+        if (::pipe(ends) == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("pipe(2) failed");
+        if (stype_ != unknown_stream)
+            stype = stype_;
+#elif defined(BOOST_WINDOWS_API)
+        SECURITY_ATTRIBUTES sa;
+        ZeroMemory(&sa, sizeof(sa));
+        sa.nLength = sizeof(sa);
+        sa.lpSecurityDescriptor = NULL;
+        sa.bInheritHandle = FALSE;
+        if (!CreatePipe(&ends[0], &ends[1], &sa, 0))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreatePipe() failed");
+#endif 
+        handle child_end = ends[stype == input_stream ? 0 : 1];
+        handle parent_end = ends[stype == input_stream ? 1 : 0];
+#if defined(BOOST_WINDOWS_API)
+        if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT,
+            HANDLE_FLAG_INHERIT))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "SetHandleInformation() failed");
+#endif
+        return stream_ends(child_end, parent_end);
+    }
+
+#if defined(BOOST_POSIX_API)
+private:
+    stream_type stype_;
+#endif
+};
+
+/**
+ * Stream behavior to redirect streams with a named pipe.
+ *
+ * A child process will be able to communicate with its parent process.
+ */
+class named_pipe
+{
+public:
+    named_pipe(const std::string &name)
+    : name_(name)
+#if defined(BOOST_POSIX_API)
+    , stype_(unknown_stream)
+#endif
+    {
+    }
+
+#if defined(BOOST_POSIX_API)
+    named_pipe(const std::string &name, stream_type stype)
+    : name_(name),
+    stype_(stype)
+    {
+    }
+#endif
+
+    stream_ends operator()(stream_type stype) const
+    {
+#if defined(BOOST_POSIX_API)
+        if (mkfifo(name_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("mkfifo(3) failed");
+        handle child_end = open(name_.c_str(), O_RDONLY | O_NONBLOCK);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed");
+        int opts = fcntl(child_end.native(), F_GETFL);
+        if (opts == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed");
+        opts ^= O_NONBLOCK;
+        if (fcntl(child_end.native(), F_SETFL, opts) == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed");
+        handle parent_end = open(name_.c_str(), O_WRONLY);
+        if (!parent_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed");
+        if (stype_ != unknown_stream)
+            stype = stype_;
+#elif defined(BOOST_WINDOWS_API)
+        SECURITY_ATTRIBUTES sa;
+        ZeroMemory(&sa, sizeof(sa));
+        sa.nLength = sizeof(sa);
+        sa.lpSecurityDescriptor = NULL;
+        sa.bInheritHandle = TRUE;
+        handle child_end = CreateNamedPipeA(name_.c_str(), PIPE_ACCESS_INBOUND |
+            FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateNamedPipe() failed");
+        handle parent_end = CreateFileA(name_.c_str(), GENERIC_WRITE, 0, NULL,
+            OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+        if (!parent_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed");
+#endif
+        if (stype == output_stream)
+            std::swap(child_end, parent_end);
+#if defined(BOOST_WINDOWS_API)
+        if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT,
+            HANDLE_FLAG_INHERIT))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "SetHandleInformation() failed");
+#endif
+        return stream_ends(child_end, parent_end);
+    }
+
+private:
+    std::string name_;
+
+#if defined(BOOST_POSIX_API)
+    stream_type stype_;
+#endif
+};
+
+/**
+ * Stream behavior to redirect streams with a pipe which supports asynchronous
+ * I/O.
+ *
+ * As platforms require different types of pipes for asynchronous I/O this
+ * stream behavior is provided for convenience. It uses the minimum required
+ * pipe type on a platform in order to be able to use asynchronous I/O.
+ */
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+typedef pipe async_pipe;
+#elif defined(BOOST_WINDOWS_API)
+class async_pipe
+{
+public:
+    stream_ends operator()(stream_type stype) const
+    {
+        UUID uuid;
+        RPC_STATUS s = UuidCreateSequential(&uuid);
+        if (s != RPC_S_OK && s != RPC_S_UUID_LOCAL_ONLY)
+            BOOST_PROCESS_THROW_ERROR(s, "UuidCreateSequential() failed");
+        unsigned char *c;
+        s = UuidToStringA(&uuid, &c);
+        if (s != RPC_S_OK)
+            BOOST_PROCESS_THROW_ERROR(s, "UuidToString() failed");
+        std::string name;
+        try
+        {
+            name = reinterpret_cast<char*>(c);
+        }
+        catch (...)
+        {
+            RpcStringFreeA(&c);
+            throw;
+        }
+        RpcStringFreeA(&c);
+        named_pipe p("\\\\.\\pipe\\boost_process_" + name);
+        return p(stype);
+    }
+};
+#endif
+
+/**
+ * Stream behavior to mute streams.
+ *
+ * A child process will be able to use streams. But data written to an
+ * output stream is discarded and data read from an input stream is 0.
+ */
+class null
+{
+public:
+#if defined(BOOST_POSIX_API)
+    null()
+    : stype_(unknown_stream)
+    {
+    }
+
+    null(stream_type stype)
+    : stype_(stype)
+    {
+    }
+#endif
+
+    stream_ends operator()(stream_type stype) const
+    {
+#if defined(BOOST_POSIX_API)
+        if (stype_ != unknown_stream)
+            stype = stype_;
+        std::string filename = (stype == input_stream) ? "/dev/zero" :
+            "/dev/null";
+        int flag = (stype == input_stream) ? O_RDONLY : O_WRONLY;
+        handle child_end = open(filename.c_str(), flag);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed");
+#elif defined(BOOST_WINDOWS_API)
+        DWORD access = (stype == input_stream) ? GENERIC_READ : GENERIC_WRITE;
+        handle child_end = CreateFileA("NUL", access, 0, NULL, OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL, NULL);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed");
+        if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT,
+            HANDLE_FLAG_INHERIT))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "SetHandleInformation() failed");
+#endif
+        return stream_ends(child_end, handle());
+    }
+
+#if defined(BOOST_POSIX_API)
+private:
+    stream_type stype_;
+#endif
+};
+
+}
+}
+}
+
+#endif