basic_descriptor.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. //
  2. // posix/basic_descriptor.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. #ifndef BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP
  11. #define BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
  17. || defined(GENERATING_DOCUMENTATION)
  18. #include <utility>
  19. #include <boost/asio/any_io_executor.hpp>
  20. #include <boost/asio/async_result.hpp>
  21. #include <boost/asio/detail/handler_type_requirements.hpp>
  22. #include <boost/asio/detail/io_object_impl.hpp>
  23. #include <boost/asio/detail/non_const_lvalue.hpp>
  24. #include <boost/asio/detail/throw_error.hpp>
  25. #include <boost/asio/error.hpp>
  26. #include <boost/asio/execution_context.hpp>
  27. #include <boost/asio/posix/descriptor_base.hpp>
  28. #if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  29. # include <boost/asio/detail/io_uring_descriptor_service.hpp>
  30. #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  31. # include <boost/asio/detail/reactive_descriptor_service.hpp>
  32. #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  33. #include <boost/asio/detail/push_options.hpp>
  34. namespace boost {
  35. namespace asio {
  36. namespace posix {
  37. /// Provides POSIX descriptor functionality.
  38. /**
  39. * The posix::basic_descriptor class template provides the ability to wrap a
  40. * POSIX descriptor.
  41. *
  42. * @par Thread Safety
  43. * @e Distinct @e objects: Safe.@n
  44. * @e Shared @e objects: Unsafe.
  45. */
  46. template <typename Executor = any_io_executor>
  47. class basic_descriptor
  48. : public descriptor_base
  49. {
  50. private:
  51. class initiate_async_wait;
  52. public:
  53. /// The type of the executor associated with the object.
  54. typedef Executor executor_type;
  55. /// Rebinds the descriptor type to another executor.
  56. template <typename Executor1>
  57. struct rebind_executor
  58. {
  59. /// The descriptor type when rebound to the specified executor.
  60. typedef basic_descriptor<Executor1> other;
  61. };
  62. /// The native representation of a descriptor.
  63. #if defined(GENERATING_DOCUMENTATION)
  64. typedef implementation_defined native_handle_type;
  65. #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  66. typedef detail::io_uring_descriptor_service::native_handle_type
  67. native_handle_type;
  68. #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  69. typedef detail::reactive_descriptor_service::native_handle_type
  70. native_handle_type;
  71. #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  72. /// A descriptor is always the lowest layer.
  73. typedef basic_descriptor lowest_layer_type;
  74. /// Construct a descriptor without opening it.
  75. /**
  76. * This constructor creates a descriptor without opening it.
  77. *
  78. * @param ex The I/O executor that the descriptor will use, by default, to
  79. * dispatch handlers for any asynchronous operations performed on the
  80. * descriptor.
  81. */
  82. explicit basic_descriptor(const executor_type& ex)
  83. : impl_(0, ex)
  84. {
  85. }
  86. /// Construct a descriptor without opening it.
  87. /**
  88. * This constructor creates a descriptor without opening it.
  89. *
  90. * @param context An execution context which provides the I/O executor that
  91. * the descriptor will use, by default, to dispatch handlers for any
  92. * asynchronous operations performed on the descriptor.
  93. */
  94. template <typename ExecutionContext>
  95. explicit basic_descriptor(ExecutionContext& context,
  96. constraint_t<
  97. is_convertible<ExecutionContext&, execution_context&>::value,
  98. defaulted_constraint
  99. > = defaulted_constraint())
  100. : impl_(0, 0, context)
  101. {
  102. }
  103. /// Construct a descriptor on an existing native descriptor.
  104. /**
  105. * This constructor creates a descriptor object to hold an existing native
  106. * descriptor.
  107. *
  108. * @param ex The I/O executor that the descriptor will use, by default, to
  109. * dispatch handlers for any asynchronous operations performed on the
  110. * descriptor.
  111. *
  112. * @param native_descriptor A native descriptor.
  113. *
  114. * @throws boost::system::system_error Thrown on failure.
  115. */
  116. basic_descriptor(const executor_type& ex,
  117. const native_handle_type& native_descriptor)
  118. : impl_(0, ex)
  119. {
  120. boost::system::error_code ec;
  121. impl_.get_service().assign(impl_.get_implementation(),
  122. native_descriptor, ec);
  123. boost::asio::detail::throw_error(ec, "assign");
  124. }
  125. /// Construct a descriptor on an existing native descriptor.
  126. /**
  127. * This constructor creates a descriptor object to hold an existing native
  128. * descriptor.
  129. *
  130. * @param context An execution context which provides the I/O executor that
  131. * the descriptor will use, by default, to dispatch handlers for any
  132. * asynchronous operations performed on the descriptor.
  133. *
  134. * @param native_descriptor A native descriptor.
  135. *
  136. * @throws boost::system::system_error Thrown on failure.
  137. */
  138. template <typename ExecutionContext>
  139. basic_descriptor(ExecutionContext& context,
  140. const native_handle_type& native_descriptor,
  141. constraint_t<
  142. is_convertible<ExecutionContext&, execution_context&>::value
  143. > = 0)
  144. : impl_(0, 0, context)
  145. {
  146. boost::system::error_code ec;
  147. impl_.get_service().assign(impl_.get_implementation(),
  148. native_descriptor, ec);
  149. boost::asio::detail::throw_error(ec, "assign");
  150. }
  151. /// Move-construct a descriptor from another.
  152. /**
  153. * This constructor moves a descriptor from one object to another.
  154. *
  155. * @param other The other descriptor object from which the move will
  156. * occur.
  157. *
  158. * @note Following the move, the moved-from object is in the same state as if
  159. * constructed using the @c basic_descriptor(const executor_type&)
  160. * constructor.
  161. */
  162. basic_descriptor(basic_descriptor&& other) noexcept
  163. : impl_(std::move(other.impl_))
  164. {
  165. }
  166. /// Move-assign a descriptor from another.
  167. /**
  168. * This assignment operator moves a descriptor from one object to another.
  169. *
  170. * @param other The other descriptor object from which the move will
  171. * occur.
  172. *
  173. * @note Following the move, the moved-from object is in the same state as if
  174. * constructed using the @c basic_descriptor(const executor_type&)
  175. * constructor.
  176. */
  177. basic_descriptor& operator=(basic_descriptor&& other)
  178. {
  179. impl_ = std::move(other.impl_);
  180. return *this;
  181. }
  182. // All descriptors have access to each other's implementations.
  183. template <typename Executor1>
  184. friend class basic_descriptor;
  185. /// Move-construct a basic_descriptor from a descriptor of another executor
  186. /// type.
  187. /**
  188. * This constructor moves a descriptor from one object to another.
  189. *
  190. * @param other The other basic_descriptor object from which the move will
  191. * occur.
  192. *
  193. * @note Following the move, the moved-from object is in the same state as if
  194. * constructed using the @c basic_descriptor(const executor_type&)
  195. * constructor.
  196. */
  197. template <typename Executor1>
  198. basic_descriptor(basic_descriptor<Executor1>&& other,
  199. constraint_t<
  200. is_convertible<Executor1, Executor>::value,
  201. defaulted_constraint
  202. > = defaulted_constraint())
  203. : impl_(std::move(other.impl_))
  204. {
  205. }
  206. /// Move-assign a basic_descriptor from a descriptor of another executor type.
  207. /**
  208. * This assignment operator moves a descriptor from one object to another.
  209. *
  210. * @param other The other basic_descriptor object from which the move will
  211. * occur.
  212. *
  213. * @note Following the move, the moved-from object is in the same state as if
  214. * constructed using the @c basic_descriptor(const executor_type&)
  215. * constructor.
  216. */
  217. template <typename Executor1>
  218. constraint_t<
  219. is_convertible<Executor1, Executor>::value,
  220. basic_descriptor&
  221. > operator=(basic_descriptor<Executor1> && other)
  222. {
  223. basic_descriptor tmp(std::move(other));
  224. impl_ = std::move(tmp.impl_);
  225. return *this;
  226. }
  227. /// Get the executor associated with the object.
  228. const executor_type& get_executor() noexcept
  229. {
  230. return impl_.get_executor();
  231. }
  232. /// Get a reference to the lowest layer.
  233. /**
  234. * This function returns a reference to the lowest layer in a stack of
  235. * layers. Since a descriptor cannot contain any further layers, it
  236. * simply returns a reference to itself.
  237. *
  238. * @return A reference to the lowest layer in the stack of layers. Ownership
  239. * is not transferred to the caller.
  240. */
  241. lowest_layer_type& lowest_layer()
  242. {
  243. return *this;
  244. }
  245. /// Get a const reference to the lowest layer.
  246. /**
  247. * This function returns a const reference to the lowest layer in a stack of
  248. * layers. Since a descriptor cannot contain any further layers, it
  249. * simply returns a reference to itself.
  250. *
  251. * @return A const reference to the lowest layer in the stack of layers.
  252. * Ownership is not transferred to the caller.
  253. */
  254. const lowest_layer_type& lowest_layer() const
  255. {
  256. return *this;
  257. }
  258. /// Assign an existing native descriptor to the descriptor.
  259. /*
  260. * This function opens the descriptor to hold an existing native descriptor.
  261. *
  262. * @param native_descriptor A native descriptor.
  263. *
  264. * @throws boost::system::system_error Thrown on failure.
  265. */
  266. void assign(const native_handle_type& native_descriptor)
  267. {
  268. boost::system::error_code ec;
  269. impl_.get_service().assign(impl_.get_implementation(),
  270. native_descriptor, ec);
  271. boost::asio::detail::throw_error(ec, "assign");
  272. }
  273. /// Assign an existing native descriptor to the descriptor.
  274. /*
  275. * This function opens the descriptor to hold an existing native descriptor.
  276. *
  277. * @param native_descriptor A native descriptor.
  278. *
  279. * @param ec Set to indicate what error occurred, if any.
  280. */
  281. BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor,
  282. boost::system::error_code& ec)
  283. {
  284. impl_.get_service().assign(
  285. impl_.get_implementation(), native_descriptor, ec);
  286. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  287. }
  288. /// Determine whether the descriptor is open.
  289. bool is_open() const
  290. {
  291. return impl_.get_service().is_open(impl_.get_implementation());
  292. }
  293. /// Close the descriptor.
  294. /**
  295. * This function is used to close the descriptor. Any asynchronous read or
  296. * write operations will be cancelled immediately, and will complete with the
  297. * boost::asio::error::operation_aborted error.
  298. *
  299. * @throws boost::system::system_error Thrown on failure. Note that, even if
  300. * the function indicates an error, the underlying descriptor is closed.
  301. */
  302. void close()
  303. {
  304. boost::system::error_code ec;
  305. impl_.get_service().close(impl_.get_implementation(), ec);
  306. boost::asio::detail::throw_error(ec, "close");
  307. }
  308. /// Close the descriptor.
  309. /**
  310. * This function is used to close the descriptor. Any asynchronous read or
  311. * write operations will be cancelled immediately, and will complete with the
  312. * boost::asio::error::operation_aborted error.
  313. *
  314. * @param ec Set to indicate what error occurred, if any. Note that, even if
  315. * the function indicates an error, the underlying descriptor is closed.
  316. */
  317. BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
  318. {
  319. impl_.get_service().close(impl_.get_implementation(), ec);
  320. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  321. }
  322. /// Get the native descriptor representation.
  323. /**
  324. * This function may be used to obtain the underlying representation of the
  325. * descriptor. This is intended to allow access to native descriptor
  326. * functionality that is not otherwise provided.
  327. */
  328. native_handle_type native_handle()
  329. {
  330. return impl_.get_service().native_handle(impl_.get_implementation());
  331. }
  332. /// Release ownership of the native descriptor implementation.
  333. /**
  334. * This function may be used to obtain the underlying representation of the
  335. * descriptor. After calling this function, @c is_open() returns false. The
  336. * caller is responsible for closing the descriptor.
  337. *
  338. * All outstanding asynchronous read or write operations will finish
  339. * immediately, and the handlers for cancelled operations will be passed the
  340. * boost::asio::error::operation_aborted error.
  341. */
  342. native_handle_type release()
  343. {
  344. return impl_.get_service().release(impl_.get_implementation());
  345. }
  346. /// Cancel all asynchronous operations associated with the descriptor.
  347. /**
  348. * This function causes all outstanding asynchronous read or write operations
  349. * to finish immediately, and the handlers for cancelled operations will be
  350. * passed the boost::asio::error::operation_aborted error.
  351. *
  352. * @throws boost::system::system_error Thrown on failure.
  353. */
  354. void cancel()
  355. {
  356. boost::system::error_code ec;
  357. impl_.get_service().cancel(impl_.get_implementation(), ec);
  358. boost::asio::detail::throw_error(ec, "cancel");
  359. }
  360. /// Cancel all asynchronous operations associated with the descriptor.
  361. /**
  362. * This function causes all outstanding asynchronous read or write operations
  363. * to finish immediately, and the handlers for cancelled operations will be
  364. * passed the boost::asio::error::operation_aborted error.
  365. *
  366. * @param ec Set to indicate what error occurred, if any.
  367. */
  368. BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
  369. {
  370. impl_.get_service().cancel(impl_.get_implementation(), ec);
  371. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  372. }
  373. /// Perform an IO control command on the descriptor.
  374. /**
  375. * This function is used to execute an IO control command on the descriptor.
  376. *
  377. * @param command The IO control command to be performed on the descriptor.
  378. *
  379. * @throws boost::system::system_error Thrown on failure.
  380. *
  381. * @sa IoControlCommand @n
  382. * boost::asio::posix::descriptor_base::bytes_readable @n
  383. * boost::asio::posix::descriptor_base::non_blocking_io
  384. *
  385. * @par Example
  386. * Getting the number of bytes ready to read:
  387. * @code
  388. * boost::asio::posix::stream_descriptor descriptor(my_context);
  389. * ...
  390. * boost::asio::posix::stream_descriptor::bytes_readable command;
  391. * descriptor.io_control(command);
  392. * std::size_t bytes_readable = command.get();
  393. * @endcode
  394. */
  395. template <typename IoControlCommand>
  396. void io_control(IoControlCommand& command)
  397. {
  398. boost::system::error_code ec;
  399. impl_.get_service().io_control(impl_.get_implementation(), command, ec);
  400. boost::asio::detail::throw_error(ec, "io_control");
  401. }
  402. /// Perform an IO control command on the descriptor.
  403. /**
  404. * This function is used to execute an IO control command on the descriptor.
  405. *
  406. * @param command The IO control command to be performed on the descriptor.
  407. *
  408. * @param ec Set to indicate what error occurred, if any.
  409. *
  410. * @sa IoControlCommand @n
  411. * boost::asio::posix::descriptor_base::bytes_readable @n
  412. * boost::asio::posix::descriptor_base::non_blocking_io
  413. *
  414. * @par Example
  415. * Getting the number of bytes ready to read:
  416. * @code
  417. * boost::asio::posix::stream_descriptor descriptor(my_context);
  418. * ...
  419. * boost::asio::posix::stream_descriptor::bytes_readable command;
  420. * boost::system::error_code ec;
  421. * descriptor.io_control(command, ec);
  422. * if (ec)
  423. * {
  424. * // An error occurred.
  425. * }
  426. * std::size_t bytes_readable = command.get();
  427. * @endcode
  428. */
  429. template <typename IoControlCommand>
  430. BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
  431. boost::system::error_code& ec)
  432. {
  433. impl_.get_service().io_control(impl_.get_implementation(), command, ec);
  434. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  435. }
  436. /// Gets the non-blocking mode of the descriptor.
  437. /**
  438. * @returns @c true if the descriptor's synchronous operations will fail with
  439. * boost::asio::error::would_block if they are unable to perform the requested
  440. * operation immediately. If @c false, synchronous operations will block
  441. * until complete.
  442. *
  443. * @note The non-blocking mode has no effect on the behaviour of asynchronous
  444. * operations. Asynchronous operations will never fail with the error
  445. * boost::asio::error::would_block.
  446. */
  447. bool non_blocking() const
  448. {
  449. return impl_.get_service().non_blocking(impl_.get_implementation());
  450. }
  451. /// Sets the non-blocking mode of the descriptor.
  452. /**
  453. * @param mode If @c true, the descriptor's synchronous operations will fail
  454. * with boost::asio::error::would_block if they are unable to perform the
  455. * requested operation immediately. If @c false, synchronous operations will
  456. * block until complete.
  457. *
  458. * @throws boost::system::system_error Thrown on failure.
  459. *
  460. * @note The non-blocking mode has no effect on the behaviour of asynchronous
  461. * operations. Asynchronous operations will never fail with the error
  462. * boost::asio::error::would_block.
  463. */
  464. void non_blocking(bool mode)
  465. {
  466. boost::system::error_code ec;
  467. impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
  468. boost::asio::detail::throw_error(ec, "non_blocking");
  469. }
  470. /// Sets the non-blocking mode of the descriptor.
  471. /**
  472. * @param mode If @c true, the descriptor's synchronous operations will fail
  473. * with boost::asio::error::would_block if they are unable to perform the
  474. * requested operation immediately. If @c false, synchronous operations will
  475. * block until complete.
  476. *
  477. * @param ec Set to indicate what error occurred, if any.
  478. *
  479. * @note The non-blocking mode has no effect on the behaviour of asynchronous
  480. * operations. Asynchronous operations will never fail with the error
  481. * boost::asio::error::would_block.
  482. */
  483. BOOST_ASIO_SYNC_OP_VOID non_blocking(
  484. bool mode, boost::system::error_code& ec)
  485. {
  486. impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
  487. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  488. }
  489. /// Gets the non-blocking mode of the native descriptor implementation.
  490. /**
  491. * This function is used to retrieve the non-blocking mode of the underlying
  492. * native descriptor. This mode has no effect on the behaviour of the
  493. * descriptor object's synchronous operations.
  494. *
  495. * @returns @c true if the underlying descriptor is in non-blocking mode and
  496. * direct system calls may fail with boost::asio::error::would_block (or the
  497. * equivalent system error).
  498. *
  499. * @note The current non-blocking mode is cached by the descriptor object.
  500. * Consequently, the return value may be incorrect if the non-blocking mode
  501. * was set directly on the native descriptor.
  502. */
  503. bool native_non_blocking() const
  504. {
  505. return impl_.get_service().native_non_blocking(
  506. impl_.get_implementation());
  507. }
  508. /// Sets the non-blocking mode of the native descriptor implementation.
  509. /**
  510. * This function is used to modify the non-blocking mode of the underlying
  511. * native descriptor. It has no effect on the behaviour of the descriptor
  512. * object's synchronous operations.
  513. *
  514. * @param mode If @c true, the underlying descriptor is put into non-blocking
  515. * mode and direct system calls may fail with boost::asio::error::would_block
  516. * (or the equivalent system error).
  517. *
  518. * @throws boost::system::system_error Thrown on failure. If the @c mode is
  519. * @c false, but the current value of @c non_blocking() is @c true, this
  520. * function fails with boost::asio::error::invalid_argument, as the
  521. * combination does not make sense.
  522. */
  523. void native_non_blocking(bool mode)
  524. {
  525. boost::system::error_code ec;
  526. impl_.get_service().native_non_blocking(
  527. impl_.get_implementation(), mode, ec);
  528. boost::asio::detail::throw_error(ec, "native_non_blocking");
  529. }
  530. /// Sets the non-blocking mode of the native descriptor implementation.
  531. /**
  532. * This function is used to modify the non-blocking mode of the underlying
  533. * native descriptor. It has no effect on the behaviour of the descriptor
  534. * object's synchronous operations.
  535. *
  536. * @param mode If @c true, the underlying descriptor is put into non-blocking
  537. * mode and direct system calls may fail with boost::asio::error::would_block
  538. * (or the equivalent system error).
  539. *
  540. * @param ec Set to indicate what error occurred, if any. If the @c mode is
  541. * @c false, but the current value of @c non_blocking() is @c true, this
  542. * function fails with boost::asio::error::invalid_argument, as the
  543. * combination does not make sense.
  544. */
  545. BOOST_ASIO_SYNC_OP_VOID native_non_blocking(
  546. bool mode, boost::system::error_code& ec)
  547. {
  548. impl_.get_service().native_non_blocking(
  549. impl_.get_implementation(), mode, ec);
  550. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  551. }
  552. /// Wait for the descriptor to become ready to read, ready to write, or to
  553. /// have pending error conditions.
  554. /**
  555. * This function is used to perform a blocking wait for a descriptor to enter
  556. * a ready to read, write or error condition state.
  557. *
  558. * @param w Specifies the desired descriptor state.
  559. *
  560. * @par Example
  561. * Waiting for a descriptor to become readable.
  562. * @code
  563. * boost::asio::posix::stream_descriptor descriptor(my_context);
  564. * ...
  565. * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read);
  566. * @endcode
  567. */
  568. void wait(wait_type w)
  569. {
  570. boost::system::error_code ec;
  571. impl_.get_service().wait(impl_.get_implementation(), w, ec);
  572. boost::asio::detail::throw_error(ec, "wait");
  573. }
  574. /// Wait for the descriptor to become ready to read, ready to write, or to
  575. /// have pending error conditions.
  576. /**
  577. * This function is used to perform a blocking wait for a descriptor to enter
  578. * a ready to read, write or error condition state.
  579. *
  580. * @param w Specifies the desired descriptor state.
  581. *
  582. * @param ec Set to indicate what error occurred, if any.
  583. *
  584. * @par Example
  585. * Waiting for a descriptor to become readable.
  586. * @code
  587. * boost::asio::posix::stream_descriptor descriptor(my_context);
  588. * ...
  589. * boost::system::error_code ec;
  590. * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read, ec);
  591. * @endcode
  592. */
  593. BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec)
  594. {
  595. impl_.get_service().wait(impl_.get_implementation(), w, ec);
  596. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  597. }
  598. /// Asynchronously wait for the descriptor to become ready to read, ready to
  599. /// write, or to have pending error conditions.
  600. /**
  601. * This function is used to perform an asynchronous wait for a descriptor to
  602. * enter a ready to read, write or error condition state. It is an initiating
  603. * function for an @ref asynchronous_operation, and always returns
  604. * immediately.
  605. *
  606. * @param w Specifies the desired descriptor state.
  607. *
  608. * @param token The @ref completion_token that will be used to produce a
  609. * completion handler, which will be called when the wait completes.
  610. * Potential completion tokens include @ref use_future, @ref use_awaitable,
  611. * @ref yield_context, or a function object with the correct completion
  612. * signature. The function signature of the completion handler must be:
  613. * @code void handler(
  614. * const boost::system::error_code& error // Result of operation.
  615. * ); @endcode
  616. * Regardless of whether the asynchronous operation completes immediately or
  617. * not, the completion handler will not be invoked from within this function.
  618. * On immediate completion, invocation of the handler will be performed in a
  619. * manner equivalent to using boost::asio::async_immediate().
  620. *
  621. * @par Completion Signature
  622. * @code void(boost::system::error_code) @endcode
  623. *
  624. * @par Example
  625. * @code
  626. * void wait_handler(const boost::system::error_code& error)
  627. * {
  628. * if (!error)
  629. * {
  630. * // Wait succeeded.
  631. * }
  632. * }
  633. *
  634. * ...
  635. *
  636. * boost::asio::posix::stream_descriptor descriptor(my_context);
  637. * ...
  638. * descriptor.async_wait(
  639. * boost::asio::posix::stream_descriptor::wait_read,
  640. * wait_handler);
  641. * @endcode
  642. *
  643. * @par Per-Operation Cancellation
  644. * This asynchronous operation supports cancellation for the following
  645. * boost::asio::cancellation_type values:
  646. *
  647. * @li @c cancellation_type::terminal
  648. *
  649. * @li @c cancellation_type::partial
  650. *
  651. * @li @c cancellation_type::total
  652. */
  653. template <
  654. BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
  655. WaitToken = default_completion_token_t<executor_type>>
  656. auto async_wait(wait_type w,
  657. WaitToken&& token = default_completion_token_t<executor_type>())
  658. -> decltype(
  659. async_initiate<WaitToken, void (boost::system::error_code)>(
  660. declval<initiate_async_wait>(), token, w))
  661. {
  662. return async_initiate<WaitToken, void (boost::system::error_code)>(
  663. initiate_async_wait(this), token, w);
  664. }
  665. protected:
  666. /// Protected destructor to prevent deletion through this type.
  667. /**
  668. * This function destroys the descriptor, cancelling any outstanding
  669. * asynchronous wait operations associated with the descriptor as if by
  670. * calling @c cancel.
  671. */
  672. ~basic_descriptor()
  673. {
  674. }
  675. #if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  676. detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
  677. #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  678. detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
  679. #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
  680. private:
  681. // Disallow copying and assignment.
  682. basic_descriptor(const basic_descriptor&) = delete;
  683. basic_descriptor& operator=(const basic_descriptor&) = delete;
  684. class initiate_async_wait
  685. {
  686. public:
  687. typedef Executor executor_type;
  688. explicit initiate_async_wait(basic_descriptor* self)
  689. : self_(self)
  690. {
  691. }
  692. const executor_type& get_executor() const noexcept
  693. {
  694. return self_->get_executor();
  695. }
  696. template <typename WaitHandler>
  697. void operator()(WaitHandler&& handler, wait_type w) const
  698. {
  699. // If you get an error on the following line it means that your handler
  700. // does not meet the documented type requirements for a WaitHandler.
  701. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
  702. detail::non_const_lvalue<WaitHandler> handler2(handler);
  703. self_->impl_.get_service().async_wait(
  704. self_->impl_.get_implementation(), w,
  705. handler2.value, self_->impl_.get_executor());
  706. }
  707. private:
  708. basic_descriptor* self_;
  709. };
  710. };
  711. } // namespace posix
  712. } // namespace asio
  713. } // namespace boost
  714. #include <boost/asio/detail/pop_options.hpp>
  715. #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
  716. // || defined(GENERATING_DOCUMENTATION)
  717. #endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP