Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:33:35

0001 //
0002 // posix/basic_descriptor.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_POSIX_BASIC_DESCRIPTOR_HPP
0012 #define BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_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_POSIX_STREAM_DESCRIPTOR) \
0021   || defined(GENERATING_DOCUMENTATION)
0022 
0023 #include <utility>
0024 #include <boost/asio/any_io_executor.hpp>
0025 #include <boost/asio/async_result.hpp>
0026 #include <boost/asio/detail/handler_type_requirements.hpp>
0027 #include <boost/asio/detail/io_object_impl.hpp>
0028 #include <boost/asio/detail/non_const_lvalue.hpp>
0029 #include <boost/asio/detail/throw_error.hpp>
0030 #include <boost/asio/error.hpp>
0031 #include <boost/asio/execution_context.hpp>
0032 #include <boost/asio/posix/descriptor_base.hpp>
0033 
0034 #if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0035 # include <boost/asio/detail/io_uring_descriptor_service.hpp>
0036 #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0037 # include <boost/asio/detail/reactive_descriptor_service.hpp>
0038 #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0039 
0040 #include <boost/asio/detail/push_options.hpp>
0041 
0042 namespace boost {
0043 namespace asio {
0044 namespace posix {
0045 
0046 /// Provides POSIX descriptor functionality.
0047 /**
0048  * The posix::basic_descriptor class template provides the ability to wrap a
0049  * POSIX descriptor.
0050  *
0051  * @par Thread Safety
0052  * @e Distinct @e objects: Safe.@n
0053  * @e Shared @e objects: Unsafe.
0054  */
0055 template <typename Executor = any_io_executor>
0056 class basic_descriptor
0057   : public descriptor_base
0058 {
0059 private:
0060   class initiate_async_wait;
0061 
0062 public:
0063   /// The type of the executor associated with the object.
0064   typedef Executor executor_type;
0065 
0066   /// Rebinds the descriptor type to another executor.
0067   template <typename Executor1>
0068   struct rebind_executor
0069   {
0070     /// The descriptor type when rebound to the specified executor.
0071     typedef basic_descriptor<Executor1> other;
0072   };
0073 
0074   /// The native representation of a descriptor.
0075 #if defined(GENERATING_DOCUMENTATION)
0076   typedef implementation_defined native_handle_type;
0077 #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0078   typedef detail::io_uring_descriptor_service::native_handle_type
0079     native_handle_type;
0080 #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0081   typedef detail::reactive_descriptor_service::native_handle_type
0082     native_handle_type;
0083 #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0084 
0085   /// A descriptor is always the lowest layer.
0086   typedef basic_descriptor lowest_layer_type;
0087 
0088   /// Construct a descriptor without opening it.
0089   /**
0090    * This constructor creates a descriptor without opening it.
0091    *
0092    * @param ex The I/O executor that the descriptor will use, by default, to
0093    * dispatch handlers for any asynchronous operations performed on the
0094    * descriptor.
0095    */
0096   explicit basic_descriptor(const executor_type& ex)
0097     : impl_(0, ex)
0098   {
0099   }
0100 
0101   /// Construct a descriptor without opening it.
0102   /**
0103    * This constructor creates a descriptor without opening it.
0104    *
0105    * @param context An execution context which provides the I/O executor that
0106    * the descriptor will use, by default, to dispatch handlers for any
0107    * asynchronous operations performed on the descriptor.
0108    */
0109   template <typename ExecutionContext>
0110   explicit basic_descriptor(ExecutionContext& context,
0111       constraint_t<
0112         is_convertible<ExecutionContext&, execution_context&>::value,
0113         defaulted_constraint
0114       > = defaulted_constraint())
0115     : impl_(0, 0, context)
0116   {
0117   }
0118 
0119   /// Construct a descriptor on an existing native descriptor.
0120   /**
0121    * This constructor creates a descriptor object to hold an existing native
0122    * descriptor.
0123    *
0124    * @param ex The I/O executor that the descriptor will use, by default, to
0125    * dispatch handlers for any asynchronous operations performed on the
0126    * descriptor.
0127    *
0128    * @param native_descriptor A native descriptor.
0129    *
0130    * @throws boost::system::system_error Thrown on failure.
0131    */
0132   basic_descriptor(const executor_type& ex,
0133       const native_handle_type& native_descriptor)
0134     : impl_(0, ex)
0135   {
0136     boost::system::error_code ec;
0137     impl_.get_service().assign(impl_.get_implementation(),
0138         native_descriptor, ec);
0139     boost::asio::detail::throw_error(ec, "assign");
0140   }
0141 
0142   /// Construct a descriptor on an existing native descriptor.
0143   /**
0144    * This constructor creates a descriptor object to hold an existing native
0145    * descriptor.
0146    *
0147    * @param context An execution context which provides the I/O executor that
0148    * the descriptor will use, by default, to dispatch handlers for any
0149    * asynchronous operations performed on the descriptor.
0150    *
0151    * @param native_descriptor A native descriptor.
0152    *
0153    * @throws boost::system::system_error Thrown on failure.
0154    */
0155   template <typename ExecutionContext>
0156   basic_descriptor(ExecutionContext& context,
0157       const native_handle_type& native_descriptor,
0158       constraint_t<
0159         is_convertible<ExecutionContext&, execution_context&>::value
0160       > = 0)
0161     : impl_(0, 0, context)
0162   {
0163     boost::system::error_code ec;
0164     impl_.get_service().assign(impl_.get_implementation(),
0165         native_descriptor, ec);
0166     boost::asio::detail::throw_error(ec, "assign");
0167   }
0168 
0169   /// Move-construct a descriptor from another.
0170   /**
0171    * This constructor moves a descriptor from one object to another.
0172    *
0173    * @param other The other descriptor object from which the move will
0174    * occur.
0175    *
0176    * @note Following the move, the moved-from object is in the same state as if
0177    * constructed using the @c basic_descriptor(const executor_type&)
0178    * constructor.
0179    */
0180   basic_descriptor(basic_descriptor&& other) noexcept
0181     : impl_(std::move(other.impl_))
0182   {
0183   }
0184 
0185   /// Move-assign a descriptor from another.
0186   /**
0187    * This assignment operator moves a descriptor from one object to another.
0188    *
0189    * @param other The other descriptor object from which the move will
0190    * occur.
0191    *
0192    * @note Following the move, the moved-from object is in the same state as if
0193    * constructed using the @c basic_descriptor(const executor_type&)
0194    * constructor.
0195    */
0196   basic_descriptor& operator=(basic_descriptor&& other)
0197   {
0198     impl_ = std::move(other.impl_);
0199     return *this;
0200   }
0201 
0202   // All descriptors have access to each other's implementations.
0203   template <typename Executor1>
0204   friend class basic_descriptor;
0205 
0206   /// Move-construct a basic_descriptor from a descriptor of another executor
0207   /// type.
0208   /**
0209    * This constructor moves a descriptor from one object to another.
0210    *
0211    * @param other The other basic_descriptor object from which the move will
0212    * occur.
0213    *
0214    * @note Following the move, the moved-from object is in the same state as if
0215    * constructed using the @c basic_descriptor(const executor_type&)
0216    * constructor.
0217    */
0218   template <typename Executor1>
0219   basic_descriptor(basic_descriptor<Executor1>&& other,
0220       constraint_t<
0221         is_convertible<Executor1, Executor>::value,
0222         defaulted_constraint
0223       > = defaulted_constraint())
0224     : impl_(std::move(other.impl_))
0225   {
0226   }
0227 
0228   /// Move-assign a basic_descriptor from a descriptor of another executor type.
0229   /**
0230    * This assignment operator moves a descriptor from one object to another.
0231    *
0232    * @param other The other basic_descriptor object from which the move will
0233    * occur.
0234    *
0235    * @note Following the move, the moved-from object is in the same state as if
0236    * constructed using the @c basic_descriptor(const executor_type&)
0237    * constructor.
0238    */
0239   template <typename Executor1>
0240   constraint_t<
0241     is_convertible<Executor1, Executor>::value,
0242     basic_descriptor&
0243   > operator=(basic_descriptor<Executor1> && other)
0244   {
0245     basic_descriptor tmp(std::move(other));
0246     impl_ = std::move(tmp.impl_);
0247     return *this;
0248   }
0249 
0250   /// Get the executor associated with the object.
0251   const executor_type& get_executor() noexcept
0252   {
0253     return impl_.get_executor();
0254   }
0255 
0256   /// Get a reference to the lowest layer.
0257   /**
0258    * This function returns a reference to the lowest layer in a stack of
0259    * layers. Since a descriptor cannot contain any further layers, it
0260    * simply returns a reference to itself.
0261    *
0262    * @return A reference to the lowest layer in the stack of layers. Ownership
0263    * is not transferred to the caller.
0264    */
0265   lowest_layer_type& lowest_layer()
0266   {
0267     return *this;
0268   }
0269 
0270   /// Get a const reference to the lowest layer.
0271   /**
0272    * This function returns a const reference to the lowest layer in a stack of
0273    * layers. Since a descriptor cannot contain any further layers, it
0274    * simply returns a reference to itself.
0275    *
0276    * @return A const reference to the lowest layer in the stack of layers.
0277    * Ownership is not transferred to the caller.
0278    */
0279   const lowest_layer_type& lowest_layer() const
0280   {
0281     return *this;
0282   }
0283 
0284   /// Assign an existing native descriptor to the descriptor.
0285   /*
0286    * This function opens the descriptor to hold an existing native descriptor.
0287    *
0288    * @param native_descriptor A native descriptor.
0289    *
0290    * @throws boost::system::system_error Thrown on failure.
0291    */
0292   void assign(const native_handle_type& native_descriptor)
0293   {
0294     boost::system::error_code ec;
0295     impl_.get_service().assign(impl_.get_implementation(),
0296         native_descriptor, ec);
0297     boost::asio::detail::throw_error(ec, "assign");
0298   }
0299 
0300   /// Assign an existing native descriptor to the descriptor.
0301   /*
0302    * This function opens the descriptor to hold an existing native descriptor.
0303    *
0304    * @param native_descriptor A native descriptor.
0305    *
0306    * @param ec Set to indicate what error occurred, if any.
0307    */
0308   BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor,
0309       boost::system::error_code& ec)
0310   {
0311     impl_.get_service().assign(
0312         impl_.get_implementation(), native_descriptor, ec);
0313     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0314   }
0315 
0316   /// Determine whether the descriptor is open.
0317   bool is_open() const
0318   {
0319     return impl_.get_service().is_open(impl_.get_implementation());
0320   }
0321 
0322   /// Close the descriptor.
0323   /**
0324    * This function is used to close the descriptor. Any asynchronous read or
0325    * write operations will be cancelled immediately, and will complete with the
0326    * boost::asio::error::operation_aborted error.
0327    *
0328    * @throws boost::system::system_error Thrown on failure. Note that, even if
0329    * the function indicates an error, the underlying descriptor is closed.
0330    */
0331   void close()
0332   {
0333     boost::system::error_code ec;
0334     impl_.get_service().close(impl_.get_implementation(), ec);
0335     boost::asio::detail::throw_error(ec, "close");
0336   }
0337 
0338   /// Close the descriptor.
0339   /**
0340    * This function is used to close the descriptor. Any asynchronous read or
0341    * write operations will be cancelled immediately, and will complete with the
0342    * boost::asio::error::operation_aborted error.
0343    *
0344    * @param ec Set to indicate what error occurred, if any. Note that, even if
0345    * the function indicates an error, the underlying descriptor is closed.
0346    */
0347   BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
0348   {
0349     impl_.get_service().close(impl_.get_implementation(), ec);
0350     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0351   }
0352 
0353   /// Get the native descriptor representation.
0354   /**
0355    * This function may be used to obtain the underlying representation of the
0356    * descriptor. This is intended to allow access to native descriptor
0357    * functionality that is not otherwise provided.
0358    */
0359   native_handle_type native_handle()
0360   {
0361     return impl_.get_service().native_handle(impl_.get_implementation());
0362   }
0363 
0364   /// Release ownership of the native descriptor implementation.
0365   /**
0366    * This function may be used to obtain the underlying representation of the
0367    * descriptor. After calling this function, @c is_open() returns false. The
0368    * caller is responsible for closing the descriptor.
0369    *
0370    * All outstanding asynchronous read or write operations will finish
0371    * immediately, and the handlers for cancelled operations will be passed the
0372    * boost::asio::error::operation_aborted error.
0373    */
0374   native_handle_type release()
0375   {
0376     return impl_.get_service().release(impl_.get_implementation());
0377   }
0378 
0379   /// Cancel all asynchronous operations associated with the descriptor.
0380   /**
0381    * This function causes all outstanding asynchronous read or write operations
0382    * to finish immediately, and the handlers for cancelled operations will be
0383    * passed the boost::asio::error::operation_aborted error.
0384    *
0385    * @throws boost::system::system_error Thrown on failure.
0386    */
0387   void cancel()
0388   {
0389     boost::system::error_code ec;
0390     impl_.get_service().cancel(impl_.get_implementation(), ec);
0391     boost::asio::detail::throw_error(ec, "cancel");
0392   }
0393 
0394   /// Cancel all asynchronous operations associated with the descriptor.
0395   /**
0396    * This function causes all outstanding asynchronous read or write operations
0397    * to finish immediately, and the handlers for cancelled operations will be
0398    * passed the boost::asio::error::operation_aborted error.
0399    *
0400    * @param ec Set to indicate what error occurred, if any.
0401    */
0402   BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
0403   {
0404     impl_.get_service().cancel(impl_.get_implementation(), ec);
0405     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0406   }
0407 
0408   /// Perform an IO control command on the descriptor.
0409   /**
0410    * This function is used to execute an IO control command on the descriptor.
0411    *
0412    * @param command The IO control command to be performed on the descriptor.
0413    *
0414    * @throws boost::system::system_error Thrown on failure.
0415    *
0416    * @sa IoControlCommand @n
0417    * boost::asio::posix::descriptor_base::bytes_readable @n
0418    * boost::asio::posix::descriptor_base::non_blocking_io
0419    *
0420    * @par Example
0421    * Getting the number of bytes ready to read:
0422    * @code
0423    * boost::asio::posix::stream_descriptor descriptor(my_context);
0424    * ...
0425    * boost::asio::posix::stream_descriptor::bytes_readable command;
0426    * descriptor.io_control(command);
0427    * std::size_t bytes_readable = command.get();
0428    * @endcode
0429    */
0430   template <typename IoControlCommand>
0431   void io_control(IoControlCommand& command)
0432   {
0433     boost::system::error_code ec;
0434     impl_.get_service().io_control(impl_.get_implementation(), command, ec);
0435     boost::asio::detail::throw_error(ec, "io_control");
0436   }
0437 
0438   /// Perform an IO control command on the descriptor.
0439   /**
0440    * This function is used to execute an IO control command on the descriptor.
0441    *
0442    * @param command The IO control command to be performed on the descriptor.
0443    *
0444    * @param ec Set to indicate what error occurred, if any.
0445    *
0446    * @sa IoControlCommand @n
0447    * boost::asio::posix::descriptor_base::bytes_readable @n
0448    * boost::asio::posix::descriptor_base::non_blocking_io
0449    *
0450    * @par Example
0451    * Getting the number of bytes ready to read:
0452    * @code
0453    * boost::asio::posix::stream_descriptor descriptor(my_context);
0454    * ...
0455    * boost::asio::posix::stream_descriptor::bytes_readable command;
0456    * boost::system::error_code ec;
0457    * descriptor.io_control(command, ec);
0458    * if (ec)
0459    * {
0460    *   // An error occurred.
0461    * }
0462    * std::size_t bytes_readable = command.get();
0463    * @endcode
0464    */
0465   template <typename IoControlCommand>
0466   BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
0467       boost::system::error_code& ec)
0468   {
0469     impl_.get_service().io_control(impl_.get_implementation(), command, ec);
0470     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0471   }
0472 
0473   /// Gets the non-blocking mode of the descriptor.
0474   /**
0475    * @returns @c true if the descriptor's synchronous operations will fail with
0476    * boost::asio::error::would_block if they are unable to perform the requested
0477    * operation immediately. If @c false, synchronous operations will block
0478    * until complete.
0479    *
0480    * @note The non-blocking mode has no effect on the behaviour of asynchronous
0481    * operations. Asynchronous operations will never fail with the error
0482    * boost::asio::error::would_block.
0483    */
0484   bool non_blocking() const
0485   {
0486     return impl_.get_service().non_blocking(impl_.get_implementation());
0487   }
0488 
0489   /// Sets the non-blocking mode of the descriptor.
0490   /**
0491    * @param mode If @c true, the descriptor's synchronous operations will fail
0492    * with boost::asio::error::would_block if they are unable to perform the
0493    * requested operation immediately. If @c false, synchronous operations will
0494    * block until complete.
0495    *
0496    * @throws boost::system::system_error Thrown on failure.
0497    *
0498    * @note The non-blocking mode has no effect on the behaviour of asynchronous
0499    * operations. Asynchronous operations will never fail with the error
0500    * boost::asio::error::would_block.
0501    */
0502   void non_blocking(bool mode)
0503   {
0504     boost::system::error_code ec;
0505     impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
0506     boost::asio::detail::throw_error(ec, "non_blocking");
0507   }
0508 
0509   /// Sets the non-blocking mode of the descriptor.
0510   /**
0511    * @param mode If @c true, the descriptor's synchronous operations will fail
0512    * with boost::asio::error::would_block if they are unable to perform the
0513    * requested operation immediately. If @c false, synchronous operations will
0514    * block until complete.
0515    *
0516    * @param ec Set to indicate what error occurred, if any.
0517    *
0518    * @note The non-blocking mode has no effect on the behaviour of asynchronous
0519    * operations. Asynchronous operations will never fail with the error
0520    * boost::asio::error::would_block.
0521    */
0522   BOOST_ASIO_SYNC_OP_VOID non_blocking(
0523       bool mode, boost::system::error_code& ec)
0524   {
0525     impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
0526     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0527   }
0528 
0529   /// Gets the non-blocking mode of the native descriptor implementation.
0530   /**
0531    * This function is used to retrieve the non-blocking mode of the underlying
0532    * native descriptor. This mode has no effect on the behaviour of the
0533    * descriptor object's synchronous operations.
0534    *
0535    * @returns @c true if the underlying descriptor is in non-blocking mode and
0536    * direct system calls may fail with boost::asio::error::would_block (or the
0537    * equivalent system error).
0538    *
0539    * @note The current non-blocking mode is cached by the descriptor object.
0540    * Consequently, the return value may be incorrect if the non-blocking mode
0541    * was set directly on the native descriptor.
0542    */
0543   bool native_non_blocking() const
0544   {
0545     return impl_.get_service().native_non_blocking(
0546         impl_.get_implementation());
0547   }
0548 
0549   /// Sets the non-blocking mode of the native descriptor implementation.
0550   /**
0551    * This function is used to modify the non-blocking mode of the underlying
0552    * native descriptor. It has no effect on the behaviour of the descriptor
0553    * object's synchronous operations.
0554    *
0555    * @param mode If @c true, the underlying descriptor is put into non-blocking
0556    * mode and direct system calls may fail with boost::asio::error::would_block
0557    * (or the equivalent system error).
0558    *
0559    * @throws boost::system::system_error Thrown on failure. If the @c mode is
0560    * @c false, but the current value of @c non_blocking() is @c true, this
0561    * function fails with boost::asio::error::invalid_argument, as the
0562    * combination does not make sense.
0563    */
0564   void native_non_blocking(bool mode)
0565   {
0566     boost::system::error_code ec;
0567     impl_.get_service().native_non_blocking(
0568         impl_.get_implementation(), mode, ec);
0569     boost::asio::detail::throw_error(ec, "native_non_blocking");
0570   }
0571 
0572   /// Sets the non-blocking mode of the native descriptor implementation.
0573   /**
0574    * This function is used to modify the non-blocking mode of the underlying
0575    * native descriptor. It has no effect on the behaviour of the descriptor
0576    * object's synchronous operations.
0577    *
0578    * @param mode If @c true, the underlying descriptor is put into non-blocking
0579    * mode and direct system calls may fail with boost::asio::error::would_block
0580    * (or the equivalent system error).
0581    *
0582    * @param ec Set to indicate what error occurred, if any. If the @c mode is
0583    * @c false, but the current value of @c non_blocking() is @c true, this
0584    * function fails with boost::asio::error::invalid_argument, as the
0585    * combination does not make sense.
0586    */
0587   BOOST_ASIO_SYNC_OP_VOID native_non_blocking(
0588       bool mode, boost::system::error_code& ec)
0589   {
0590     impl_.get_service().native_non_blocking(
0591         impl_.get_implementation(), mode, ec);
0592     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0593   }
0594 
0595   /// Wait for the descriptor to become ready to read, ready to write, or to
0596   /// have pending error conditions.
0597   /**
0598    * This function is used to perform a blocking wait for a descriptor to enter
0599    * a ready to read, write or error condition state.
0600    *
0601    * @param w Specifies the desired descriptor state.
0602    *
0603    * @par Example
0604    * Waiting for a descriptor to become readable.
0605    * @code
0606    * boost::asio::posix::stream_descriptor descriptor(my_context);
0607    * ...
0608    * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read);
0609    * @endcode
0610    */
0611   void wait(wait_type w)
0612   {
0613     boost::system::error_code ec;
0614     impl_.get_service().wait(impl_.get_implementation(), w, ec);
0615     boost::asio::detail::throw_error(ec, "wait");
0616   }
0617 
0618   /// Wait for the descriptor to become ready to read, ready to write, or to
0619   /// have pending error conditions.
0620   /**
0621    * This function is used to perform a blocking wait for a descriptor to enter
0622    * a ready to read, write or error condition state.
0623    *
0624    * @param w Specifies the desired descriptor state.
0625    *
0626    * @param ec Set to indicate what error occurred, if any.
0627    *
0628    * @par Example
0629    * Waiting for a descriptor to become readable.
0630    * @code
0631    * boost::asio::posix::stream_descriptor descriptor(my_context);
0632    * ...
0633    * boost::system::error_code ec;
0634    * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read, ec);
0635    * @endcode
0636    */
0637   BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec)
0638   {
0639     impl_.get_service().wait(impl_.get_implementation(), w, ec);
0640     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0641   }
0642 
0643   /// Asynchronously wait for the descriptor to become ready to read, ready to
0644   /// write, or to have pending error conditions.
0645   /**
0646    * This function is used to perform an asynchronous wait for a descriptor to
0647    * enter a ready to read, write or error condition state. It is an initiating
0648    * function for an @ref asynchronous_operation, and always returns
0649    * immediately.
0650    *
0651    * @param w Specifies the desired descriptor state.
0652    *
0653    * @param token The @ref completion_token that will be used to produce a
0654    * completion handler, which will be called when the wait completes.
0655    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0656    * @ref yield_context, or a function object with the correct completion
0657    * signature. The function signature of the completion handler must be:
0658    * @code void handler(
0659    *   const boost::system::error_code& error // Result of operation.
0660    * ); @endcode
0661    * Regardless of whether the asynchronous operation completes immediately or
0662    * not, the completion handler will not be invoked from within this function.
0663    * On immediate completion, invocation of the handler will be performed in a
0664    * manner equivalent to using boost::asio::post().
0665    *
0666    * @par Completion Signature
0667    * @code void(boost::system::error_code) @endcode
0668    *
0669    * @par Example
0670    * @code
0671    * void wait_handler(const boost::system::error_code& error)
0672    * {
0673    *   if (!error)
0674    *   {
0675    *     // Wait succeeded.
0676    *   }
0677    * }
0678    *
0679    * ...
0680    *
0681    * boost::asio::posix::stream_descriptor descriptor(my_context);
0682    * ...
0683    * descriptor.async_wait(
0684    *     boost::asio::posix::stream_descriptor::wait_read,
0685    *     wait_handler);
0686    * @endcode
0687    *
0688    * @par Per-Operation Cancellation
0689    * This asynchronous operation supports cancellation for the following
0690    * boost::asio::cancellation_type values:
0691    *
0692    * @li @c cancellation_type::terminal
0693    *
0694    * @li @c cancellation_type::partial
0695    *
0696    * @li @c cancellation_type::total
0697    */
0698   template <
0699       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
0700         WaitToken = default_completion_token_t<executor_type>>
0701   auto async_wait(wait_type w,
0702       WaitToken&& token = default_completion_token_t<executor_type>())
0703     -> decltype(
0704       async_initiate<WaitToken, void (boost::system::error_code)>(
0705         declval<initiate_async_wait>(), token, w))
0706   {
0707     return async_initiate<WaitToken, void (boost::system::error_code)>(
0708         initiate_async_wait(this), token, w);
0709   }
0710 
0711 protected:
0712   /// Protected destructor to prevent deletion through this type.
0713   /**
0714    * This function destroys the descriptor, cancelling any outstanding
0715    * asynchronous wait operations associated with the descriptor as if by
0716    * calling @c cancel.
0717    */
0718   ~basic_descriptor()
0719   {
0720   }
0721 
0722 #if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0723   detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
0724 #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0725   detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
0726 #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0727 
0728 private:
0729   // Disallow copying and assignment.
0730   basic_descriptor(const basic_descriptor&) = delete;
0731   basic_descriptor& operator=(const basic_descriptor&) = delete;
0732 
0733   class initiate_async_wait
0734   {
0735   public:
0736     typedef Executor executor_type;
0737 
0738     explicit initiate_async_wait(basic_descriptor* self)
0739       : self_(self)
0740     {
0741     }
0742 
0743     const executor_type& get_executor() const noexcept
0744     {
0745       return self_->get_executor();
0746     }
0747 
0748     template <typename WaitHandler>
0749     void operator()(WaitHandler&& handler, wait_type w) const
0750     {
0751       // If you get an error on the following line it means that your handler
0752       // does not meet the documented type requirements for a WaitHandler.
0753       BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
0754 
0755       detail::non_const_lvalue<WaitHandler> handler2(handler);
0756       self_->impl_.get_service().async_wait(
0757           self_->impl_.get_implementation(), w,
0758           handler2.value, self_->impl_.get_executor());
0759     }
0760 
0761   private:
0762     basic_descriptor* self_;
0763   };
0764 };
0765 
0766 } // namespace posix
0767 } // namespace asio
0768 } // namespace boost
0769 
0770 #include <boost/asio/detail/pop_options.hpp>
0771 
0772 #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
0773        //   || defined(GENERATING_DOCUMENTATION)
0774 
0775 #endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP