Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:05

0001 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
0002 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
0003 // Copyright (c) 2009 Boris Schaeling
0004 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
0005 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
0011 #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
0012 
0013 
0014 #include <boost/process/detail/posix/handler.hpp>
0015 #include <boost/asio/posix/stream_descriptor.hpp>
0016 #include <boost/asio/read.hpp>
0017 #include <boost/process/async_pipe.hpp>
0018 #include <istream>
0019 #include <memory>
0020 #include <exception>
0021 #include <future>
0022 #include <array>
0023 #include <boost/process/detail/used_handles.hpp>
0024 
0025 namespace boost { namespace process { namespace detail { namespace posix {
0026 
0027 
0028 inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
0029 {
0030     return ::dup2(handle, STDOUT_FILENO);
0031 }
0032 
0033 inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
0034 {
0035     return ::dup2(handle, STDERR_FILENO);
0036 }
0037 
0038 inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
0039 {
0040     if (::dup2(handle, STDOUT_FILENO) == -1)
0041         return -1;
0042     if (::dup2(handle, STDERR_FILENO) == -1)
0043         return -1;
0044 
0045     return 0;
0046 }
0047 
0048 template<int p1, int p2, typename Buffer>
0049 struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
0050                           ::boost::process::detail::posix::require_io_context,
0051                           ::boost::process::detail::uses_handles
0052 {
0053     Buffer & buf;
0054 
0055     std::shared_ptr<boost::process::async_pipe> pipe;
0056 
0057     std::array<int, 4> get_used_handles()
0058     {
0059         const auto pp1 = p1 != -1 ? p1 : p2;
0060         const auto pp2 = p2 != -1 ? p2 : p1;
0061 
0062         if (pipe)
0063             return {pipe->native_source(), pipe->native_sink(), pp1, pp2};
0064         else  //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
0065             return {pp1, pp2, pp1, pp2};
0066     }
0067 
0068 
0069     async_out_buffer(Buffer & buf) : buf(buf)
0070     {
0071     }
0072 
0073     template <typename Executor>
0074     inline void on_success(Executor &)
0075     {
0076         auto  pipe              = this->pipe;
0077         boost::asio::async_read(*pipe, buf,
0078                 [pipe](const boost::system::error_code&, std::size_t){});
0079 
0080         this->pipe = nullptr;
0081         std::move(*pipe).sink().close();
0082     }
0083 
0084     template<typename Executor>
0085     void on_error(Executor &, const std::error_code &) const
0086     {
0087         std::move(*pipe).sink().close();
0088     }
0089 
0090     template<typename Executor>
0091     void on_setup(Executor & exec)
0092     {
0093         pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
0094     }
0095 
0096 
0097     template <typename Executor>
0098     void on_exec_setup(Executor &exec)
0099     {
0100         int res = apply_out_handles(pipe->native_sink(),
0101                       std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
0102         if (res == -1)
0103             exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
0104 
0105         ::close(pipe->native_sink());
0106         ::close(pipe->native_source());
0107 
0108     }
0109 };
0110 
0111 
0112 
0113 
0114 template<int p1, int p2, typename Type>
0115 struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
0116                           ::boost::process::detail::posix::require_io_context
0117 {
0118     std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
0119 
0120     std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
0121 
0122     std::shared_ptr<boost::process::async_pipe> pipe;
0123 
0124     async_out_future(std::future<Type> & fut)
0125     {
0126         fut = promise->get_future();
0127     }
0128     template <typename Executor>
0129     inline void on_success(Executor &)
0130     {
0131         auto pipe_ = this->pipe;
0132 
0133         auto buffer_  = this->buffer;
0134         auto promise_ = this->promise;
0135 
0136         boost::asio::async_read(*pipe_, *buffer_,
0137                 [pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t)
0138                 {
0139                     if (ec && (ec.value() != ENOENT))
0140                     {
0141                         std::error_code e(ec.value(), std::system_category());
0142                         promise_->set_exception(std::make_exception_ptr(process_error(e)));
0143                     }
0144                     else
0145                     {
0146                         std::istream is (buffer_.get());
0147                         Type arg;
0148                         if (buffer_->size() > 0)
0149                         {
0150                             arg.resize(buffer_->size());
0151                             is.read(&*arg.begin(), buffer_->size());
0152                         }
0153                         promise_->set_value(std::move(arg));
0154                     }
0155                 });
0156 
0157         std::move(*pipe_).sink().close();
0158         this->pipe = nullptr;
0159     }
0160 
0161     template<typename Executor>
0162     void on_error(Executor &, const std::error_code &) const
0163     {
0164         std::move(*pipe).sink().close();
0165     }
0166 
0167     template<typename Executor>
0168     void on_setup(Executor & exec)
0169     {
0170         pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
0171     }
0172 
0173     template <typename Executor>
0174     void on_exec_setup(Executor &exec)
0175     {
0176 
0177         int res = apply_out_handles(pipe->native_sink(),
0178                       std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
0179         if (res == -1)
0180             exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
0181 
0182         ::close(pipe->native_sink());
0183         ::close(pipe->native_source());
0184     }
0185 
0186 };
0187 
0188 }}}}
0189 
0190 #endif