io_uring_descriptor_service.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. //
  2. // detail/io_uring_descriptor_service.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_DETAIL_IO_URING_DESCRIPTOR_SERVICE_HPP
  11. #define BOOST_ASIO_DETAIL_IO_URING_DESCRIPTOR_SERVICE_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_IO_URING)
  17. #include <boost/asio/associated_cancellation_slot.hpp>
  18. #include <boost/asio/buffer.hpp>
  19. #include <boost/asio/cancellation_type.hpp>
  20. #include <boost/asio/execution_context.hpp>
  21. #include <boost/asio/detail/buffer_sequence_adapter.hpp>
  22. #include <boost/asio/detail/descriptor_ops.hpp>
  23. #include <boost/asio/detail/io_uring_descriptor_read_at_op.hpp>
  24. #include <boost/asio/detail/io_uring_descriptor_read_op.hpp>
  25. #include <boost/asio/detail/io_uring_descriptor_write_at_op.hpp>
  26. #include <boost/asio/detail/io_uring_descriptor_write_op.hpp>
  27. #include <boost/asio/detail/io_uring_null_buffers_op.hpp>
  28. #include <boost/asio/detail/io_uring_service.hpp>
  29. #include <boost/asio/detail/io_uring_wait_op.hpp>
  30. #include <boost/asio/detail/memory.hpp>
  31. #include <boost/asio/detail/noncopyable.hpp>
  32. #include <boost/asio/posix/descriptor_base.hpp>
  33. #include <boost/asio/detail/push_options.hpp>
  34. namespace boost {
  35. namespace asio {
  36. namespace detail {
  37. class io_uring_descriptor_service :
  38. public execution_context_service_base<io_uring_descriptor_service>
  39. {
  40. public:
  41. // The native type of a descriptor.
  42. typedef int native_handle_type;
  43. // The implementation type of the descriptor.
  44. class implementation_type
  45. : private boost::asio::detail::noncopyable
  46. {
  47. public:
  48. // Default constructor.
  49. implementation_type()
  50. : descriptor_(-1),
  51. state_(0)
  52. {
  53. }
  54. private:
  55. // Only this service will have access to the internal values.
  56. friend class io_uring_descriptor_service;
  57. // The native descriptor representation.
  58. int descriptor_;
  59. // The current state of the descriptor.
  60. descriptor_ops::state_type state_;
  61. // Per I/O object data used by the io_uring_service.
  62. io_uring_service::per_io_object_data io_object_data_;
  63. };
  64. // Constructor.
  65. BOOST_ASIO_DECL io_uring_descriptor_service(execution_context& context);
  66. // Destroy all user-defined handler objects owned by the service.
  67. BOOST_ASIO_DECL void shutdown();
  68. // Construct a new descriptor implementation.
  69. BOOST_ASIO_DECL void construct(implementation_type& impl);
  70. // Move-construct a new descriptor implementation.
  71. BOOST_ASIO_DECL void move_construct(implementation_type& impl,
  72. implementation_type& other_impl) noexcept;
  73. // Move-assign from another descriptor implementation.
  74. BOOST_ASIO_DECL void move_assign(implementation_type& impl,
  75. io_uring_descriptor_service& other_service,
  76. implementation_type& other_impl);
  77. // Destroy a descriptor implementation.
  78. BOOST_ASIO_DECL void destroy(implementation_type& impl);
  79. // Assign a native descriptor to a descriptor implementation.
  80. BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl,
  81. const native_handle_type& native_descriptor,
  82. boost::system::error_code& ec);
  83. // Determine whether the descriptor is open.
  84. bool is_open(const implementation_type& impl) const
  85. {
  86. return impl.descriptor_ != -1;
  87. }
  88. // Destroy a descriptor implementation.
  89. BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl,
  90. boost::system::error_code& ec);
  91. // Get the native descriptor representation.
  92. native_handle_type native_handle(const implementation_type& impl) const
  93. {
  94. return impl.descriptor_;
  95. }
  96. // Release ownership of the native descriptor representation.
  97. BOOST_ASIO_DECL native_handle_type release(implementation_type& impl);
  98. // Release ownership of the native descriptor representation.
  99. native_handle_type release(implementation_type& impl,
  100. boost::system::error_code& ec)
  101. {
  102. ec = success_ec_;
  103. return release(impl);
  104. }
  105. // Cancel all operations associated with the descriptor.
  106. BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
  107. boost::system::error_code& ec);
  108. // Perform an IO control command on the descriptor.
  109. template <typename IO_Control_Command>
  110. boost::system::error_code io_control(implementation_type& impl,
  111. IO_Control_Command& command, boost::system::error_code& ec)
  112. {
  113. descriptor_ops::ioctl(impl.descriptor_, impl.state_,
  114. command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
  115. BOOST_ASIO_ERROR_LOCATION(ec);
  116. return ec;
  117. }
  118. // Gets the non-blocking mode of the descriptor.
  119. bool non_blocking(const implementation_type& impl) const
  120. {
  121. return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
  122. }
  123. // Sets the non-blocking mode of the descriptor.
  124. boost::system::error_code non_blocking(implementation_type& impl,
  125. bool mode, boost::system::error_code& ec)
  126. {
  127. descriptor_ops::set_user_non_blocking(
  128. impl.descriptor_, impl.state_, mode, ec);
  129. BOOST_ASIO_ERROR_LOCATION(ec);
  130. return ec;
  131. }
  132. // Gets the non-blocking mode of the native descriptor implementation.
  133. bool native_non_blocking(const implementation_type& impl) const
  134. {
  135. return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
  136. }
  137. // Sets the non-blocking mode of the native descriptor implementation.
  138. boost::system::error_code native_non_blocking(implementation_type& impl,
  139. bool mode, boost::system::error_code& ec)
  140. {
  141. descriptor_ops::set_internal_non_blocking(
  142. impl.descriptor_, impl.state_, mode, ec);
  143. BOOST_ASIO_ERROR_LOCATION(ec);
  144. return ec;
  145. }
  146. // Wait for the descriptor to become ready to read, ready to write, or to have
  147. // pending error conditions.
  148. boost::system::error_code wait(implementation_type& impl,
  149. posix::descriptor_base::wait_type w, boost::system::error_code& ec)
  150. {
  151. switch (w)
  152. {
  153. case posix::descriptor_base::wait_read:
  154. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
  155. break;
  156. case posix::descriptor_base::wait_write:
  157. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
  158. break;
  159. case posix::descriptor_base::wait_error:
  160. descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);
  161. break;
  162. default:
  163. ec = boost::asio::error::invalid_argument;
  164. break;
  165. }
  166. BOOST_ASIO_ERROR_LOCATION(ec);
  167. return ec;
  168. }
  169. // Asynchronously wait for the descriptor to become ready to read, ready to
  170. // write, or to have pending error conditions.
  171. template <typename Handler, typename IoExecutor>
  172. void async_wait(implementation_type& impl,
  173. posix::descriptor_base::wait_type w,
  174. Handler& handler, const IoExecutor& io_ex)
  175. {
  176. bool is_continuation =
  177. boost_asio_handler_cont_helpers::is_continuation(handler);
  178. associated_cancellation_slot_t<Handler> slot
  179. = boost::asio::get_associated_cancellation_slot(handler);
  180. int op_type;
  181. int poll_flags;
  182. switch (w)
  183. {
  184. case posix::descriptor_base::wait_read:
  185. op_type = io_uring_service::read_op;
  186. poll_flags = POLLIN;
  187. break;
  188. case posix::descriptor_base::wait_write:
  189. op_type = io_uring_service::write_op;
  190. poll_flags = POLLOUT;
  191. break;
  192. case posix::descriptor_base::wait_error:
  193. op_type = io_uring_service::except_op;
  194. poll_flags = POLLPRI | POLLERR | POLLHUP;
  195. break;
  196. default:
  197. op_type = -1;
  198. poll_flags = -1;
  199. return;
  200. }
  201. // Allocate and construct an operation to wrap the handler.
  202. typedef io_uring_wait_op<Handler, IoExecutor> op;
  203. typename op::ptr p = { boost::asio::detail::addressof(handler),
  204. op::ptr::allocate(handler), 0 };
  205. p.p = new (p.v) op(success_ec_, impl.descriptor_,
  206. poll_flags, handler, io_ex);
  207. // Optionally register for per-operation cancellation.
  208. if (slot.is_connected() && op_type != -1)
  209. {
  210. p.p->cancellation_key_ =
  211. &slot.template emplace<io_uring_op_cancellation>(
  212. &io_uring_service_, &impl.io_object_data_, op_type);
  213. }
  214. BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
  215. "descriptor", &impl, impl.descriptor_, "async_wait"));
  216. start_op(impl, op_type, p.p, is_continuation, op_type == -1);
  217. p.v = p.p = 0;
  218. }
  219. // Write some data to the descriptor.
  220. template <typename ConstBufferSequence>
  221. size_t write_some(implementation_type& impl,
  222. const ConstBufferSequence& buffers, boost::system::error_code& ec)
  223. {
  224. typedef buffer_sequence_adapter<boost::asio::const_buffer,
  225. ConstBufferSequence> bufs_type;
  226. size_t n;
  227. if (bufs_type::is_single_buffer)
  228. {
  229. n = descriptor_ops::sync_write1(impl.descriptor_,
  230. impl.state_, bufs_type::first(buffers).data(),
  231. bufs_type::first(buffers).size(), ec);
  232. }
  233. else
  234. {
  235. bufs_type bufs(buffers);
  236. n = descriptor_ops::sync_write(impl.descriptor_, impl.state_,
  237. bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  238. }
  239. BOOST_ASIO_ERROR_LOCATION(ec);
  240. return n;
  241. }
  242. // Wait until data can be written without blocking.
  243. size_t write_some(implementation_type& impl,
  244. const null_buffers&, boost::system::error_code& ec)
  245. {
  246. // Wait for descriptor to become ready.
  247. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
  248. BOOST_ASIO_ERROR_LOCATION(ec);
  249. return 0;
  250. }
  251. // Start an asynchronous write. The data being sent must be valid for the
  252. // lifetime of the asynchronous operation.
  253. template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
  254. void async_write_some(implementation_type& impl,
  255. const ConstBufferSequence& buffers, Handler& handler,
  256. const IoExecutor& io_ex)
  257. {
  258. bool is_continuation =
  259. boost_asio_handler_cont_helpers::is_continuation(handler);
  260. associated_cancellation_slot_t<Handler> slot
  261. = boost::asio::get_associated_cancellation_slot(handler);
  262. // Allocate and construct an operation to wrap the handler.
  263. typedef io_uring_descriptor_write_op<
  264. ConstBufferSequence, Handler, IoExecutor> op;
  265. typename op::ptr p = { boost::asio::detail::addressof(handler),
  266. op::ptr::allocate(handler), 0 };
  267. p.p = new (p.v) op(success_ec_, impl.descriptor_,
  268. impl.state_, buffers, handler, io_ex);
  269. // Optionally register for per-operation cancellation.
  270. if (slot.is_connected())
  271. {
  272. p.p->cancellation_key_ =
  273. &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
  274. &impl.io_object_data_, io_uring_service::write_op);
  275. }
  276. BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
  277. "descriptor", &impl, impl.descriptor_, "async_write_some"));
  278. start_op(impl, io_uring_service::write_op, p.p, is_continuation,
  279. buffer_sequence_adapter<boost::asio::const_buffer,
  280. ConstBufferSequence>::all_empty(buffers));
  281. p.v = p.p = 0;
  282. }
  283. // Start an asynchronous wait until data can be written without blocking.
  284. template <typename Handler, typename IoExecutor>
  285. void async_write_some(implementation_type& impl,
  286. const null_buffers&, Handler& handler, const IoExecutor& io_ex)
  287. {
  288. bool is_continuation =
  289. boost_asio_handler_cont_helpers::is_continuation(handler);
  290. associated_cancellation_slot_t<Handler> slot
  291. = boost::asio::get_associated_cancellation_slot(handler);
  292. // Allocate and construct an operation to wrap the handler.
  293. typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
  294. typename op::ptr p = { boost::asio::detail::addressof(handler),
  295. op::ptr::allocate(handler), 0 };
  296. p.p = new (p.v) op(success_ec_, impl.descriptor_, POLLOUT, handler, io_ex);
  297. // Optionally register for per-operation cancellation.
  298. if (slot.is_connected())
  299. {
  300. p.p->cancellation_key_ =
  301. &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
  302. &impl.io_object_data_, io_uring_service::write_op);
  303. }
  304. BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(),
  305. *p.p, "descriptor", &impl, impl.descriptor_,
  306. "async_write_some(null_buffers)"));
  307. start_op(impl, io_uring_service::write_op, p.p, is_continuation, false);
  308. p.v = p.p = 0;
  309. }
  310. // Write some data to the descriptor at the specified offset.
  311. template <typename ConstBufferSequence>
  312. size_t write_some_at(implementation_type& impl, uint64_t offset,
  313. const ConstBufferSequence& buffers, boost::system::error_code& ec)
  314. {
  315. typedef buffer_sequence_adapter<boost::asio::const_buffer,
  316. ConstBufferSequence> bufs_type;
  317. size_t n;
  318. if (bufs_type::is_single_buffer)
  319. {
  320. n = descriptor_ops::sync_write_at1(impl.descriptor_,
  321. impl.state_, offset, bufs_type::first(buffers).data(),
  322. bufs_type::first(buffers).size(), ec);
  323. }
  324. else
  325. {
  326. bufs_type bufs(buffers);
  327. n = descriptor_ops::sync_write_at(impl.descriptor_, impl.state_,
  328. offset, bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  329. }
  330. BOOST_ASIO_ERROR_LOCATION(ec);
  331. return n;
  332. }
  333. // Wait until data can be written without blocking.
  334. size_t write_some_at(implementation_type& impl, uint64_t,
  335. const null_buffers& buffers, boost::system::error_code& ec)
  336. {
  337. return write_some(impl, buffers, ec);
  338. }
  339. // Start an asynchronous write at the specified offset. The data being sent
  340. // must be valid for the lifetime of the asynchronous operation.
  341. template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
  342. void async_write_some_at(implementation_type& impl, uint64_t offset,
  343. const ConstBufferSequence& buffers, Handler& handler,
  344. const IoExecutor& io_ex)
  345. {
  346. bool is_continuation =
  347. boost_asio_handler_cont_helpers::is_continuation(handler);
  348. associated_cancellation_slot_t<Handler> slot
  349. = boost::asio::get_associated_cancellation_slot(handler);
  350. // Allocate and construct an operation to wrap the handler.
  351. typedef io_uring_descriptor_write_at_op<
  352. ConstBufferSequence, Handler, IoExecutor> op;
  353. typename op::ptr p = { boost::asio::detail::addressof(handler),
  354. op::ptr::allocate(handler), 0 };
  355. p.p = new (p.v) op(success_ec_, impl.descriptor_,
  356. impl.state_, offset, buffers, handler, io_ex);
  357. // Optionally register for per-operation cancellation.
  358. if (slot.is_connected())
  359. {
  360. p.p->cancellation_key_ =
  361. &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
  362. &impl.io_object_data_, io_uring_service::write_op);
  363. }
  364. BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
  365. "descriptor", &impl, impl.descriptor_, "async_write_some"));
  366. start_op(impl, io_uring_service::write_op, p.p, is_continuation,
  367. buffer_sequence_adapter<boost::asio::const_buffer,
  368. ConstBufferSequence>::all_empty(buffers));
  369. p.v = p.p = 0;
  370. }
  371. // Start an asynchronous wait until data can be written without blocking.
  372. template <typename Handler, typename IoExecutor>
  373. void async_write_some_at(implementation_type& impl,
  374. const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex)
  375. {
  376. return async_write_some(impl, buffers, handler, io_ex);
  377. }
  378. // Read some data from the stream. Returns the number of bytes read.
  379. template <typename MutableBufferSequence>
  380. size_t read_some(implementation_type& impl,
  381. const MutableBufferSequence& buffers, boost::system::error_code& ec)
  382. {
  383. typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
  384. MutableBufferSequence> bufs_type;
  385. size_t n;
  386. if (bufs_type::is_single_buffer)
  387. {
  388. n = descriptor_ops::sync_read1(impl.descriptor_,
  389. impl.state_, bufs_type::first(buffers).data(),
  390. bufs_type::first(buffers).size(), ec);
  391. }
  392. else
  393. {
  394. bufs_type bufs(buffers);
  395. n = descriptor_ops::sync_read(impl.descriptor_, impl.state_,
  396. bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  397. }
  398. BOOST_ASIO_ERROR_LOCATION(ec);
  399. return n;
  400. }
  401. // Wait until data can be read without blocking.
  402. size_t read_some(implementation_type& impl,
  403. const null_buffers&, boost::system::error_code& ec)
  404. {
  405. // Wait for descriptor to become ready.
  406. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
  407. BOOST_ASIO_ERROR_LOCATION(ec);
  408. return 0;
  409. }
  410. // Start an asynchronous read. The buffer for the data being read must be
  411. // valid for the lifetime of the asynchronous operation.
  412. template <typename MutableBufferSequence,
  413. typename Handler, typename IoExecutor>
  414. void async_read_some(implementation_type& impl,
  415. const MutableBufferSequence& buffers,
  416. Handler& handler, const IoExecutor& io_ex)
  417. {
  418. bool is_continuation =
  419. boost_asio_handler_cont_helpers::is_continuation(handler);
  420. associated_cancellation_slot_t<Handler> slot
  421. = boost::asio::get_associated_cancellation_slot(handler);
  422. // Allocate and construct an operation to wrap the handler.
  423. typedef io_uring_descriptor_read_op<
  424. MutableBufferSequence, Handler, IoExecutor> op;
  425. typename op::ptr p = { boost::asio::detail::addressof(handler),
  426. op::ptr::allocate(handler), 0 };
  427. p.p = new (p.v) op(success_ec_, impl.descriptor_,
  428. impl.state_, buffers, handler, io_ex);
  429. // Optionally register for per-operation cancellation.
  430. if (slot.is_connected())
  431. {
  432. p.p->cancellation_key_ =
  433. &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
  434. &impl.io_object_data_, io_uring_service::read_op);
  435. }
  436. BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
  437. "descriptor", &impl, impl.descriptor_, "async_read_some"));
  438. start_op(impl, io_uring_service::read_op, p.p, is_continuation,
  439. buffer_sequence_adapter<boost::asio::mutable_buffer,
  440. MutableBufferSequence>::all_empty(buffers));
  441. p.v = p.p = 0;
  442. }
  443. // Wait until data can be read without blocking.
  444. template <typename Handler, typename IoExecutor>
  445. void async_read_some(implementation_type& impl,
  446. const null_buffers&, Handler& handler, const IoExecutor& io_ex)
  447. {
  448. bool is_continuation =
  449. boost_asio_handler_cont_helpers::is_continuation(handler);
  450. associated_cancellation_slot_t<Handler> slot
  451. = boost::asio::get_associated_cancellation_slot(handler);
  452. // Allocate and construct an operation to wrap the handler.
  453. typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
  454. typename op::ptr p = { boost::asio::detail::addressof(handler),
  455. op::ptr::allocate(handler), 0 };
  456. p.p = new (p.v) op(success_ec_, impl.descriptor_, POLLIN, handler, io_ex);
  457. // Optionally register for per-operation cancellation.
  458. if (slot.is_connected())
  459. {
  460. p.p->cancellation_key_ =
  461. &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
  462. &impl.io_object_data_, io_uring_service::read_op);
  463. }
  464. BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(),
  465. *p.p, "descriptor", &impl, impl.descriptor_,
  466. "async_read_some(null_buffers)"));
  467. start_op(impl, io_uring_service::read_op, p.p, is_continuation, false);
  468. p.v = p.p = 0;
  469. }
  470. // Read some data at the specified offset. Returns the number of bytes read.
  471. template <typename MutableBufferSequence>
  472. size_t read_some_at(implementation_type& impl, uint64_t offset,
  473. const MutableBufferSequence& buffers, boost::system::error_code& ec)
  474. {
  475. typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
  476. MutableBufferSequence> bufs_type;
  477. if (bufs_type::is_single_buffer)
  478. {
  479. return descriptor_ops::sync_read_at1(impl.descriptor_,
  480. impl.state_, offset, bufs_type::first(buffers).data(),
  481. bufs_type::first(buffers).size(), ec);
  482. }
  483. else
  484. {
  485. bufs_type bufs(buffers);
  486. return descriptor_ops::sync_read_at(impl.descriptor_, impl.state_,
  487. offset, bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  488. }
  489. }
  490. // Wait until data can be read without blocking.
  491. size_t read_some_at(implementation_type& impl, uint64_t,
  492. const null_buffers& buffers, boost::system::error_code& ec)
  493. {
  494. return read_some(impl, buffers, ec);
  495. }
  496. // Start an asynchronous read. The buffer for the data being read must be
  497. // valid for the lifetime of the asynchronous operation.
  498. template <typename MutableBufferSequence,
  499. typename Handler, typename IoExecutor>
  500. void async_read_some_at(implementation_type& impl,
  501. uint64_t offset, const MutableBufferSequence& buffers,
  502. Handler& handler, const IoExecutor& io_ex)
  503. {
  504. bool is_continuation =
  505. boost_asio_handler_cont_helpers::is_continuation(handler);
  506. associated_cancellation_slot_t<Handler> slot
  507. = boost::asio::get_associated_cancellation_slot(handler);
  508. // Allocate and construct an operation to wrap the handler.
  509. typedef io_uring_descriptor_read_at_op<
  510. MutableBufferSequence, Handler, IoExecutor> op;
  511. typename op::ptr p = { boost::asio::detail::addressof(handler),
  512. op::ptr::allocate(handler), 0 };
  513. p.p = new (p.v) op(success_ec_, impl.descriptor_,
  514. impl.state_, offset, buffers, handler, io_ex);
  515. // Optionally register for per-operation cancellation.
  516. if (slot.is_connected())
  517. {
  518. p.p->cancellation_key_ =
  519. &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
  520. &impl.io_object_data_, io_uring_service::read_op);
  521. }
  522. BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
  523. "descriptor", &impl, impl.descriptor_, "async_read_some"));
  524. start_op(impl, io_uring_service::read_op, p.p, is_continuation,
  525. buffer_sequence_adapter<boost::asio::mutable_buffer,
  526. MutableBufferSequence>::all_empty(buffers));
  527. p.v = p.p = 0;
  528. }
  529. // Wait until data can be read without blocking.
  530. template <typename Handler, typename IoExecutor>
  531. void async_read_some_at(implementation_type& impl, uint64_t,
  532. const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex)
  533. {
  534. return async_read_some(impl, buffers, handler, io_ex);
  535. }
  536. private:
  537. // Start the asynchronous operation.
  538. BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type,
  539. io_uring_operation* op, bool is_continuation, bool noop);
  540. // Helper class used to implement per-operation cancellation
  541. class io_uring_op_cancellation
  542. {
  543. public:
  544. io_uring_op_cancellation(io_uring_service* s,
  545. io_uring_service::per_io_object_data* p, int o)
  546. : io_uring_service_(s),
  547. io_object_data_(p),
  548. op_type_(o)
  549. {
  550. }
  551. void operator()(cancellation_type_t type)
  552. {
  553. if (!!(type &
  554. (cancellation_type::terminal
  555. | cancellation_type::partial
  556. | cancellation_type::total)))
  557. {
  558. io_uring_service_->cancel_ops_by_key(*io_object_data_, op_type_, this);
  559. }
  560. }
  561. private:
  562. io_uring_service* io_uring_service_;
  563. io_uring_service::per_io_object_data* io_object_data_;
  564. int op_type_;
  565. };
  566. // The io_uring_service that performs event demultiplexing for the service.
  567. io_uring_service& io_uring_service_;
  568. // Cached success value to avoid accessing category singleton.
  569. const boost::system::error_code success_ec_;
  570. };
  571. } // namespace detail
  572. } // namespace asio
  573. } // namespace boost
  574. #include <boost/asio/detail/pop_options.hpp>
  575. #if defined(BOOST_ASIO_HEADER_ONLY)
  576. # include <boost/asio/detail/impl/io_uring_descriptor_service.ipp>
  577. #endif // defined(BOOST_ASIO_HEADER_ONLY)
  578. #endif // defined(BOOST_ASIO_HAS_IO_URING)
  579. #endif // BOOST_ASIO_DETAIL_IO_URING_DESCRIPTOR_SERVICE_HPP