]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // Copyright (c) 2016 Klemens D. Morgenstern |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | #ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_ | |
7 | #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_ | |
8 | ||
9 | ||
10 | #include <boost/process/detail/posix/basic_pipe.hpp> | |
11 | #include <boost/asio/posix/stream_descriptor.hpp> | |
92f5a8d4 | 12 | #include <boost/asio/post.hpp> |
b32b8144 FG |
13 | #include <system_error> |
14 | #include <string> | |
15 | #include <utility> | |
16 | ||
17 | namespace boost { namespace process { namespace detail { namespace posix { | |
18 | ||
19 | class async_pipe | |
20 | { | |
21 | ::boost::asio::posix::stream_descriptor _source; | |
22 | ::boost::asio::posix::stream_descriptor _sink ; | |
23 | public: | |
24 | typedef int native_handle_type; | |
25 | typedef ::boost::asio::posix::stream_descriptor handle_type; | |
f67539c2 | 26 | typedef typename handle_type::executor_type executor_type; |
b32b8144 FG |
27 | |
28 | inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {} | |
29 | ||
30 | inline async_pipe(boost::asio::io_context & ios_source, | |
31 | boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink) | |
32 | { | |
33 | int fds[2]; | |
34 | if (::pipe(fds) == -1) | |
35 | boost::process::detail::throw_last_error("pipe(2) failed"); | |
36 | ||
37 | _source.assign(fds[0]); | |
38 | _sink .assign(fds[1]); | |
39 | }; | |
40 | inline async_pipe(boost::asio::io_context & ios, const std::string & name) | |
41 | : async_pipe(ios, ios, name) {} | |
42 | ||
43 | inline async_pipe(boost::asio::io_context & ios_source, | |
44 | boost::asio::io_context & io_sink, const std::string & name); | |
45 | inline async_pipe(const async_pipe& lhs); | |
46 | async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink)) | |
47 | { | |
48 | lhs._source.assign (-1); | |
49 | lhs._sink .assign (-1); | |
50 | } | |
51 | ||
52 | template<class CharT, class Traits = std::char_traits<CharT>> | |
53 | explicit async_pipe(::boost::asio::io_context & ios_source, | |
54 | ::boost::asio::io_context & ios_sink, | |
55 | const basic_pipe<CharT, Traits> & p) | |
56 | : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink()) | |
57 | { | |
58 | } | |
59 | ||
60 | template<class CharT, class Traits = std::char_traits<CharT>> | |
61 | explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p) | |
62 | : async_pipe(ios, ios, p) | |
63 | { | |
64 | } | |
65 | ||
66 | template<class CharT, class Traits = std::char_traits<CharT>> | |
67 | inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p); | |
68 | inline async_pipe& operator=(const async_pipe& rhs); | |
69 | ||
70 | inline async_pipe& operator=(async_pipe&& lhs); | |
71 | ||
72 | ~async_pipe() | |
73 | { | |
74 | if (_sink .native_handle() != -1) | |
75 | ::close(_sink.native_handle()); | |
76 | if (_source.native_handle() != -1) | |
77 | ::close(_source.native_handle()); | |
78 | } | |
79 | ||
80 | template<class CharT, class Traits = std::char_traits<CharT>> | |
81 | inline explicit operator basic_pipe<CharT, Traits>() const; | |
82 | ||
83 | void cancel() | |
84 | { | |
85 | if (_sink.is_open()) | |
86 | _sink.cancel(); | |
87 | if (_source.is_open()) | |
88 | _source.cancel(); | |
89 | } | |
90 | ||
91 | void close() | |
92 | { | |
93 | if (_sink.is_open()) | |
94 | _sink.close(); | |
95 | if (_source.is_open()) | |
96 | _source.close(); | |
97 | } | |
98 | void close(boost::system::error_code & ec) | |
99 | { | |
100 | if (_sink.is_open()) | |
101 | _sink.close(ec); | |
102 | if (_source.is_open()) | |
103 | _source.close(ec); | |
104 | } | |
105 | ||
106 | ||
107 | bool is_open() const | |
108 | { | |
109 | return _sink.is_open() || _source.is_open(); | |
110 | } | |
111 | void async_close() | |
112 | { | |
113 | if (_sink.is_open()) | |
92f5a8d4 | 114 | boost::asio::post(_sink.get_executor(), [this]{_sink.close();}); |
b32b8144 | 115 | if (_source.is_open()) |
92f5a8d4 | 116 | boost::asio::post(_source.get_executor(), [this]{_source.close();}); |
b32b8144 FG |
117 | } |
118 | ||
119 | template<typename MutableBufferSequence> | |
120 | std::size_t read_some(const MutableBufferSequence & buffers) | |
121 | { | |
122 | return _source.read_some(buffers); | |
123 | } | |
124 | template<typename MutableBufferSequence> | |
125 | std::size_t write_some(const MutableBufferSequence & buffers) | |
126 | { | |
127 | return _sink.write_some(buffers); | |
128 | } | |
129 | ||
11fdf7f2 TL |
130 | template<typename MutableBufferSequence> |
131 | std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept | |
132 | { | |
133 | return _source.read_some(buffers, ec); | |
134 | } | |
135 | template<typename MutableBufferSequence> | |
136 | std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept | |
137 | { | |
138 | return _sink.write_some(buffers, ec); | |
139 | } | |
140 | ||
141 | ||
b32b8144 FG |
142 | native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();} |
143 | native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();} | |
144 | ||
145 | template<typename MutableBufferSequence, | |
146 | typename ReadHandler> | |
147 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
148 | ReadHandler, void(boost::system::error_code, std::size_t)) | |
149 | async_read_some( | |
150 | const MutableBufferSequence & buffers, | |
151 | ReadHandler &&handler) | |
152 | { | |
92f5a8d4 | 153 | return _source.async_read_some(buffers, std::forward<ReadHandler>(handler)); |
b32b8144 FG |
154 | } |
155 | ||
156 | template<typename ConstBufferSequence, | |
157 | typename WriteHandler> | |
158 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
159 | WriteHandler, void(boost::system::error_code, std::size_t)) | |
160 | async_write_some( | |
161 | const ConstBufferSequence & buffers, | |
162 | WriteHandler&& handler) | |
163 | { | |
92f5a8d4 | 164 | return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler)); |
b32b8144 FG |
165 | } |
166 | ||
167 | ||
168 | const handle_type & sink () const & {return _sink;} | |
169 | const handle_type & source() const & {return _source;} | |
170 | ||
171 | handle_type && sink() && { return std::move(_sink); } | |
172 | handle_type && source()&& { return std::move(_source); } | |
173 | ||
174 | handle_type source(::boost::asio::io_context& ios) && | |
175 | { | |
176 | ::boost::asio::posix::stream_descriptor stolen(ios, _source.release()); | |
177 | return stolen; | |
178 | } | |
179 | handle_type sink (::boost::asio::io_context& ios) && | |
180 | { | |
181 | ::boost::asio::posix::stream_descriptor stolen(ios, _sink.release()); | |
182 | return stolen; | |
183 | } | |
184 | ||
185 | handle_type source(::boost::asio::io_context& ios) const & | |
186 | { | |
187 | auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle(); | |
188 | return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in)); | |
189 | } | |
190 | handle_type sink (::boost::asio::io_context& ios) const & | |
191 | { | |
192 | auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle(); | |
193 | return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in)); | |
194 | } | |
195 | }; | |
196 | ||
197 | ||
198 | async_pipe::async_pipe(boost::asio::io_context & ios_source, | |
199 | boost::asio::io_context & ios_sink, | |
200 | const std::string & name) : _source(ios_source), _sink(ios_sink) | |
201 | { | |
202 | auto fifo = mkfifo(name.c_str(), 0666 ); | |
203 | ||
204 | if (fifo != 0) | |
205 | boost::process::detail::throw_last_error("mkfifo() failed"); | |
206 | ||
207 | ||
208 | int read_fd = open(name.c_str(), O_RDWR); | |
209 | ||
210 | if (read_fd == -1) | |
211 | boost::process::detail::throw_last_error(); | |
212 | ||
213 | int write_fd = dup(read_fd); | |
214 | ||
215 | if (write_fd == -1) | |
216 | boost::process::detail::throw_last_error(); | |
217 | ||
218 | _source.assign(read_fd); | |
219 | _sink .assign(write_fd); | |
220 | } | |
221 | ||
222 | async_pipe::async_pipe(const async_pipe & p) : | |
92f5a8d4 TL |
223 | _source(const_cast<async_pipe&>(p)._source.get_executor()), |
224 | _sink( const_cast<async_pipe&>(p)._sink.get_executor()) | |
b32b8144 FG |
225 | { |
226 | ||
227 | //cannot get the handle from a const object. | |
228 | auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle(); | |
229 | auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle(); | |
230 | if (source_in == -1) | |
231 | _source.assign(-1); | |
232 | else | |
233 | { | |
234 | _source.assign(::dup(source_in)); | |
235 | if (_source.native_handle()== -1) | |
236 | ::boost::process::detail::throw_last_error("dup()"); | |
237 | } | |
238 | ||
239 | if (sink_in == -1) | |
240 | _sink.assign(-1); | |
241 | else | |
242 | { | |
243 | _sink.assign(::dup(sink_in)); | |
244 | if (_sink.native_handle() == -1) | |
245 | ::boost::process::detail::throw_last_error("dup()"); | |
246 | } | |
247 | } | |
248 | ||
249 | async_pipe& async_pipe::operator=(const async_pipe & p) | |
250 | { | |
251 | int source; | |
252 | int sink; | |
253 | ||
254 | //cannot get the handle from a const object. | |
92f5a8d4 TL |
255 | auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle(); |
256 | auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle(); | |
b32b8144 FG |
257 | if (source_in == -1) |
258 | source = -1; | |
259 | else | |
260 | { | |
261 | source = ::dup(source_in); | |
262 | if (source == -1) | |
263 | ::boost::process::detail::throw_last_error("dup()"); | |
264 | } | |
265 | ||
266 | if (sink_in == -1) | |
267 | sink = -1; | |
268 | else | |
269 | { | |
270 | sink = ::dup(sink_in); | |
271 | if (sink == -1) | |
272 | ::boost::process::detail::throw_last_error("dup()"); | |
273 | } | |
274 | _source.assign(source); | |
275 | _sink. assign(sink); | |
276 | ||
277 | return *this; | |
278 | } | |
279 | ||
280 | async_pipe& async_pipe::operator=(async_pipe && lhs) | |
281 | { | |
282 | std::swap(_source, lhs._source); | |
283 | std::swap(_sink, lhs._sink); | |
284 | return *this; | |
285 | } | |
286 | ||
287 | template<class CharT, class Traits> | |
288 | async_pipe::operator basic_pipe<CharT, Traits>() const | |
289 | { | |
290 | int source; | |
291 | int sink; | |
292 | ||
293 | //cannot get the handle from a const object. | |
294 | auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle(); | |
295 | auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle(); | |
296 | ||
297 | ||
298 | if (source_in == -1) | |
299 | source = -1; | |
300 | else | |
301 | { | |
302 | source = ::dup(source_in); | |
303 | if (source == -1) | |
304 | ::boost::process::detail::throw_last_error("dup()"); | |
305 | } | |
306 | ||
307 | if (sink_in == -1) | |
308 | sink = -1; | |
309 | else | |
310 | { | |
311 | sink = ::dup(sink_in); | |
312 | if (sink == -1) | |
313 | ::boost::process::detail::throw_last_error("dup()"); | |
314 | } | |
315 | ||
316 | return basic_pipe<CharT, Traits>{source, sink}; | |
317 | } | |
318 | ||
319 | ||
320 | inline bool operator==(const async_pipe & lhs, const async_pipe & rhs) | |
321 | { | |
322 | return compare_handles(lhs.native_source(), rhs.native_source()) && | |
323 | compare_handles(lhs.native_sink(), rhs.native_sink()); | |
324 | } | |
325 | ||
326 | inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs) | |
327 | { | |
328 | return !compare_handles(lhs.native_source(), rhs.native_source()) || | |
329 | !compare_handles(lhs.native_sink(), rhs.native_sink()); | |
330 | } | |
331 | ||
332 | template<class Char, class Traits> | |
333 | inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs) | |
334 | { | |
335 | return compare_handles(lhs.native_source(), rhs.native_source()) && | |
336 | compare_handles(lhs.native_sink(), rhs.native_sink()); | |
337 | } | |
338 | ||
339 | template<class Char, class Traits> | |
340 | inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs) | |
341 | { | |
342 | return !compare_handles(lhs.native_source(), rhs.native_source()) || | |
343 | !compare_handles(lhs.native_sink(), rhs.native_sink()); | |
344 | } | |
345 | ||
346 | template<class Char, class Traits> | |
347 | inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs) | |
348 | { | |
349 | return compare_handles(lhs.native_source(), rhs.native_source()) && | |
350 | compare_handles(lhs.native_sink(), rhs.native_sink()); | |
351 | } | |
352 | ||
353 | template<class Char, class Traits> | |
354 | inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs) | |
355 | { | |
356 | return !compare_handles(lhs.native_source(), rhs.native_source()) || | |
357 | !compare_handles(lhs.native_sink(), rhs.native_sink()); | |
358 | } | |
359 | ||
360 | }}}} | |
361 | ||
362 | #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */ |