File indexing completed on 2025-01-18 09:28:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_DETAIL_IO_URING_DESCRIPTOR_SERVICE_HPP
0012 #define BOOST_ASIO_DETAIL_IO_URING_DESCRIPTOR_SERVICE_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019
0020 #if defined(BOOST_ASIO_HAS_IO_URING)
0021
0022 #include <boost/asio/associated_cancellation_slot.hpp>
0023 #include <boost/asio/buffer.hpp>
0024 #include <boost/asio/cancellation_type.hpp>
0025 #include <boost/asio/execution_context.hpp>
0026 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
0027 #include <boost/asio/detail/descriptor_ops.hpp>
0028 #include <boost/asio/detail/io_uring_descriptor_read_at_op.hpp>
0029 #include <boost/asio/detail/io_uring_descriptor_read_op.hpp>
0030 #include <boost/asio/detail/io_uring_descriptor_write_at_op.hpp>
0031 #include <boost/asio/detail/io_uring_descriptor_write_op.hpp>
0032 #include <boost/asio/detail/io_uring_null_buffers_op.hpp>
0033 #include <boost/asio/detail/io_uring_service.hpp>
0034 #include <boost/asio/detail/io_uring_wait_op.hpp>
0035 #include <boost/asio/detail/memory.hpp>
0036 #include <boost/asio/detail/noncopyable.hpp>
0037 #include <boost/asio/posix/descriptor_base.hpp>
0038
0039 #include <boost/asio/detail/push_options.hpp>
0040
0041 namespace boost {
0042 namespace asio {
0043 namespace detail {
0044
0045 class io_uring_descriptor_service :
0046 public execution_context_service_base<io_uring_descriptor_service>
0047 {
0048 public:
0049
0050 typedef int native_handle_type;
0051
0052
0053 class implementation_type
0054 : private boost::asio::detail::noncopyable
0055 {
0056 public:
0057
0058 implementation_type()
0059 : descriptor_(-1),
0060 state_(0)
0061 {
0062 }
0063
0064 private:
0065
0066 friend class io_uring_descriptor_service;
0067
0068
0069 int descriptor_;
0070
0071
0072 descriptor_ops::state_type state_;
0073
0074
0075 io_uring_service::per_io_object_data io_object_data_;
0076 };
0077
0078
0079 BOOST_ASIO_DECL io_uring_descriptor_service(execution_context& context);
0080
0081
0082 BOOST_ASIO_DECL void shutdown();
0083
0084
0085 BOOST_ASIO_DECL void construct(implementation_type& impl);
0086
0087
0088 BOOST_ASIO_DECL void move_construct(implementation_type& impl,
0089 implementation_type& other_impl) noexcept;
0090
0091
0092 BOOST_ASIO_DECL void move_assign(implementation_type& impl,
0093 io_uring_descriptor_service& other_service,
0094 implementation_type& other_impl);
0095
0096
0097 BOOST_ASIO_DECL void destroy(implementation_type& impl);
0098
0099
0100 BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl,
0101 const native_handle_type& native_descriptor,
0102 boost::system::error_code& ec);
0103
0104
0105 bool is_open(const implementation_type& impl) const
0106 {
0107 return impl.descriptor_ != -1;
0108 }
0109
0110
0111 BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl,
0112 boost::system::error_code& ec);
0113
0114
0115 native_handle_type native_handle(const implementation_type& impl) const
0116 {
0117 return impl.descriptor_;
0118 }
0119
0120
0121 BOOST_ASIO_DECL native_handle_type release(implementation_type& impl);
0122
0123
0124 native_handle_type release(implementation_type& impl,
0125 boost::system::error_code& ec)
0126 {
0127 ec = success_ec_;
0128 return release(impl);
0129 }
0130
0131
0132 BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
0133 boost::system::error_code& ec);
0134
0135
0136 template <typename IO_Control_Command>
0137 boost::system::error_code io_control(implementation_type& impl,
0138 IO_Control_Command& command, boost::system::error_code& ec)
0139 {
0140 descriptor_ops::ioctl(impl.descriptor_, impl.state_,
0141 command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
0142 BOOST_ASIO_ERROR_LOCATION(ec);
0143 return ec;
0144 }
0145
0146
0147 bool non_blocking(const implementation_type& impl) const
0148 {
0149 return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
0150 }
0151
0152
0153 boost::system::error_code non_blocking(implementation_type& impl,
0154 bool mode, boost::system::error_code& ec)
0155 {
0156 descriptor_ops::set_user_non_blocking(
0157 impl.descriptor_, impl.state_, mode, ec);
0158 BOOST_ASIO_ERROR_LOCATION(ec);
0159 return ec;
0160 }
0161
0162
0163 bool native_non_blocking(const implementation_type& impl) const
0164 {
0165 return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
0166 }
0167
0168
0169 boost::system::error_code native_non_blocking(implementation_type& impl,
0170 bool mode, boost::system::error_code& ec)
0171 {
0172 descriptor_ops::set_internal_non_blocking(
0173 impl.descriptor_, impl.state_, mode, ec);
0174 BOOST_ASIO_ERROR_LOCATION(ec);
0175 return ec;
0176 }
0177
0178
0179
0180 boost::system::error_code wait(implementation_type& impl,
0181 posix::descriptor_base::wait_type w, boost::system::error_code& ec)
0182 {
0183 switch (w)
0184 {
0185 case posix::descriptor_base::wait_read:
0186 descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
0187 break;
0188 case posix::descriptor_base::wait_write:
0189 descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
0190 break;
0191 case posix::descriptor_base::wait_error:
0192 descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);
0193 break;
0194 default:
0195 ec = boost::asio::error::invalid_argument;
0196 break;
0197 }
0198
0199 BOOST_ASIO_ERROR_LOCATION(ec);
0200 return ec;
0201 }
0202
0203
0204
0205 template <typename Handler, typename IoExecutor>
0206 void async_wait(implementation_type& impl,
0207 posix::descriptor_base::wait_type w,
0208 Handler& handler, const IoExecutor& io_ex)
0209 {
0210 bool is_continuation =
0211 boost_asio_handler_cont_helpers::is_continuation(handler);
0212
0213 associated_cancellation_slot_t<Handler> slot
0214 = boost::asio::get_associated_cancellation_slot(handler);
0215
0216 int op_type;
0217 int poll_flags;
0218 switch (w)
0219 {
0220 case posix::descriptor_base::wait_read:
0221 op_type = io_uring_service::read_op;
0222 poll_flags = POLLIN;
0223 break;
0224 case posix::descriptor_base::wait_write:
0225 op_type = io_uring_service::write_op;
0226 poll_flags = POLLOUT;
0227 break;
0228 case posix::descriptor_base::wait_error:
0229 op_type = io_uring_service::except_op;
0230 poll_flags = POLLPRI | POLLERR | POLLHUP;
0231 break;
0232 default:
0233 op_type = -1;
0234 poll_flags = -1;
0235 return;
0236 }
0237
0238
0239 typedef io_uring_wait_op<Handler, IoExecutor> op;
0240 typename op::ptr p = { boost::asio::detail::addressof(handler),
0241 op::ptr::allocate(handler), 0 };
0242 p.p = new (p.v) op(success_ec_, impl.descriptor_,
0243 poll_flags, handler, io_ex);
0244
0245
0246 if (slot.is_connected() && op_type != -1)
0247 {
0248 p.p->cancellation_key_ =
0249 &slot.template emplace<io_uring_op_cancellation>(
0250 &io_uring_service_, &impl.io_object_data_, op_type);
0251 }
0252
0253 BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0254 "descriptor", &impl, impl.descriptor_, "async_wait"));
0255
0256 start_op(impl, op_type, p.p, is_continuation, op_type == -1);
0257 p.v = p.p = 0;
0258 }
0259
0260
0261 template <typename ConstBufferSequence>
0262 size_t write_some(implementation_type& impl,
0263 const ConstBufferSequence& buffers, boost::system::error_code& ec)
0264 {
0265 typedef buffer_sequence_adapter<boost::asio::const_buffer,
0266 ConstBufferSequence> bufs_type;
0267
0268 size_t n;
0269 if (bufs_type::is_single_buffer)
0270 {
0271 n = descriptor_ops::sync_write1(impl.descriptor_,
0272 impl.state_, bufs_type::first(buffers).data(),
0273 bufs_type::first(buffers).size(), ec);
0274 }
0275 else
0276 {
0277 bufs_type bufs(buffers);
0278
0279 n = descriptor_ops::sync_write(impl.descriptor_, impl.state_,
0280 bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
0281 }
0282
0283 BOOST_ASIO_ERROR_LOCATION(ec);
0284 return n;
0285 }
0286
0287
0288 size_t write_some(implementation_type& impl,
0289 const null_buffers&, boost::system::error_code& ec)
0290 {
0291
0292 descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
0293
0294 BOOST_ASIO_ERROR_LOCATION(ec);
0295 return 0;
0296 }
0297
0298
0299
0300 template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
0301 void async_write_some(implementation_type& impl,
0302 const ConstBufferSequence& buffers, Handler& handler,
0303 const IoExecutor& io_ex)
0304 {
0305 bool is_continuation =
0306 boost_asio_handler_cont_helpers::is_continuation(handler);
0307
0308 associated_cancellation_slot_t<Handler> slot
0309 = boost::asio::get_associated_cancellation_slot(handler);
0310
0311
0312 typedef io_uring_descriptor_write_op<
0313 ConstBufferSequence, Handler, IoExecutor> op;
0314 typename op::ptr p = { boost::asio::detail::addressof(handler),
0315 op::ptr::allocate(handler), 0 };
0316 p.p = new (p.v) op(success_ec_, impl.descriptor_,
0317 impl.state_, buffers, handler, io_ex);
0318
0319
0320 if (slot.is_connected())
0321 {
0322 p.p->cancellation_key_ =
0323 &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0324 &impl.io_object_data_, io_uring_service::write_op);
0325 }
0326
0327 BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0328 "descriptor", &impl, impl.descriptor_, "async_write_some"));
0329
0330 start_op(impl, io_uring_service::write_op, p.p, is_continuation,
0331 buffer_sequence_adapter<boost::asio::const_buffer,
0332 ConstBufferSequence>::all_empty(buffers));
0333 p.v = p.p = 0;
0334 }
0335
0336
0337 template <typename Handler, typename IoExecutor>
0338 void async_write_some(implementation_type& impl,
0339 const null_buffers&, Handler& handler, const IoExecutor& io_ex)
0340 {
0341 bool is_continuation =
0342 boost_asio_handler_cont_helpers::is_continuation(handler);
0343
0344 associated_cancellation_slot_t<Handler> slot
0345 = boost::asio::get_associated_cancellation_slot(handler);
0346
0347
0348 typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
0349 typename op::ptr p = { boost::asio::detail::addressof(handler),
0350 op::ptr::allocate(handler), 0 };
0351 p.p = new (p.v) op(success_ec_, impl.descriptor_, POLLOUT, handler, io_ex);
0352
0353
0354 if (slot.is_connected())
0355 {
0356 p.p->cancellation_key_ =
0357 &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0358 &impl.io_object_data_, io_uring_service::write_op);
0359 }
0360
0361 BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(),
0362 *p.p, "descriptor", &impl, impl.descriptor_,
0363 "async_write_some(null_buffers)"));
0364
0365 start_op(impl, io_uring_service::write_op, p.p, is_continuation, false);
0366 p.v = p.p = 0;
0367 }
0368
0369
0370 template <typename ConstBufferSequence>
0371 size_t write_some_at(implementation_type& impl, uint64_t offset,
0372 const ConstBufferSequence& buffers, boost::system::error_code& ec)
0373 {
0374 typedef buffer_sequence_adapter<boost::asio::const_buffer,
0375 ConstBufferSequence> bufs_type;
0376
0377 size_t n;
0378 if (bufs_type::is_single_buffer)
0379 {
0380 n = descriptor_ops::sync_write_at1(impl.descriptor_,
0381 impl.state_, offset, bufs_type::first(buffers).data(),
0382 bufs_type::first(buffers).size(), ec);
0383 }
0384 else
0385 {
0386 bufs_type bufs(buffers);
0387
0388 n = descriptor_ops::sync_write_at(impl.descriptor_, impl.state_,
0389 offset, bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
0390 }
0391
0392 BOOST_ASIO_ERROR_LOCATION(ec);
0393 return n;
0394 }
0395
0396
0397 size_t write_some_at(implementation_type& impl, uint64_t,
0398 const null_buffers& buffers, boost::system::error_code& ec)
0399 {
0400 return write_some(impl, buffers, ec);
0401 }
0402
0403
0404
0405 template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
0406 void async_write_some_at(implementation_type& impl, uint64_t offset,
0407 const ConstBufferSequence& buffers, Handler& handler,
0408 const IoExecutor& io_ex)
0409 {
0410 bool is_continuation =
0411 boost_asio_handler_cont_helpers::is_continuation(handler);
0412
0413 associated_cancellation_slot_t<Handler> slot
0414 = boost::asio::get_associated_cancellation_slot(handler);
0415
0416
0417 typedef io_uring_descriptor_write_at_op<
0418 ConstBufferSequence, Handler, IoExecutor> op;
0419 typename op::ptr p = { boost::asio::detail::addressof(handler),
0420 op::ptr::allocate(handler), 0 };
0421 p.p = new (p.v) op(success_ec_, impl.descriptor_,
0422 impl.state_, offset, buffers, handler, io_ex);
0423
0424
0425 if (slot.is_connected())
0426 {
0427 p.p->cancellation_key_ =
0428 &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0429 &impl.io_object_data_, io_uring_service::write_op);
0430 }
0431
0432 BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0433 "descriptor", &impl, impl.descriptor_, "async_write_some"));
0434
0435 start_op(impl, io_uring_service::write_op, p.p, is_continuation,
0436 buffer_sequence_adapter<boost::asio::const_buffer,
0437 ConstBufferSequence>::all_empty(buffers));
0438 p.v = p.p = 0;
0439 }
0440
0441
0442 template <typename Handler, typename IoExecutor>
0443 void async_write_some_at(implementation_type& impl,
0444 const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex)
0445 {
0446 return async_write_some(impl, buffers, handler, io_ex);
0447 }
0448
0449
0450 template <typename MutableBufferSequence>
0451 size_t read_some(implementation_type& impl,
0452 const MutableBufferSequence& buffers, boost::system::error_code& ec)
0453 {
0454 typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
0455 MutableBufferSequence> bufs_type;
0456
0457 size_t n;
0458 if (bufs_type::is_single_buffer)
0459 {
0460 n = descriptor_ops::sync_read1(impl.descriptor_,
0461 impl.state_, bufs_type::first(buffers).data(),
0462 bufs_type::first(buffers).size(), ec);
0463 }
0464 else
0465 {
0466 bufs_type bufs(buffers);
0467
0468 n = descriptor_ops::sync_read(impl.descriptor_, impl.state_,
0469 bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
0470 }
0471
0472 BOOST_ASIO_ERROR_LOCATION(ec);
0473 return n;
0474 }
0475
0476
0477 size_t read_some(implementation_type& impl,
0478 const null_buffers&, boost::system::error_code& ec)
0479 {
0480
0481 descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
0482
0483 BOOST_ASIO_ERROR_LOCATION(ec);
0484 return 0;
0485 }
0486
0487
0488
0489 template <typename MutableBufferSequence,
0490 typename Handler, typename IoExecutor>
0491 void async_read_some(implementation_type& impl,
0492 const MutableBufferSequence& buffers,
0493 Handler& handler, const IoExecutor& io_ex)
0494 {
0495 bool is_continuation =
0496 boost_asio_handler_cont_helpers::is_continuation(handler);
0497
0498 associated_cancellation_slot_t<Handler> slot
0499 = boost::asio::get_associated_cancellation_slot(handler);
0500
0501
0502 typedef io_uring_descriptor_read_op<
0503 MutableBufferSequence, Handler, IoExecutor> op;
0504 typename op::ptr p = { boost::asio::detail::addressof(handler),
0505 op::ptr::allocate(handler), 0 };
0506 p.p = new (p.v) op(success_ec_, impl.descriptor_,
0507 impl.state_, buffers, handler, io_ex);
0508
0509
0510 if (slot.is_connected())
0511 {
0512 p.p->cancellation_key_ =
0513 &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0514 &impl.io_object_data_, io_uring_service::read_op);
0515 }
0516
0517 BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0518 "descriptor", &impl, impl.descriptor_, "async_read_some"));
0519
0520 start_op(impl, io_uring_service::read_op, p.p, is_continuation,
0521 buffer_sequence_adapter<boost::asio::mutable_buffer,
0522 MutableBufferSequence>::all_empty(buffers));
0523 p.v = p.p = 0;
0524 }
0525
0526
0527 template <typename Handler, typename IoExecutor>
0528 void async_read_some(implementation_type& impl,
0529 const null_buffers&, Handler& handler, const IoExecutor& io_ex)
0530 {
0531 bool is_continuation =
0532 boost_asio_handler_cont_helpers::is_continuation(handler);
0533
0534 associated_cancellation_slot_t<Handler> slot
0535 = boost::asio::get_associated_cancellation_slot(handler);
0536
0537
0538 typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
0539 typename op::ptr p = { boost::asio::detail::addressof(handler),
0540 op::ptr::allocate(handler), 0 };
0541 p.p = new (p.v) op(success_ec_, impl.descriptor_, POLLIN, handler, io_ex);
0542
0543
0544 if (slot.is_connected())
0545 {
0546 p.p->cancellation_key_ =
0547 &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0548 &impl.io_object_data_, io_uring_service::read_op);
0549 }
0550
0551 BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(),
0552 *p.p, "descriptor", &impl, impl.descriptor_,
0553 "async_read_some(null_buffers)"));
0554
0555 start_op(impl, io_uring_service::read_op, p.p, is_continuation, false);
0556 p.v = p.p = 0;
0557 }
0558
0559
0560 template <typename MutableBufferSequence>
0561 size_t read_some_at(implementation_type& impl, uint64_t offset,
0562 const MutableBufferSequence& buffers, boost::system::error_code& ec)
0563 {
0564 typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
0565 MutableBufferSequence> bufs_type;
0566
0567 if (bufs_type::is_single_buffer)
0568 {
0569 return descriptor_ops::sync_read_at1(impl.descriptor_,
0570 impl.state_, offset, bufs_type::first(buffers).data(),
0571 bufs_type::first(buffers).size(), ec);
0572 }
0573 else
0574 {
0575 bufs_type bufs(buffers);
0576
0577 return descriptor_ops::sync_read_at(impl.descriptor_, impl.state_,
0578 offset, bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
0579 }
0580 }
0581
0582
0583 size_t read_some_at(implementation_type& impl, uint64_t,
0584 const null_buffers& buffers, boost::system::error_code& ec)
0585 {
0586 return read_some(impl, buffers, ec);
0587 }
0588
0589
0590
0591 template <typename MutableBufferSequence,
0592 typename Handler, typename IoExecutor>
0593 void async_read_some_at(implementation_type& impl,
0594 uint64_t offset, const MutableBufferSequence& buffers,
0595 Handler& handler, const IoExecutor& io_ex)
0596 {
0597 bool is_continuation =
0598 boost_asio_handler_cont_helpers::is_continuation(handler);
0599
0600 associated_cancellation_slot_t<Handler> slot
0601 = boost::asio::get_associated_cancellation_slot(handler);
0602
0603
0604 typedef io_uring_descriptor_read_at_op<
0605 MutableBufferSequence, Handler, IoExecutor> op;
0606 typename op::ptr p = { boost::asio::detail::addressof(handler),
0607 op::ptr::allocate(handler), 0 };
0608 p.p = new (p.v) op(success_ec_, impl.descriptor_,
0609 impl.state_, offset, buffers, handler, io_ex);
0610
0611
0612 if (slot.is_connected())
0613 {
0614 p.p->cancellation_key_ =
0615 &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0616 &impl.io_object_data_, io_uring_service::read_op);
0617 }
0618
0619 BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0620 "descriptor", &impl, impl.descriptor_, "async_read_some"));
0621
0622 start_op(impl, io_uring_service::read_op, p.p, is_continuation,
0623 buffer_sequence_adapter<boost::asio::mutable_buffer,
0624 MutableBufferSequence>::all_empty(buffers));
0625 p.v = p.p = 0;
0626 }
0627
0628
0629 template <typename Handler, typename IoExecutor>
0630 void async_read_some_at(implementation_type& impl, uint64_t,
0631 const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex)
0632 {
0633 return async_read_some(impl, buffers, handler, io_ex);
0634 }
0635
0636 private:
0637
0638 BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type,
0639 io_uring_operation* op, bool is_continuation, bool noop);
0640
0641
0642 class io_uring_op_cancellation
0643 {
0644 public:
0645 io_uring_op_cancellation(io_uring_service* s,
0646 io_uring_service::per_io_object_data* p, int o)
0647 : io_uring_service_(s),
0648 io_object_data_(p),
0649 op_type_(o)
0650 {
0651 }
0652
0653 void operator()(cancellation_type_t type)
0654 {
0655 if (!!(type &
0656 (cancellation_type::terminal
0657 | cancellation_type::partial
0658 | cancellation_type::total)))
0659 {
0660 io_uring_service_->cancel_ops_by_key(*io_object_data_, op_type_, this);
0661 }
0662 }
0663
0664 private:
0665 io_uring_service* io_uring_service_;
0666 io_uring_service::per_io_object_data* io_object_data_;
0667 int op_type_;
0668 };
0669
0670
0671 io_uring_service& io_uring_service_;
0672
0673
0674 const boost::system::error_code success_ec_;
0675 };
0676
0677 }
0678 }
0679 }
0680
0681 #include <boost/asio/detail/pop_options.hpp>
0682
0683 #if defined(BOOST_ASIO_HEADER_ONLY)
0684 # include <boost/asio/detail/impl/io_uring_descriptor_service.ipp>
0685 #endif
0686
0687 #endif
0688
0689 #endif