basic_descriptor.hpp 25 KB

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