|
||||
File indexing completed on 2025-01-18 09:29:05
0001 // 0002 // basic_readable_pipe.hpp 0003 // ~~~~~~~~~~~~~~~~~~~~~~~ 0004 // 0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) 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 0011 #ifndef BOOST_ASIO_BASIC_READABLE_PIPE_HPP 0012 #define BOOST_ASIO_BASIC_READABLE_PIPE_HPP 0013 0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 0015 # pragma once 0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 0017 0018 #include <boost/asio/detail/config.hpp> 0019 0020 #if defined(BOOST_ASIO_HAS_PIPE) \ 0021 || defined(GENERATING_DOCUMENTATION) 0022 0023 #include <string> 0024 #include <utility> 0025 #include <boost/asio/any_io_executor.hpp> 0026 #include <boost/asio/async_result.hpp> 0027 #include <boost/asio/detail/handler_type_requirements.hpp> 0028 #include <boost/asio/detail/io_object_impl.hpp> 0029 #include <boost/asio/detail/non_const_lvalue.hpp> 0030 #include <boost/asio/detail/throw_error.hpp> 0031 #include <boost/asio/detail/type_traits.hpp> 0032 #include <boost/asio/error.hpp> 0033 #include <boost/asio/execution_context.hpp> 0034 #if defined(BOOST_ASIO_HAS_IOCP) 0035 # include <boost/asio/detail/win_iocp_handle_service.hpp> 0036 #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) 0037 # include <boost/asio/detail/io_uring_descriptor_service.hpp> 0038 #else 0039 # include <boost/asio/detail/reactive_descriptor_service.hpp> 0040 #endif 0041 0042 #include <boost/asio/detail/push_options.hpp> 0043 0044 namespace boost { 0045 namespace asio { 0046 0047 /// Provides pipe functionality. 0048 /** 0049 * The basic_readable_pipe class provides a wrapper over pipe 0050 * functionality. 0051 * 0052 * @par Thread Safety 0053 * @e Distinct @e objects: Safe.@n 0054 * @e Shared @e objects: Unsafe. 0055 */ 0056 template <typename Executor = any_io_executor> 0057 class basic_readable_pipe 0058 { 0059 private: 0060 class initiate_async_read_some; 0061 0062 public: 0063 /// The type of the executor associated with the object. 0064 typedef Executor executor_type; 0065 0066 /// Rebinds the pipe type to another executor. 0067 template <typename Executor1> 0068 struct rebind_executor 0069 { 0070 /// The pipe type when rebound to the specified executor. 0071 typedef basic_readable_pipe<Executor1> other; 0072 }; 0073 0074 /// The native representation of a pipe. 0075 #if defined(GENERATING_DOCUMENTATION) 0076 typedef implementation_defined native_handle_type; 0077 #elif defined(BOOST_ASIO_HAS_IOCP) 0078 typedef detail::win_iocp_handle_service::native_handle_type 0079 native_handle_type; 0080 #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) 0081 typedef detail::io_uring_descriptor_service::native_handle_type 0082 native_handle_type; 0083 #else 0084 typedef detail::reactive_descriptor_service::native_handle_type 0085 native_handle_type; 0086 #endif 0087 0088 /// A basic_readable_pipe is always the lowest layer. 0089 typedef basic_readable_pipe lowest_layer_type; 0090 0091 /// Construct a basic_readable_pipe without opening it. 0092 /** 0093 * This constructor creates a pipe without opening it. 0094 * 0095 * @param ex The I/O executor that the pipe will use, by default, to dispatch 0096 * handlers for any asynchronous operations performed on the pipe. 0097 */ 0098 explicit basic_readable_pipe(const executor_type& ex) 0099 : impl_(0, ex) 0100 { 0101 } 0102 0103 /// Construct a basic_readable_pipe without opening it. 0104 /** 0105 * This constructor creates a pipe without opening it. 0106 * 0107 * @param context An execution context which provides the I/O executor that 0108 * the pipe will use, by default, to dispatch handlers for any asynchronous 0109 * operations performed on the pipe. 0110 */ 0111 template <typename ExecutionContext> 0112 explicit basic_readable_pipe(ExecutionContext& context, 0113 constraint_t< 0114 is_convertible<ExecutionContext&, execution_context&>::value, 0115 defaulted_constraint 0116 > = defaulted_constraint()) 0117 : impl_(0, 0, context) 0118 { 0119 } 0120 0121 /// Construct a basic_readable_pipe on an existing native pipe. 0122 /** 0123 * This constructor creates a pipe object to hold an existing native 0124 * pipe. 0125 * 0126 * @param ex The I/O executor that the pipe will use, by default, to 0127 * dispatch handlers for any asynchronous operations performed on the 0128 * pipe. 0129 * 0130 * @param native_pipe A native pipe. 0131 * 0132 * @throws boost::system::system_error Thrown on failure. 0133 */ 0134 basic_readable_pipe(const executor_type& ex, 0135 const native_handle_type& native_pipe) 0136 : impl_(0, ex) 0137 { 0138 boost::system::error_code ec; 0139 impl_.get_service().assign(impl_.get_implementation(), 0140 native_pipe, ec); 0141 boost::asio::detail::throw_error(ec, "assign"); 0142 } 0143 0144 /// Construct a basic_readable_pipe on an existing native pipe. 0145 /** 0146 * This constructor creates a pipe object to hold an existing native 0147 * pipe. 0148 * 0149 * @param context An execution context which provides the I/O executor that 0150 * the pipe will use, by default, to dispatch handlers for any 0151 * asynchronous operations performed on the pipe. 0152 * 0153 * @param native_pipe A native pipe. 0154 * 0155 * @throws boost::system::system_error Thrown on failure. 0156 */ 0157 template <typename ExecutionContext> 0158 basic_readable_pipe(ExecutionContext& context, 0159 const native_handle_type& native_pipe, 0160 constraint_t< 0161 is_convertible<ExecutionContext&, execution_context&>::value 0162 > = 0) 0163 : impl_(0, 0, context) 0164 { 0165 boost::system::error_code ec; 0166 impl_.get_service().assign(impl_.get_implementation(), 0167 native_pipe, ec); 0168 boost::asio::detail::throw_error(ec, "assign"); 0169 } 0170 0171 /// Move-construct a basic_readable_pipe from another. 0172 /** 0173 * This constructor moves a pipe from one object to another. 0174 * 0175 * @param other The other basic_readable_pipe object from which the move will 0176 * occur. 0177 * 0178 * @note Following the move, the moved-from object is in the same state as if 0179 * constructed using the @c basic_readable_pipe(const executor_type&) 0180 * constructor. 0181 */ 0182 basic_readable_pipe(basic_readable_pipe&& other) 0183 : impl_(std::move(other.impl_)) 0184 { 0185 } 0186 0187 /// Move-assign a basic_readable_pipe from another. 0188 /** 0189 * This assignment operator moves a pipe from one object to another. 0190 * 0191 * @param other The other basic_readable_pipe object from which the move will 0192 * occur. 0193 * 0194 * @note Following the move, the moved-from object is in the same state as if 0195 * constructed using the @c basic_readable_pipe(const executor_type&) 0196 * constructor. 0197 */ 0198 basic_readable_pipe& operator=(basic_readable_pipe&& other) 0199 { 0200 impl_ = std::move(other.impl_); 0201 return *this; 0202 } 0203 0204 // All pipes have access to each other's implementations. 0205 template <typename Executor1> 0206 friend class basic_readable_pipe; 0207 0208 /// Move-construct a basic_readable_pipe from a pipe of another executor type. 0209 /** 0210 * This constructor moves a pipe from one object to another. 0211 * 0212 * @param other The other basic_readable_pipe object from which the move will 0213 * occur. 0214 * 0215 * @note Following the move, the moved-from object is in the same state as if 0216 * constructed using the @c basic_readable_pipe(const executor_type&) 0217 * constructor. 0218 */ 0219 template <typename Executor1> 0220 basic_readable_pipe(basic_readable_pipe<Executor1>&& other, 0221 constraint_t< 0222 is_convertible<Executor1, Executor>::value, 0223 defaulted_constraint 0224 > = defaulted_constraint()) 0225 : impl_(std::move(other.impl_)) 0226 { 0227 } 0228 0229 /// Move-assign a basic_readable_pipe from a pipe of another executor type. 0230 /** 0231 * This assignment operator moves a pipe from one object to another. 0232 * 0233 * @param other The other basic_readable_pipe object from which the move will 0234 * occur. 0235 * 0236 * @note Following the move, the moved-from object is in the same state as if 0237 * constructed using the @c basic_readable_pipe(const executor_type&) 0238 * constructor. 0239 */ 0240 template <typename Executor1> 0241 constraint_t< 0242 is_convertible<Executor1, Executor>::value, 0243 basic_readable_pipe& 0244 > operator=(basic_readable_pipe<Executor1>&& other) 0245 { 0246 basic_readable_pipe tmp(std::move(other)); 0247 impl_ = std::move(tmp.impl_); 0248 return *this; 0249 } 0250 0251 /// Destroys the pipe. 0252 /** 0253 * This function destroys the pipe, cancelling any outstanding 0254 * asynchronous wait operations associated with the pipe as if by 0255 * calling @c cancel. 0256 */ 0257 ~basic_readable_pipe() 0258 { 0259 } 0260 0261 /// Get the executor associated with the object. 0262 const executor_type& get_executor() noexcept 0263 { 0264 return impl_.get_executor(); 0265 } 0266 0267 /// Get a reference to the lowest layer. 0268 /** 0269 * This function returns a reference to the lowest layer in a stack of 0270 * layers. Since a basic_readable_pipe cannot contain any further layers, it 0271 * simply returns a reference to itself. 0272 * 0273 * @return A reference to the lowest layer in the stack of layers. Ownership 0274 * is not transferred to the caller. 0275 */ 0276 lowest_layer_type& lowest_layer() 0277 { 0278 return *this; 0279 } 0280 0281 /// Get a const reference to the lowest layer. 0282 /** 0283 * This function returns a const reference to the lowest layer in a stack of 0284 * layers. Since a basic_readable_pipe cannot contain any further layers, it 0285 * simply returns a reference to itself. 0286 * 0287 * @return A const reference to the lowest layer in the stack of layers. 0288 * Ownership is not transferred to the caller. 0289 */ 0290 const lowest_layer_type& lowest_layer() const 0291 { 0292 return *this; 0293 } 0294 0295 /// Assign an existing native pipe to the pipe. 0296 /* 0297 * This function opens the pipe to hold an existing native pipe. 0298 * 0299 * @param native_pipe A native pipe. 0300 * 0301 * @throws boost::system::system_error Thrown on failure. 0302 */ 0303 void assign(const native_handle_type& native_pipe) 0304 { 0305 boost::system::error_code ec; 0306 impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); 0307 boost::asio::detail::throw_error(ec, "assign"); 0308 } 0309 0310 /// Assign an existing native pipe to the pipe. 0311 /* 0312 * This function opens the pipe to hold an existing native pipe. 0313 * 0314 * @param native_pipe A native pipe. 0315 * 0316 * @param ec Set to indicate what error occurred, if any. 0317 */ 0318 BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe, 0319 boost::system::error_code& ec) 0320 { 0321 impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); 0322 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 0323 } 0324 0325 /// Determine whether the pipe is open. 0326 bool is_open() const 0327 { 0328 return impl_.get_service().is_open(impl_.get_implementation()); 0329 } 0330 0331 /// Close the pipe. 0332 /** 0333 * This function is used to close the pipe. Any asynchronous read operations 0334 * will be cancelled immediately, and will complete with the 0335 * boost::asio::error::operation_aborted error. 0336 * 0337 * @throws boost::system::system_error Thrown on failure. 0338 */ 0339 void close() 0340 { 0341 boost::system::error_code ec; 0342 impl_.get_service().close(impl_.get_implementation(), ec); 0343 boost::asio::detail::throw_error(ec, "close"); 0344 } 0345 0346 /// Close the pipe. 0347 /** 0348 * This function is used to close the pipe. Any asynchronous read operations 0349 * will be cancelled immediately, and will complete with the 0350 * boost::asio::error::operation_aborted error. 0351 * 0352 * @param ec Set to indicate what error occurred, if any. 0353 */ 0354 BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) 0355 { 0356 impl_.get_service().close(impl_.get_implementation(), ec); 0357 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 0358 } 0359 0360 /// Release ownership of the underlying native pipe. 0361 /** 0362 * This function causes all outstanding asynchronous read operations to 0363 * finish immediately, and the handlers for cancelled operations will be 0364 * passed the boost::asio::error::operation_aborted error. Ownership of the 0365 * native pipe is then transferred to the caller. 0366 * 0367 * @throws boost::system::system_error Thrown on failure. 0368 * 0369 * @note This function is unsupported on Windows versions prior to Windows 0370 * 8.1, and will fail with boost::asio::error::operation_not_supported on 0371 * these platforms. 0372 */ 0373 #if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ 0374 && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) 0375 __declspec(deprecated("This function always fails with " 0376 "operation_not_supported when used on Windows versions " 0377 "prior to Windows 8.1.")) 0378 #endif 0379 native_handle_type release() 0380 { 0381 boost::system::error_code ec; 0382 native_handle_type s = impl_.get_service().release( 0383 impl_.get_implementation(), ec); 0384 boost::asio::detail::throw_error(ec, "release"); 0385 return s; 0386 } 0387 0388 /// Release ownership of the underlying native pipe. 0389 /** 0390 * This function causes all outstanding asynchronous read operations to 0391 * finish immediately, and the handlers for cancelled operations will be 0392 * passed the boost::asio::error::operation_aborted error. Ownership of the 0393 * native pipe is then transferred to the caller. 0394 * 0395 * @param ec Set to indicate what error occurred, if any. 0396 * 0397 * @note This function is unsupported on Windows versions prior to Windows 0398 * 8.1, and will fail with boost::asio::error::operation_not_supported on 0399 * these platforms. 0400 */ 0401 #if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ 0402 && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) 0403 __declspec(deprecated("This function always fails with " 0404 "operation_not_supported when used on Windows versions " 0405 "prior to Windows 8.1.")) 0406 #endif 0407 native_handle_type release(boost::system::error_code& ec) 0408 { 0409 return impl_.get_service().release(impl_.get_implementation(), ec); 0410 } 0411 0412 /// Get the native pipe representation. 0413 /** 0414 * This function may be used to obtain the underlying representation of the 0415 * pipe. This is intended to allow access to native pipe 0416 * functionality that is not otherwise provided. 0417 */ 0418 native_handle_type native_handle() 0419 { 0420 return impl_.get_service().native_handle(impl_.get_implementation()); 0421 } 0422 0423 /// Cancel all asynchronous operations associated with the pipe. 0424 /** 0425 * This function causes all outstanding asynchronous read operations to finish 0426 * immediately, and the handlers for cancelled operations will be passed the 0427 * boost::asio::error::operation_aborted error. 0428 * 0429 * @throws boost::system::system_error Thrown on failure. 0430 */ 0431 void cancel() 0432 { 0433 boost::system::error_code ec; 0434 impl_.get_service().cancel(impl_.get_implementation(), ec); 0435 boost::asio::detail::throw_error(ec, "cancel"); 0436 } 0437 0438 /// Cancel all asynchronous operations associated with the pipe. 0439 /** 0440 * This function causes all outstanding asynchronous read operations to finish 0441 * immediately, and the handlers for cancelled operations will be passed the 0442 * boost::asio::error::operation_aborted error. 0443 * 0444 * @param ec Set to indicate what error occurred, if any. 0445 */ 0446 BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) 0447 { 0448 impl_.get_service().cancel(impl_.get_implementation(), ec); 0449 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 0450 } 0451 0452 /// Read some data from the pipe. 0453 /** 0454 * This function is used to read data from the pipe. The function call will 0455 * block until one or more bytes of data has been read successfully, or until 0456 * an error occurs. 0457 * 0458 * @param buffers One or more buffers into which the data will be read. 0459 * 0460 * @returns The number of bytes read. 0461 * 0462 * @throws boost::system::system_error Thrown on failure. An error code of 0463 * boost::asio::error::eof indicates that the connection was closed by the 0464 * peer. 0465 * 0466 * @note The read_some operation may not read all of the requested number of 0467 * bytes. Consider using the @ref read function if you need to ensure that 0468 * the requested amount of data is read before the blocking operation 0469 * completes. 0470 * 0471 * @par Example 0472 * To read into a single data buffer use the @ref buffer function as follows: 0473 * @code 0474 * basic_readable_pipe.read_some(boost::asio::buffer(data, size)); 0475 * @endcode 0476 * See the @ref buffer documentation for information on reading into multiple 0477 * buffers in one go, and how to use it with arrays, boost::array or 0478 * std::vector. 0479 */ 0480 template <typename MutableBufferSequence> 0481 std::size_t read_some(const MutableBufferSequence& buffers) 0482 { 0483 boost::system::error_code ec; 0484 std::size_t s = impl_.get_service().read_some( 0485 impl_.get_implementation(), buffers, ec); 0486 boost::asio::detail::throw_error(ec, "read_some"); 0487 return s; 0488 } 0489 0490 /// Read some data from the pipe. 0491 /** 0492 * This function is used to read data from the pipe. The function call will 0493 * block until one or more bytes of data has been read successfully, or until 0494 * an error occurs. 0495 * 0496 * @param buffers One or more buffers into which the data will be read. 0497 * 0498 * @param ec Set to indicate what error occurred, if any. 0499 * 0500 * @returns The number of bytes read. Returns 0 if an error occurred. 0501 * 0502 * @note The read_some operation may not read all of the requested number of 0503 * bytes. Consider using the @ref read function if you need to ensure that 0504 * the requested amount of data is read before the blocking operation 0505 * completes. 0506 */ 0507 template <typename MutableBufferSequence> 0508 std::size_t read_some(const MutableBufferSequence& buffers, 0509 boost::system::error_code& ec) 0510 { 0511 return impl_.get_service().read_some( 0512 impl_.get_implementation(), buffers, ec); 0513 } 0514 0515 /// Start an asynchronous read. 0516 /** 0517 * This function is used to asynchronously read data from the pipe. It is an 0518 * initiating function for an @ref asynchronous_operation, and always returns 0519 * immediately. 0520 * 0521 * @param buffers One or more buffers into which the data will be read. 0522 * Although the buffers object may be copied as necessary, ownership of the 0523 * underlying memory blocks is retained by the caller, which must guarantee 0524 * that they remain valid until the completion handler is called. 0525 * 0526 * @param token The @ref completion_token that will be used to produce a 0527 * completion handler, which will be called when the read completes. 0528 * Potential completion tokens include @ref use_future, @ref use_awaitable, 0529 * @ref yield_context, or a function object with the correct completion 0530 * signature. The function signature of the completion handler must be: 0531 * @code void handler( 0532 * const boost::system::error_code& error, // Result of operation. 0533 * std::size_t bytes_transferred // Number of bytes read. 0534 * ); @endcode 0535 * Regardless of whether the asynchronous operation completes immediately or 0536 * not, the completion handler will not be invoked from within this function. 0537 * On immediate completion, invocation of the handler will be performed in a 0538 * manner equivalent to using boost::asio::post(). 0539 * 0540 * @par Completion Signature 0541 * @code void(boost::system::error_code, std::size_t) @endcode 0542 * 0543 * @note The read operation may not read all of the requested number of bytes. 0544 * Consider using the @ref async_read function if you need to ensure that the 0545 * requested amount of data is read before the asynchronous operation 0546 * completes. 0547 * 0548 * @par Example 0549 * To read into a single data buffer use the @ref buffer function as follows: 0550 * @code 0551 * basic_readable_pipe.async_read_some( 0552 * boost::asio::buffer(data, size), handler); 0553 * @endcode 0554 * See the @ref buffer documentation for information on reading into multiple 0555 * buffers in one go, and how to use it with arrays, boost::array or 0556 * std::vector. 0557 */ 0558 template <typename MutableBufferSequence, 0559 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, 0560 std::size_t)) ReadToken = default_completion_token_t<executor_type>> 0561 auto async_read_some(const MutableBufferSequence& buffers, 0562 ReadToken&& token = default_completion_token_t<executor_type>()) 0563 -> decltype( 0564 async_initiate<ReadToken, 0565 void (boost::system::error_code, std::size_t)>( 0566 declval<initiate_async_read_some>(), token, buffers)) 0567 { 0568 return async_initiate<ReadToken, 0569 void (boost::system::error_code, std::size_t)>( 0570 initiate_async_read_some(this), token, buffers); 0571 } 0572 0573 private: 0574 // Disallow copying and assignment. 0575 basic_readable_pipe(const basic_readable_pipe&) = delete; 0576 basic_readable_pipe& operator=(const basic_readable_pipe&) = delete; 0577 0578 class initiate_async_read_some 0579 { 0580 public: 0581 typedef Executor executor_type; 0582 0583 explicit initiate_async_read_some(basic_readable_pipe* self) 0584 : self_(self) 0585 { 0586 } 0587 0588 const executor_type& get_executor() const noexcept 0589 { 0590 return self_->get_executor(); 0591 } 0592 0593 template <typename ReadHandler, typename MutableBufferSequence> 0594 void operator()(ReadHandler&& handler, 0595 const MutableBufferSequence& buffers) const 0596 { 0597 // If you get an error on the following line it means that your handler 0598 // does not meet the documented type requirements for a ReadHandler. 0599 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; 0600 0601 detail::non_const_lvalue<ReadHandler> handler2(handler); 0602 self_->impl_.get_service().async_read_some( 0603 self_->impl_.get_implementation(), buffers, 0604 handler2.value, self_->impl_.get_executor()); 0605 } 0606 0607 private: 0608 basic_readable_pipe* self_; 0609 }; 0610 0611 #if defined(BOOST_ASIO_HAS_IOCP) 0612 detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_; 0613 #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) 0614 detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_; 0615 #else 0616 detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_; 0617 #endif 0618 }; 0619 0620 } // namespace asio 0621 } // namespace boost 0622 0623 #include <boost/asio/detail/pop_options.hpp> 0624 0625 #endif // defined(BOOST_ASIO_HAS_PIPE) 0626 // || defined(GENERATING_DOCUMENTATION) 0627 0628 #endif // BOOST_ASIO_BASIC_READABLE_PIPE_HPP
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |