]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // Copyright (c) 2006, 2007 Julio M. Merino Vidal |
2 | // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling | |
3 | // Copyright (c) 2009 Boris Schaeling | |
4 | // Copyright (c) 2010 Felipe Tanus, Boris Schaeling | |
5 | // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling | |
6 | // | |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | ||
10 | #ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP | |
11 | #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP | |
12 | ||
13 | ||
14 | #include <boost/process/detail/posix/handler.hpp> | |
15 | #include <boost/asio/posix/stream_descriptor.hpp> | |
16 | #include <boost/asio/read.hpp> | |
17 | #include <boost/process/async_pipe.hpp> | |
18 | #include <istream> | |
19 | #include <memory> | |
20 | #include <exception> | |
21 | #include <future> | |
92f5a8d4 TL |
22 | #include <array> |
23 | #include <boost/process/detail/used_handles.hpp> | |
b32b8144 FG |
24 | |
25 | namespace boost { namespace process { namespace detail { namespace posix { | |
26 | ||
27 | ||
28 | inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>) | |
29 | { | |
30 | return ::dup2(handle, STDOUT_FILENO); | |
31 | } | |
32 | ||
33 | inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>) | |
34 | { | |
35 | return ::dup2(handle, STDERR_FILENO); | |
36 | } | |
37 | ||
38 | inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>) | |
39 | { | |
40 | if (::dup2(handle, STDOUT_FILENO) == -1) | |
41 | return -1; | |
42 | if (::dup2(handle, STDERR_FILENO) == -1) | |
43 | return -1; | |
44 | ||
45 | return 0; | |
46 | } | |
47 | ||
48 | template<int p1, int p2, typename Buffer> | |
49 | struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext, | |
92f5a8d4 TL |
50 | ::boost::process::detail::posix::require_io_context, |
51 | ::boost::process::detail::uses_handles | |
b32b8144 FG |
52 | { |
53 | Buffer & buf; | |
54 | ||
55 | std::shared_ptr<boost::process::async_pipe> pipe; | |
56 | ||
92f5a8d4 TL |
57 | std::array<int, 4> get_used_handles() |
58 | { | |
59 | const auto pp1 = p1 != -1 ? p1 : p2; | |
60 | const auto pp2 = p2 != -1 ? p2 : p1; | |
61 | ||
62 | if (pipe) | |
63 | return {pipe->native_source(), pipe->native_sink(), pp1, pp2}; | |
64 | else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before. | |
65 | return {pp1, pp2, pp1, pp2}; | |
66 | } | |
67 | ||
b32b8144 FG |
68 | |
69 | async_out_buffer(Buffer & buf) : buf(buf) | |
70 | { | |
71 | } | |
72 | ||
73 | template <typename Executor> | |
74 | inline void on_success(Executor &exec) | |
75 | { | |
76 | auto pipe = this->pipe; | |
77 | boost::asio::async_read(*pipe, buf, | |
92f5a8d4 | 78 | [pipe](const boost::system::error_code&, std::size_t){}); |
b32b8144 FG |
79 | |
80 | this->pipe = nullptr; | |
81 | std::move(*pipe).sink().close(); | |
82 | } | |
83 | ||
84 | template<typename Executor> | |
85 | void on_error(Executor &, const std::error_code &) const | |
86 | { | |
87 | std::move(*pipe).sink().close(); | |
88 | } | |
89 | ||
90 | template<typename Executor> | |
91 | void on_setup(Executor & exec) | |
92 | { | |
93 | pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq)); | |
94 | } | |
95 | ||
96 | ||
97 | template <typename Executor> | |
98 | void on_exec_setup(Executor &exec) | |
99 | { | |
100 | int res = apply_out_handles(pipe->native_sink(), | |
101 | std::integral_constant<int, p1>(), std::integral_constant<int, p2>()); | |
102 | if (res == -1) | |
103 | exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); | |
104 | ||
105 | ::close(pipe->native_sink()); | |
11fdf7f2 TL |
106 | ::close(pipe->native_source()); |
107 | ||
b32b8144 FG |
108 | } |
109 | }; | |
110 | ||
111 | ||
112 | ||
113 | ||
114 | template<int p1, int p2, typename Type> | |
115 | struct async_out_future : ::boost::process::detail::posix::handler_base_ext, | |
116 | ::boost::process::detail::posix::require_io_context | |
117 | { | |
118 | std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>(); | |
119 | ||
120 | std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>(); | |
121 | ||
122 | std::shared_ptr<boost::process::async_pipe> pipe; | |
123 | ||
124 | async_out_future(std::future<Type> & fut) | |
125 | { | |
126 | fut = promise->get_future(); | |
127 | } | |
128 | template <typename Executor> | |
92f5a8d4 | 129 | inline void on_success(Executor &) |
b32b8144 | 130 | { |
92f5a8d4 | 131 | auto pipe_ = this->pipe; |
b32b8144 | 132 | |
92f5a8d4 TL |
133 | auto buffer_ = this->buffer; |
134 | auto promise_ = this->promise; | |
b32b8144 | 135 | |
92f5a8d4 TL |
136 | boost::asio::async_read(*pipe_, *buffer_, |
137 | [pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t) | |
b32b8144 FG |
138 | { |
139 | if (ec && (ec.value() != ENOENT)) | |
140 | { | |
141 | std::error_code e(ec.value(), std::system_category()); | |
92f5a8d4 | 142 | promise_->set_exception(std::make_exception_ptr(process_error(e))); |
b32b8144 FG |
143 | } |
144 | else | |
145 | { | |
92f5a8d4 | 146 | std::istream is (buffer_.get()); |
b32b8144 | 147 | Type arg; |
f67539c2 TL |
148 | if (buffer_->size() > 0) |
149 | { | |
150 | arg.resize(buffer_->size()); | |
151 | is.read(&*arg.begin(), buffer_->size()); | |
152 | } | |
92f5a8d4 | 153 | promise_->set_value(std::move(arg)); |
b32b8144 FG |
154 | } |
155 | }); | |
156 | ||
92f5a8d4 | 157 | std::move(*pipe_).sink().close(); |
b32b8144 FG |
158 | this->pipe = nullptr; |
159 | } | |
160 | ||
161 | template<typename Executor> | |
162 | void on_error(Executor &, const std::error_code &) const | |
163 | { | |
164 | std::move(*pipe).sink().close(); | |
165 | } | |
166 | ||
167 | template<typename Executor> | |
168 | void on_setup(Executor & exec) | |
169 | { | |
170 | pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq)); | |
171 | } | |
172 | ||
173 | template <typename Executor> | |
174 | void on_exec_setup(Executor &exec) | |
175 | { | |
176 | ||
177 | int res = apply_out_handles(pipe->native_sink(), | |
178 | std::integral_constant<int, p1>(), std::integral_constant<int, p2>()); | |
179 | if (res == -1) | |
180 | exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); | |
181 | ||
182 | ::close(pipe->native_sink()); | |
11fdf7f2 | 183 | ::close(pipe->native_source()); |
b32b8144 FG |
184 | } |
185 | ||
186 | }; | |
187 | ||
188 | }}}} | |
189 | ||
190 | #endif |