File indexing completed on 2025-01-18 09:50:05
0001
0002
0003
0004
0005
0006
0007
0008
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
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