// // Boost.Process // ~~~~~~~~~~~~~ // // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008, 2009 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/detail/pipe.hpp * * Includes the declaration of the pipe class. This file is for * internal usage only and must not be included by the library user. */ #ifndef BOOST_PROCESS_DETAIL_PIPE_HPP #define BOOST_PROCESS_DETAIL_PIPE_HPP #include #if defined(BOOST_POSIX_API) # include # include #elif defined(BOOST_WINDOWS_API) # if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) # include # include # endif # include #else # error "Unsupported platform." #endif #include #include #include namespace boost { namespace process { namespace detail { /** * Simple RAII model for anonymous pipes. * * The pipe class is a simple RAII model for anonymous pipes. It * provides a portable constructor that allocates a new %pipe and creates * a pipe object that owns the two file handles associated to it: the * read end and the write end. * * These handles can be retrieved for modification according to * file_handle semantics. Optionally, their ownership can be transferred * to external \a file_handle objects which comes handy when the two * ends need to be used in different places (i.e. after a POSIX fork() * system call). * * Pipes can be copied following the same semantics as file handles. * In other words, copying a %pipe object invalidates the source one. * * \see file_handle */ class pipe { public: /** * Creates a new %pipe. * * The default pipe constructor allocates a new anonymous %pipe * and assigns its ownership to the created pipe object. On Windows * when the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE is defined * a named pipe is created. This is required if asynchronous I/O * should be used as asynchronous I/O is only supported by named * pipes on Windows. * * \throw boost::system::system_error If the anonymous %pipe * creation fails. */ pipe() { file_handle::handle_type hs[2]; #if defined(BOOST_POSIX_API) if (::pipe(hs) == -1) boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::pipe::pipe: pipe(2) failed")); #elif defined(BOOST_WINDOWS_API) SECURITY_ATTRIBUTES sa; ZeroMemory(&sa, sizeof(sa)); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; # if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) static unsigned int nextid = 0; std::string pipe = "\\\\.\\pipe\\boost_process_" + boost::lexical_cast(::GetCurrentProcessId()) + "_" + boost::lexical_cast(nextid++); hs[0] = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa); if (hs[0] == INVALID_HANDLE_VALUE) boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateNamedPipe failed")); hs[1] = ::CreateFileA(pipe.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hs[1] == INVALID_HANDLE_VALUE) boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateFile failed")); OVERLAPPED overlapped; ZeroMemory(&overlapped, sizeof(overlapped)); overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); if (!overlapped.hEvent) boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateEvent failed")); BOOL b = ::ConnectNamedPipe(hs[0], &overlapped); if (!b) { if (::GetLastError() == ERROR_IO_PENDING) { if (::WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_FAILED) { ::CloseHandle(overlapped.hEvent); boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: WaitForSingleObject failed")); } } else if (::GetLastError() != ERROR_PIPE_CONNECTED) { ::CloseHandle(overlapped.hEvent); boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: ConnectNamedPipe failed")); } } ::CloseHandle(overlapped.hEvent); # else if (!::CreatePipe(&hs[0], &hs[1], &sa, 0)) boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreatePipe failed")); # endif #endif read_end_ = file_handle(hs[0]); write_end_ = file_handle(hs[1]); } /** * Returns the %pipe's read end file handle. * * Obtains a reference to the %pipe's read end file handle. Care * should be taken to not duplicate the returned object if ownership * shall remain to the %pipe. * * Duplicating the returned object invalidates its corresponding file * handle in the %pipe. * * \return A reference to the %pipe's read end file handle. */ file_handle &rend() { return read_end_; } /** * Returns the %pipe's write end file handle. * * Obtains a reference to the %pipe's write end file handle. Care * should be taken to not duplicate the returned object if ownership * shall remain to the %pipe. * * Duplicating the returned object invalidates its corresponding file * handle in the %pipe. * * \return A reference to the %pipe's write end file handle. */ file_handle &wend() { return write_end_; } private: /** * The %pipe's read end file handle. */ file_handle read_end_; /** * The %pipe's write end file handle. */ file_handle write_end_; }; } } } #endif