1 | // |
2 | // basic_readable_pipe.hpp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
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 | |
11 | #ifndef BOOST_ASIO_BASIC_READABLE_PIPE_HPP |
12 | #define BOOST_ASIO_BASIC_READABLE_PIPE_HPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/config.hpp> |
19 | |
20 | #if defined(BOOST_ASIO_HAS_PIPE) \ |
21 | || defined(GENERATING_DOCUMENTATION) |
22 | |
23 | #include <string> |
24 | #include <utility> |
25 | #include <boost/asio/any_io_executor.hpp> |
26 | #include <boost/asio/async_result.hpp> |
27 | #include <boost/asio/detail/handler_type_requirements.hpp> |
28 | #include <boost/asio/detail/io_object_impl.hpp> |
29 | #include <boost/asio/detail/non_const_lvalue.hpp> |
30 | #include <boost/asio/detail/throw_error.hpp> |
31 | #include <boost/asio/detail/type_traits.hpp> |
32 | #include <boost/asio/error.hpp> |
33 | #include <boost/asio/execution_context.hpp> |
34 | #if defined(BOOST_ASIO_HAS_IOCP) |
35 | # include <boost/asio/detail/win_iocp_handle_service.hpp> |
36 | #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
37 | # include <boost/asio/detail/io_uring_descriptor_service.hpp> |
38 | #else |
39 | # include <boost/asio/detail/reactive_descriptor_service.hpp> |
40 | #endif |
41 | |
42 | #include <boost/asio/detail/push_options.hpp> |
43 | |
44 | namespace boost { |
45 | namespace asio { |
46 | |
47 | /// Provides pipe functionality. |
48 | /** |
49 | * The basic_readable_pipe class provides a wrapper over pipe |
50 | * functionality. |
51 | * |
52 | * @par Thread Safety |
53 | * @e Distinct @e objects: Safe.@n |
54 | * @e Shared @e objects: Unsafe. |
55 | */ |
56 | template <typename Executor = any_io_executor> |
57 | class basic_readable_pipe |
58 | { |
59 | private: |
60 | class initiate_async_read_some; |
61 | |
62 | public: |
63 | /// The type of the executor associated with the object. |
64 | typedef Executor executor_type; |
65 | |
66 | /// Rebinds the pipe type to another executor. |
67 | template <typename Executor1> |
68 | struct rebind_executor |
69 | { |
70 | /// The pipe type when rebound to the specified executor. |
71 | typedef basic_readable_pipe<Executor1> other; |
72 | }; |
73 | |
74 | /// The native representation of a pipe. |
75 | #if defined(GENERATING_DOCUMENTATION) |
76 | typedef implementation_defined native_handle_type; |
77 | #elif defined(BOOST_ASIO_HAS_IOCP) |
78 | typedef detail::win_iocp_handle_service::native_handle_type |
79 | native_handle_type; |
80 | #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
81 | typedef detail::io_uring_descriptor_service::native_handle_type |
82 | native_handle_type; |
83 | #else |
84 | typedef detail::reactive_descriptor_service::native_handle_type |
85 | native_handle_type; |
86 | #endif |
87 | |
88 | /// A basic_readable_pipe is always the lowest layer. |
89 | typedef basic_readable_pipe lowest_layer_type; |
90 | |
91 | /// Construct a basic_readable_pipe without opening it. |
92 | /** |
93 | * This constructor creates a pipe without opening it. |
94 | * |
95 | * @param ex The I/O executor that the pipe will use, by default, to dispatch |
96 | * handlers for any asynchronous operations performed on the pipe. |
97 | */ |
98 | explicit basic_readable_pipe(const executor_type& ex) |
99 | : impl_(0, ex) |
100 | { |
101 | } |
102 | |
103 | /// Construct a basic_readable_pipe without opening it. |
104 | /** |
105 | * This constructor creates a pipe without opening it. |
106 | * |
107 | * @param context An execution context which provides the I/O executor that |
108 | * the pipe will use, by default, to dispatch handlers for any asynchronous |
109 | * operations performed on the pipe. |
110 | */ |
111 | template <typename ExecutionContext> |
112 | explicit basic_readable_pipe(ExecutionContext& context, |
113 | constraint_t< |
114 | is_convertible<ExecutionContext&, execution_context&>::value, |
115 | defaulted_constraint |
116 | > = defaulted_constraint()) |
117 | : impl_(0, 0, context) |
118 | { |
119 | } |
120 | |
121 | /// Construct a basic_readable_pipe on an existing native pipe. |
122 | /** |
123 | * This constructor creates a pipe object to hold an existing native |
124 | * pipe. |
125 | * |
126 | * @param ex The I/O executor that the pipe will use, by default, to |
127 | * dispatch handlers for any asynchronous operations performed on the |
128 | * pipe. |
129 | * |
130 | * @param native_pipe A native pipe. |
131 | * |
132 | * @throws boost::system::system_error Thrown on failure. |
133 | */ |
134 | basic_readable_pipe(const executor_type& ex, |
135 | const native_handle_type& native_pipe) |
136 | : impl_(0, ex) |
137 | { |
138 | boost::system::error_code ec; |
139 | impl_.get_service().assign(impl_.get_implementation(), |
140 | native_pipe, ec); |
141 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
142 | } |
143 | |
144 | /// Construct a basic_readable_pipe on an existing native pipe. |
145 | /** |
146 | * This constructor creates a pipe object to hold an existing native |
147 | * pipe. |
148 | * |
149 | * @param context An execution context which provides the I/O executor that |
150 | * the pipe will use, by default, to dispatch handlers for any |
151 | * asynchronous operations performed on the pipe. |
152 | * |
153 | * @param native_pipe A native pipe. |
154 | * |
155 | * @throws boost::system::system_error Thrown on failure. |
156 | */ |
157 | template <typename ExecutionContext> |
158 | basic_readable_pipe(ExecutionContext& context, |
159 | const native_handle_type& native_pipe, |
160 | constraint_t< |
161 | is_convertible<ExecutionContext&, execution_context&>::value |
162 | > = 0) |
163 | : impl_(0, 0, context) |
164 | { |
165 | boost::system::error_code ec; |
166 | impl_.get_service().assign(impl_.get_implementation(), |
167 | native_pipe, ec); |
168 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
169 | } |
170 | |
171 | /// Move-construct a basic_readable_pipe from another. |
172 | /** |
173 | * This constructor moves a pipe from one object to another. |
174 | * |
175 | * @param other The other basic_readable_pipe object from which the move will |
176 | * occur. |
177 | * |
178 | * @note Following the move, the moved-from object is in the same state as if |
179 | * constructed using the @c basic_readable_pipe(const executor_type&) |
180 | * constructor. |
181 | */ |
182 | basic_readable_pipe(basic_readable_pipe&& other) |
183 | : impl_(std::move(other.impl_)) |
184 | { |
185 | } |
186 | |
187 | /// Move-assign a basic_readable_pipe from another. |
188 | /** |
189 | * This assignment operator moves a pipe from one object to another. |
190 | * |
191 | * @param other The other basic_readable_pipe object from which the move will |
192 | * occur. |
193 | * |
194 | * @note Following the move, the moved-from object is in the same state as if |
195 | * constructed using the @c basic_readable_pipe(const executor_type&) |
196 | * constructor. |
197 | */ |
198 | basic_readable_pipe& operator=(basic_readable_pipe&& other) |
199 | { |
200 | impl_ = std::move(other.impl_); |
201 | return *this; |
202 | } |
203 | |
204 | // All pipes have access to each other's implementations. |
205 | template <typename Executor1> |
206 | friend class basic_readable_pipe; |
207 | |
208 | /// Move-construct a basic_readable_pipe from a pipe of another executor type. |
209 | /** |
210 | * This constructor moves a pipe from one object to another. |
211 | * |
212 | * @param other The other basic_readable_pipe object from which the move will |
213 | * occur. |
214 | * |
215 | * @note Following the move, the moved-from object is in the same state as if |
216 | * constructed using the @c basic_readable_pipe(const executor_type&) |
217 | * constructor. |
218 | */ |
219 | template <typename Executor1> |
220 | basic_readable_pipe(basic_readable_pipe<Executor1>&& other, |
221 | constraint_t< |
222 | is_convertible<Executor1, Executor>::value, |
223 | defaulted_constraint |
224 | > = defaulted_constraint()) |
225 | : impl_(std::move(other.impl_)) |
226 | { |
227 | } |
228 | |
229 | /// Move-assign a basic_readable_pipe from a pipe of another executor type. |
230 | /** |
231 | * This assignment operator moves a pipe from one object to another. |
232 | * |
233 | * @param other The other basic_readable_pipe object from which the move will |
234 | * occur. |
235 | * |
236 | * @note Following the move, the moved-from object is in the same state as if |
237 | * constructed using the @c basic_readable_pipe(const executor_type&) |
238 | * constructor. |
239 | */ |
240 | template <typename Executor1> |
241 | constraint_t< |
242 | is_convertible<Executor1, Executor>::value, |
243 | basic_readable_pipe& |
244 | > operator=(basic_readable_pipe<Executor1>&& other) |
245 | { |
246 | basic_readable_pipe tmp(std::move(other)); |
247 | impl_ = std::move(tmp.impl_); |
248 | return *this; |
249 | } |
250 | |
251 | /// Destroys the pipe. |
252 | /** |
253 | * This function destroys the pipe, cancelling any outstanding |
254 | * asynchronous wait operations associated with the pipe as if by |
255 | * calling @c cancel. |
256 | */ |
257 | ~basic_readable_pipe() |
258 | { |
259 | } |
260 | |
261 | /// Get the executor associated with the object. |
262 | const executor_type& get_executor() noexcept |
263 | { |
264 | return impl_.get_executor(); |
265 | } |
266 | |
267 | /// Get a reference to the lowest layer. |
268 | /** |
269 | * This function returns a reference to the lowest layer in a stack of |
270 | * layers. Since a basic_readable_pipe cannot contain any further layers, it |
271 | * simply returns a reference to itself. |
272 | * |
273 | * @return A reference to the lowest layer in the stack of layers. Ownership |
274 | * is not transferred to the caller. |
275 | */ |
276 | lowest_layer_type& lowest_layer() |
277 | { |
278 | return *this; |
279 | } |
280 | |
281 | /// Get a const reference to the lowest layer. |
282 | /** |
283 | * This function returns a const reference to the lowest layer in a stack of |
284 | * layers. Since a basic_readable_pipe cannot contain any further layers, it |
285 | * simply returns a reference to itself. |
286 | * |
287 | * @return A const reference to the lowest layer in the stack of layers. |
288 | * Ownership is not transferred to the caller. |
289 | */ |
290 | const lowest_layer_type& lowest_layer() const |
291 | { |
292 | return *this; |
293 | } |
294 | |
295 | /// Assign an existing native pipe to the pipe. |
296 | /* |
297 | * This function opens the pipe to hold an existing native pipe. |
298 | * |
299 | * @param native_pipe A native pipe. |
300 | * |
301 | * @throws boost::system::system_error Thrown on failure. |
302 | */ |
303 | void assign(const native_handle_type& native_pipe) |
304 | { |
305 | boost::system::error_code ec; |
306 | impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); |
307 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
308 | } |
309 | |
310 | /// Assign an existing native pipe to the pipe. |
311 | /* |
312 | * This function opens the pipe to hold an existing native pipe. |
313 | * |
314 | * @param native_pipe A native pipe. |
315 | * |
316 | * @param ec Set to indicate what error occurred, if any. |
317 | */ |
318 | BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe, |
319 | boost::system::error_code& ec) |
320 | { |
321 | impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); |
322 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
323 | } |
324 | |
325 | /// Determine whether the pipe is open. |
326 | bool is_open() const |
327 | { |
328 | return impl_.get_service().is_open(impl_.get_implementation()); |
329 | } |
330 | |
331 | /// Close the pipe. |
332 | /** |
333 | * This function is used to close the pipe. Any asynchronous read operations |
334 | * will be cancelled immediately, and will complete with the |
335 | * boost::asio::error::operation_aborted error. |
336 | * |
337 | * @throws boost::system::system_error Thrown on failure. |
338 | */ |
339 | void close() |
340 | { |
341 | boost::system::error_code ec; |
342 | impl_.get_service().close(impl_.get_implementation(), ec); |
343 | boost::asio::detail::throw_error(err: ec, location: "close" ); |
344 | } |
345 | |
346 | /// Close the pipe. |
347 | /** |
348 | * This function is used to close the pipe. Any asynchronous read operations |
349 | * will be cancelled immediately, and will complete with the |
350 | * boost::asio::error::operation_aborted error. |
351 | * |
352 | * @param ec Set to indicate what error occurred, if any. |
353 | */ |
354 | BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) |
355 | { |
356 | impl_.get_service().close(impl_.get_implementation(), ec); |
357 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
358 | } |
359 | |
360 | /// Release ownership of the underlying native pipe. |
361 | /** |
362 | * This function causes all outstanding asynchronous read operations to |
363 | * finish immediately, and the handlers for cancelled operations will be |
364 | * passed the boost::asio::error::operation_aborted error. Ownership of the |
365 | * native pipe is then transferred to the caller. |
366 | * |
367 | * @throws boost::system::system_error Thrown on failure. |
368 | * |
369 | * @note This function is unsupported on Windows versions prior to Windows |
370 | * 8.1, and will fail with boost::asio::error::operation_not_supported on |
371 | * these platforms. |
372 | */ |
373 | #if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ |
374 | && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) |
375 | __declspec(deprecated("This function always fails with " |
376 | "operation_not_supported when used on Windows versions " |
377 | "prior to Windows 8.1." )) |
378 | #endif |
379 | native_handle_type release() |
380 | { |
381 | boost::system::error_code ec; |
382 | native_handle_type s = impl_.get_service().release( |
383 | impl_.get_implementation(), ec); |
384 | boost::asio::detail::throw_error(err: ec, location: "release" ); |
385 | return s; |
386 | } |
387 | |
388 | /// Release ownership of the underlying native pipe. |
389 | /** |
390 | * This function causes all outstanding asynchronous read operations to |
391 | * finish immediately, and the handlers for cancelled operations will be |
392 | * passed the boost::asio::error::operation_aborted error. Ownership of the |
393 | * native pipe is then transferred to the caller. |
394 | * |
395 | * @param ec Set to indicate what error occurred, if any. |
396 | * |
397 | * @note This function is unsupported on Windows versions prior to Windows |
398 | * 8.1, and will fail with boost::asio::error::operation_not_supported on |
399 | * these platforms. |
400 | */ |
401 | #if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ |
402 | && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) |
403 | __declspec(deprecated("This function always fails with " |
404 | "operation_not_supported when used on Windows versions " |
405 | "prior to Windows 8.1." )) |
406 | #endif |
407 | native_handle_type release(boost::system::error_code& ec) |
408 | { |
409 | return impl_.get_service().release(impl_.get_implementation(), ec); |
410 | } |
411 | |
412 | /// Get the native pipe representation. |
413 | /** |
414 | * This function may be used to obtain the underlying representation of the |
415 | * pipe. This is intended to allow access to native pipe |
416 | * functionality that is not otherwise provided. |
417 | */ |
418 | native_handle_type native_handle() |
419 | { |
420 | return impl_.get_service().native_handle(impl_.get_implementation()); |
421 | } |
422 | |
423 | /// Cancel all asynchronous operations associated with the pipe. |
424 | /** |
425 | * This function causes all outstanding asynchronous read operations to finish |
426 | * immediately, and the handlers for cancelled operations will be passed the |
427 | * boost::asio::error::operation_aborted error. |
428 | * |
429 | * @throws boost::system::system_error Thrown on failure. |
430 | */ |
431 | void cancel() |
432 | { |
433 | boost::system::error_code ec; |
434 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
435 | boost::asio::detail::throw_error(err: ec, location: "cancel" ); |
436 | } |
437 | |
438 | /// Cancel all asynchronous operations associated with the pipe. |
439 | /** |
440 | * This function causes all outstanding asynchronous read operations to finish |
441 | * immediately, and the handlers for cancelled operations will be passed the |
442 | * boost::asio::error::operation_aborted error. |
443 | * |
444 | * @param ec Set to indicate what error occurred, if any. |
445 | */ |
446 | BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) |
447 | { |
448 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
449 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
450 | } |
451 | |
452 | /// Read some data from the pipe. |
453 | /** |
454 | * This function is used to read data from the pipe. The function call will |
455 | * block until one or more bytes of data has been read successfully, or until |
456 | * an error occurs. |
457 | * |
458 | * @param buffers One or more buffers into which the data will be read. |
459 | * |
460 | * @returns The number of bytes read. |
461 | * |
462 | * @throws boost::system::system_error Thrown on failure. An error code of |
463 | * boost::asio::error::eof indicates that the connection was closed by the |
464 | * peer. |
465 | * |
466 | * @note The read_some operation may not read all of the requested number of |
467 | * bytes. Consider using the @ref read function if you need to ensure that |
468 | * the requested amount of data is read before the blocking operation |
469 | * completes. |
470 | * |
471 | * @par Example |
472 | * To read into a single data buffer use the @ref buffer function as follows: |
473 | * @code |
474 | * basic_readable_pipe.read_some(boost::asio::buffer(data, size)); |
475 | * @endcode |
476 | * See the @ref buffer documentation for information on reading into multiple |
477 | * buffers in one go, and how to use it with arrays, boost::array or |
478 | * std::vector. |
479 | */ |
480 | template <typename MutableBufferSequence> |
481 | std::size_t read_some(const MutableBufferSequence& buffers) |
482 | { |
483 | boost::system::error_code ec; |
484 | std::size_t s = impl_.get_service().read_some( |
485 | impl_.get_implementation(), buffers, ec); |
486 | boost::asio::detail::throw_error(err: ec, location: "read_some" ); |
487 | return s; |
488 | } |
489 | |
490 | /// Read some data from the pipe. |
491 | /** |
492 | * This function is used to read data from the pipe. The function call will |
493 | * block until one or more bytes of data has been read successfully, or until |
494 | * an error occurs. |
495 | * |
496 | * @param buffers One or more buffers into which the data will be read. |
497 | * |
498 | * @param ec Set to indicate what error occurred, if any. |
499 | * |
500 | * @returns The number of bytes read. Returns 0 if an error occurred. |
501 | * |
502 | * @note The read_some operation may not read all of the requested number of |
503 | * bytes. Consider using the @ref read function if you need to ensure that |
504 | * the requested amount of data is read before the blocking operation |
505 | * completes. |
506 | */ |
507 | template <typename MutableBufferSequence> |
508 | std::size_t read_some(const MutableBufferSequence& buffers, |
509 | boost::system::error_code& ec) |
510 | { |
511 | return impl_.get_service().read_some( |
512 | impl_.get_implementation(), buffers, ec); |
513 | } |
514 | |
515 | /// Start an asynchronous read. |
516 | /** |
517 | * This function is used to asynchronously read data from the pipe. It is an |
518 | * initiating function for an @ref asynchronous_operation, and always returns |
519 | * immediately. |
520 | * |
521 | * @param buffers One or more buffers into which the data will be read. |
522 | * Although the buffers object may be copied as necessary, ownership of the |
523 | * underlying memory blocks is retained by the caller, which must guarantee |
524 | * that they remain valid until the completion handler is called. |
525 | * |
526 | * @param token The @ref completion_token that will be used to produce a |
527 | * completion handler, which will be called when the read completes. |
528 | * Potential completion tokens include @ref use_future, @ref use_awaitable, |
529 | * @ref yield_context, or a function object with the correct completion |
530 | * signature. The function signature of the completion handler must be: |
531 | * @code void handler( |
532 | * const boost::system::error_code& error, // Result of operation. |
533 | * std::size_t bytes_transferred // Number of bytes read. |
534 | * ); @endcode |
535 | * Regardless of whether the asynchronous operation completes immediately or |
536 | * not, the completion handler will not be invoked from within this function. |
537 | * On immediate completion, invocation of the handler will be performed in a |
538 | * manner equivalent to using boost::asio::post(). |
539 | * |
540 | * @par Completion Signature |
541 | * @code void(boost::system::error_code, std::size_t) @endcode |
542 | * |
543 | * @note The read operation may not read all of the requested number of bytes. |
544 | * Consider using the @ref async_read function if you need to ensure that the |
545 | * requested amount of data is read before the asynchronous operation |
546 | * completes. |
547 | * |
548 | * @par Example |
549 | * To read into a single data buffer use the @ref buffer function as follows: |
550 | * @code |
551 | * basic_readable_pipe.async_read_some( |
552 | * boost::asio::buffer(data, size), handler); |
553 | * @endcode |
554 | * See the @ref buffer documentation for information on reading into multiple |
555 | * buffers in one go, and how to use it with arrays, boost::array or |
556 | * std::vector. |
557 | */ |
558 | template <typename MutableBufferSequence, |
559 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
560 | std::size_t)) ReadToken = default_completion_token_t<executor_type>> |
561 | auto async_read_some(const MutableBufferSequence& buffers, |
562 | ReadToken&& token = default_completion_token_t<executor_type>()) |
563 | -> decltype( |
564 | async_initiate<ReadToken, |
565 | void (boost::system::error_code, std::size_t)>( |
566 | declval<initiate_async_read_some>(), token, buffers)) |
567 | { |
568 | return async_initiate<ReadToken, |
569 | void (boost::system::error_code, std::size_t)>( |
570 | initiate_async_read_some(this), token, buffers); |
571 | } |
572 | |
573 | private: |
574 | // Disallow copying and assignment. |
575 | basic_readable_pipe(const basic_readable_pipe&) = delete; |
576 | basic_readable_pipe& operator=(const basic_readable_pipe&) = delete; |
577 | |
578 | class initiate_async_read_some |
579 | { |
580 | public: |
581 | typedef Executor executor_type; |
582 | |
583 | explicit initiate_async_read_some(basic_readable_pipe* self) |
584 | : self_(self) |
585 | { |
586 | } |
587 | |
588 | const executor_type& get_executor() const noexcept |
589 | { |
590 | return self_->get_executor(); |
591 | } |
592 | |
593 | template <typename ReadHandler, typename MutableBufferSequence> |
594 | void operator()(ReadHandler&& handler, |
595 | const MutableBufferSequence& buffers) const |
596 | { |
597 | // If you get an error on the following line it means that your handler |
598 | // does not meet the documented type requirements for a ReadHandler. |
599 | BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; |
600 | |
601 | detail::non_const_lvalue<ReadHandler> handler2(handler); |
602 | self_->impl_.get_service().async_read_some( |
603 | self_->impl_.get_implementation(), buffers, |
604 | handler2.value, self_->impl_.get_executor()); |
605 | } |
606 | |
607 | private: |
608 | basic_readable_pipe* self_; |
609 | }; |
610 | |
611 | #if defined(BOOST_ASIO_HAS_IOCP) |
612 | detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_; |
613 | #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
614 | detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_; |
615 | #else |
616 | detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_; |
617 | #endif |
618 | }; |
619 | |
620 | } // namespace asio |
621 | } // namespace boost |
622 | |
623 | #include <boost/asio/detail/pop_options.hpp> |
624 | |
625 | #endif // defined(BOOST_ASIO_HAS_PIPE) |
626 | // || defined(GENERATING_DOCUMENTATION) |
627 | |
628 | #endif // BOOST_ASIO_BASIC_READABLE_PIPE_HPP |
629 | |