Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:41

0001 //
0002 // detail/io_uring_socket_service_base.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_IO_URING_SOCKET_SERVICE_BASE_HPP
0012 #define BOOST_ASIO_DETAIL_IO_URING_SOCKET_SERVICE_BASE_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if defined(BOOST_ASIO_HAS_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/error.hpp>
0026 #include <boost/asio/execution_context.hpp>
0027 #include <boost/asio/socket_base.hpp>
0028 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
0029 #include <boost/asio/detail/memory.hpp>
0030 #include <boost/asio/detail/io_uring_null_buffers_op.hpp>
0031 #include <boost/asio/detail/io_uring_service.hpp>
0032 #include <boost/asio/detail/io_uring_socket_recv_op.hpp>
0033 #include <boost/asio/detail/io_uring_socket_recvmsg_op.hpp>
0034 #include <boost/asio/detail/io_uring_socket_send_op.hpp>
0035 #include <boost/asio/detail/io_uring_wait_op.hpp>
0036 #include <boost/asio/detail/socket_holder.hpp>
0037 #include <boost/asio/detail/socket_ops.hpp>
0038 #include <boost/asio/detail/socket_types.hpp>
0039 
0040 #include <boost/asio/detail/push_options.hpp>
0041 
0042 namespace boost {
0043 namespace asio {
0044 namespace detail {
0045 
0046 class io_uring_socket_service_base
0047 {
0048 public:
0049   // The native type of a socket.
0050   typedef socket_type native_handle_type;
0051 
0052   // The implementation type of the socket.
0053   struct base_implementation_type
0054   {
0055     // The native socket representation.
0056     socket_type socket_;
0057 
0058     // The current state of the socket.
0059     socket_ops::state_type state_;
0060 
0061     // Per I/O object data used by the io_uring_service.
0062     io_uring_service::per_io_object_data io_object_data_;
0063   };
0064 
0065   // Constructor.
0066   BOOST_ASIO_DECL io_uring_socket_service_base(execution_context& context);
0067 
0068   // Destroy all user-defined handler objects owned by the service.
0069   BOOST_ASIO_DECL void base_shutdown();
0070 
0071   // Construct a new socket implementation.
0072   BOOST_ASIO_DECL void construct(base_implementation_type& impl);
0073 
0074   // Move-construct a new socket implementation.
0075   BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl,
0076       base_implementation_type& other_impl) noexcept;
0077 
0078   // Move-assign from another socket implementation.
0079   BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl,
0080       io_uring_socket_service_base& other_service,
0081       base_implementation_type& other_impl);
0082 
0083   // Destroy a socket implementation.
0084   BOOST_ASIO_DECL void destroy(base_implementation_type& impl);
0085 
0086   // Determine whether the socket is open.
0087   bool is_open(const base_implementation_type& impl) const
0088   {
0089     return impl.socket_ != invalid_socket;
0090   }
0091 
0092   // Destroy a socket implementation.
0093   BOOST_ASIO_DECL boost::system::error_code close(
0094       base_implementation_type& impl, boost::system::error_code& ec);
0095 
0096   // Release ownership of the socket.
0097   BOOST_ASIO_DECL socket_type release(
0098       base_implementation_type& impl, boost::system::error_code& ec);
0099 
0100   // Get the native socket representation.
0101   native_handle_type native_handle(base_implementation_type& impl)
0102   {
0103     return impl.socket_;
0104   }
0105 
0106   // Cancel all operations associated with the socket.
0107   BOOST_ASIO_DECL boost::system::error_code cancel(
0108       base_implementation_type& impl, boost::system::error_code& ec);
0109 
0110   // Determine whether the socket is at the out-of-band data mark.
0111   bool at_mark(const base_implementation_type& impl,
0112       boost::system::error_code& ec) const
0113   {
0114     return socket_ops::sockatmark(impl.socket_, ec);
0115   }
0116 
0117   // Determine the number of bytes available for reading.
0118   std::size_t available(const base_implementation_type& impl,
0119       boost::system::error_code& ec) const
0120   {
0121     return socket_ops::available(impl.socket_, ec);
0122   }
0123 
0124   // Place the socket into the state where it will listen for new connections.
0125   boost::system::error_code listen(base_implementation_type& impl,
0126       int backlog, boost::system::error_code& ec)
0127   {
0128     socket_ops::listen(impl.socket_, backlog, ec);
0129     return ec;
0130   }
0131 
0132   // Perform an IO control command on the socket.
0133   template <typename IO_Control_Command>
0134   boost::system::error_code io_control(base_implementation_type& impl,
0135       IO_Control_Command& command, boost::system::error_code& ec)
0136   {
0137     socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
0138         static_cast<ioctl_arg_type*>(command.data()), ec);
0139     return ec;
0140   }
0141 
0142   // Gets the non-blocking mode of the socket.
0143   bool non_blocking(const base_implementation_type& impl) const
0144   {
0145     return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
0146   }
0147 
0148   // Sets the non-blocking mode of the socket.
0149   boost::system::error_code non_blocking(base_implementation_type& impl,
0150       bool mode, boost::system::error_code& ec)
0151   {
0152     socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
0153     return ec;
0154   }
0155 
0156   // Gets the non-blocking mode of the native socket implementation.
0157   bool native_non_blocking(const base_implementation_type& impl) const
0158   {
0159     return (impl.state_ & socket_ops::internal_non_blocking) != 0;
0160   }
0161 
0162   // Sets the non-blocking mode of the native socket implementation.
0163   boost::system::error_code native_non_blocking(base_implementation_type& impl,
0164       bool mode, boost::system::error_code& ec)
0165   {
0166     socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
0167     return ec;
0168   }
0169 
0170   // Wait for the socket to become ready to read, ready to write, or to have
0171   // pending error conditions.
0172   boost::system::error_code wait(base_implementation_type& impl,
0173       socket_base::wait_type w, boost::system::error_code& ec)
0174   {
0175     switch (w)
0176     {
0177     case socket_base::wait_read:
0178       socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
0179       break;
0180     case socket_base::wait_write:
0181       socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
0182       break;
0183     case socket_base::wait_error:
0184       socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
0185       break;
0186     default:
0187       ec = boost::asio::error::invalid_argument;
0188       break;
0189     }
0190 
0191     return ec;
0192   }
0193 
0194   // Asynchronously wait for the socket to become ready to read, ready to
0195   // write, or to have pending error conditions.
0196   template <typename Handler, typename IoExecutor>
0197   void async_wait(base_implementation_type& impl,
0198       socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
0199   {
0200     bool is_continuation =
0201       boost_asio_handler_cont_helpers::is_continuation(handler);
0202 
0203     associated_cancellation_slot_t<Handler> slot
0204       = boost::asio::get_associated_cancellation_slot(handler);
0205 
0206     int op_type;
0207     int poll_flags;
0208     switch (w)
0209     {
0210     case socket_base::wait_read:
0211       op_type = io_uring_service::read_op;
0212       poll_flags = POLLIN;
0213       break;
0214     case socket_base::wait_write:
0215       op_type = io_uring_service::write_op;
0216       poll_flags = POLLOUT;
0217       break;
0218     case socket_base::wait_error:
0219       op_type = io_uring_service::except_op;
0220       poll_flags = POLLPRI | POLLERR | POLLHUP;
0221       break;
0222     default:
0223       op_type = -1;
0224       poll_flags = -1;
0225       return;
0226     }
0227 
0228     // Allocate and construct an operation to wrap the handler.
0229     typedef io_uring_wait_op<Handler, IoExecutor> op;
0230     typename op::ptr p = { boost::asio::detail::addressof(handler),
0231       op::ptr::allocate(handler), 0 };
0232     p.p = new (p.v) op(success_ec_, impl.socket_,
0233         poll_flags, handler, io_ex);
0234 
0235     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0236           "socket", &impl, impl.socket_, "async_wait"));
0237 
0238     // Optionally register for per-operation cancellation.
0239     if (slot.is_connected())
0240     {
0241       p.p->cancellation_key_ =
0242         &slot.template emplace<io_uring_op_cancellation>(
0243             &io_uring_service_, &impl.io_object_data_, op_type);
0244     }
0245 
0246     start_op(impl, op_type, p.p, is_continuation, op_type == -1);
0247     p.v = p.p = 0;
0248   }
0249 
0250   // Send the given data to the peer.
0251   template <typename ConstBufferSequence>
0252   size_t send(base_implementation_type& impl,
0253       const ConstBufferSequence& buffers,
0254       socket_base::message_flags flags, boost::system::error_code& ec)
0255   {
0256     typedef buffer_sequence_adapter<boost::asio::const_buffer,
0257         ConstBufferSequence> bufs_type;
0258 
0259     if (bufs_type::is_single_buffer)
0260     {
0261       return socket_ops::sync_send1(impl.socket_,
0262           impl.state_, bufs_type::first(buffers).data(),
0263           bufs_type::first(buffers).size(), flags, ec);
0264     }
0265     else
0266     {
0267       bufs_type bufs(buffers);
0268       return socket_ops::sync_send(impl.socket_, impl.state_,
0269           bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
0270     }
0271   }
0272 
0273   // Wait until data can be sent without blocking.
0274   size_t send(base_implementation_type& impl, const null_buffers&,
0275       socket_base::message_flags, boost::system::error_code& ec)
0276   {
0277     // Wait for socket to become ready.
0278     socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
0279 
0280     return 0;
0281   }
0282 
0283   // Start an asynchronous send. The data being sent must be valid for the
0284   // lifetime of the asynchronous operation.
0285   template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
0286   void async_send(base_implementation_type& impl,
0287       const ConstBufferSequence& buffers, socket_base::message_flags flags,
0288       Handler& handler, const IoExecutor& io_ex)
0289   {
0290     bool is_continuation =
0291       boost_asio_handler_cont_helpers::is_continuation(handler);
0292 
0293     associated_cancellation_slot_t<Handler> slot
0294       = boost::asio::get_associated_cancellation_slot(handler);
0295 
0296     // Allocate and construct an operation to wrap the handler.
0297     typedef io_uring_socket_send_op<
0298         ConstBufferSequence, Handler, IoExecutor> op;
0299     typename op::ptr p = { boost::asio::detail::addressof(handler),
0300       op::ptr::allocate(handler), 0 };
0301     p.p = new (p.v) op(success_ec_, impl.socket_,
0302         impl.state_, buffers, flags, handler, io_ex);
0303 
0304     // Optionally register for per-operation cancellation.
0305     if (slot.is_connected())
0306     {
0307       p.p->cancellation_key_ =
0308         &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0309             &impl.io_object_data_, io_uring_service::write_op);
0310     }
0311 
0312     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0313           "socket", &impl, impl.socket_, "async_send"));
0314 
0315     start_op(impl, io_uring_service::write_op, p.p, is_continuation,
0316         ((impl.state_ & socket_ops::stream_oriented)
0317           && buffer_sequence_adapter<boost::asio::const_buffer,
0318             ConstBufferSequence>::all_empty(buffers)));
0319     p.v = p.p = 0;
0320   }
0321 
0322   // Start an asynchronous wait until data can be sent without blocking.
0323   template <typename Handler, typename IoExecutor>
0324   void async_send(base_implementation_type& impl, const null_buffers&,
0325       socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
0326   {
0327     bool is_continuation =
0328       boost_asio_handler_cont_helpers::is_continuation(handler);
0329 
0330     associated_cancellation_slot_t<Handler> slot
0331       = boost::asio::get_associated_cancellation_slot(handler);
0332 
0333     // Allocate and construct an operation to wrap the handler.
0334     typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
0335     typename op::ptr p = { boost::asio::detail::addressof(handler),
0336       op::ptr::allocate(handler), 0 };
0337     p.p = new (p.v) op(success_ec_, impl.socket_, POLLOUT, handler, io_ex);
0338 
0339     // Optionally register for per-operation cancellation.
0340     if (slot.is_connected())
0341     {
0342       p.p->cancellation_key_ =
0343         &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_,
0344             &impl.io_object_data_, io_uring_service::write_op);
0345     }
0346 
0347     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0348           "socket", &impl, impl.socket_, "async_send(null_buffers)"));
0349 
0350     start_op(impl, io_uring_service::write_op, p.p, is_continuation, false);
0351     p.v = p.p = 0;
0352   }
0353 
0354   // Receive some data from the peer. Returns the number of bytes received.
0355   template <typename MutableBufferSequence>
0356   size_t receive(base_implementation_type& impl,
0357       const MutableBufferSequence& buffers,
0358       socket_base::message_flags flags, boost::system::error_code& ec)
0359   {
0360     typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
0361         MutableBufferSequence> bufs_type;
0362 
0363     if (bufs_type::is_single_buffer)
0364     {
0365       return socket_ops::sync_recv1(impl.socket_,
0366           impl.state_, bufs_type::first(buffers).data(),
0367           bufs_type::first(buffers).size(), flags, ec);
0368     }
0369     else
0370     {
0371       bufs_type bufs(buffers);
0372       return socket_ops::sync_recv(impl.socket_, impl.state_,
0373           bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
0374     }
0375   }
0376 
0377   // Wait until data can be received without blocking.
0378   size_t receive(base_implementation_type& impl, const null_buffers&,
0379       socket_base::message_flags, boost::system::error_code& ec)
0380   {
0381     // Wait for socket to become ready.
0382     socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
0383 
0384     return 0;
0385   }
0386 
0387   // Start an asynchronous receive. The buffer for the data being received
0388   // must be valid for the lifetime of the asynchronous operation.
0389   template <typename MutableBufferSequence,
0390       typename Handler, typename IoExecutor>
0391   void async_receive(base_implementation_type& impl,
0392       const MutableBufferSequence& buffers, socket_base::message_flags flags,
0393       Handler& handler, const IoExecutor& io_ex)
0394   {
0395     bool is_continuation =
0396       boost_asio_handler_cont_helpers::is_continuation(handler);
0397 
0398     int op_type = (flags & socket_base::message_out_of_band)
0399       ? io_uring_service::except_op : io_uring_service::read_op;
0400 
0401     associated_cancellation_slot_t<Handler> slot
0402       = boost::asio::get_associated_cancellation_slot(handler);
0403 
0404     // Allocate and construct an operation to wrap the handler.
0405     typedef io_uring_socket_recv_op<
0406         MutableBufferSequence, Handler, IoExecutor> op;
0407     typename op::ptr p = { boost::asio::detail::addressof(handler),
0408       op::ptr::allocate(handler), 0 };
0409     p.p = new (p.v) op(success_ec_, impl.socket_,
0410         impl.state_, buffers, flags, handler, io_ex);
0411 
0412     // Optionally register for per-operation cancellation.
0413     if (slot.is_connected())
0414     {
0415       p.p->cancellation_key_ =
0416         &slot.template emplace<io_uring_op_cancellation>(
0417             &io_uring_service_, &impl.io_object_data_, op_type);
0418     }
0419 
0420     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0421           "socket", &impl, impl.socket_, "async_receive"));
0422 
0423     start_op(impl, op_type, p.p, is_continuation,
0424         ((impl.state_ & socket_ops::stream_oriented)
0425           && buffer_sequence_adapter<boost::asio::mutable_buffer,
0426             MutableBufferSequence>::all_empty(buffers)));
0427     p.v = p.p = 0;
0428   }
0429 
0430   // Wait until data can be received without blocking.
0431   template <typename Handler, typename IoExecutor>
0432   void async_receive(base_implementation_type& impl,
0433       const null_buffers&, socket_base::message_flags flags,
0434       Handler& handler, const IoExecutor& io_ex)
0435   {
0436     bool is_continuation =
0437       boost_asio_handler_cont_helpers::is_continuation(handler);
0438 
0439     int op_type;
0440     int poll_flags;
0441     if ((flags & socket_base::message_out_of_band) != 0)
0442     {
0443       op_type = io_uring_service::except_op;
0444       poll_flags = POLLPRI;
0445     }
0446     else
0447     {
0448       op_type = io_uring_service::read_op;
0449       poll_flags = POLLIN;
0450     }
0451 
0452     associated_cancellation_slot_t<Handler> slot
0453       = boost::asio::get_associated_cancellation_slot(handler);
0454 
0455     // Allocate and construct an operation to wrap the handler.
0456     typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
0457     typename op::ptr p = { boost::asio::detail::addressof(handler),
0458       op::ptr::allocate(handler), 0 };
0459     p.p = new (p.v) op(success_ec_, impl.socket_, poll_flags, handler, io_ex);
0460 
0461     // Optionally register for per-operation cancellation.
0462     if (slot.is_connected())
0463     {
0464       p.p->cancellation_key_ =
0465         &slot.template emplace<io_uring_op_cancellation>(
0466             &io_uring_service_, &impl.io_object_data_, op_type);
0467     }
0468 
0469     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0470           "socket", &impl, impl.socket_, "async_receive(null_buffers)"));
0471 
0472     start_op(impl, op_type, p.p, is_continuation, false);
0473     p.v = p.p = 0;
0474   }
0475 
0476   // Receive some data with associated flags. Returns the number of bytes
0477   // received.
0478   template <typename MutableBufferSequence>
0479   size_t receive_with_flags(base_implementation_type& impl,
0480       const MutableBufferSequence& buffers,
0481       socket_base::message_flags in_flags,
0482       socket_base::message_flags& out_flags, boost::system::error_code& ec)
0483   {
0484     buffer_sequence_adapter<boost::asio::mutable_buffer,
0485         MutableBufferSequence> bufs(buffers);
0486 
0487     return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
0488         bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
0489   }
0490 
0491   // Wait until data can be received without blocking.
0492   size_t receive_with_flags(base_implementation_type& impl,
0493       const null_buffers&, socket_base::message_flags,
0494       socket_base::message_flags& out_flags, boost::system::error_code& ec)
0495   {
0496     // Wait for socket to become ready.
0497     socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
0498 
0499     // Clear out_flags, since we cannot give it any other sensible value when
0500     // performing a null_buffers operation.
0501     out_flags = 0;
0502 
0503     return 0;
0504   }
0505 
0506   // Start an asynchronous receive. The buffer for the data being received
0507   // must be valid for the lifetime of the asynchronous operation.
0508   template <typename MutableBufferSequence,
0509       typename Handler, typename IoExecutor>
0510   void async_receive_with_flags(base_implementation_type& impl,
0511       const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
0512       socket_base::message_flags& out_flags, Handler& handler,
0513       const IoExecutor& io_ex)
0514   {
0515     bool is_continuation =
0516       boost_asio_handler_cont_helpers::is_continuation(handler);
0517 
0518     int op_type = (in_flags & socket_base::message_out_of_band)
0519       ? io_uring_service::except_op : io_uring_service::read_op;
0520 
0521     associated_cancellation_slot_t<Handler> slot
0522       = boost::asio::get_associated_cancellation_slot(handler);
0523 
0524     // Allocate and construct an operation to wrap the handler.
0525     typedef io_uring_socket_recvmsg_op<
0526         MutableBufferSequence, Handler, IoExecutor> op;
0527     typename op::ptr p = { boost::asio::detail::addressof(handler),
0528       op::ptr::allocate(handler), 0 };
0529     p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
0530         buffers, in_flags, out_flags, handler, io_ex);
0531 
0532     // Optionally register for per-operation cancellation.
0533     if (slot.is_connected())
0534     {
0535       p.p->cancellation_key_ =
0536         &slot.template emplace<io_uring_op_cancellation>(
0537             &io_uring_service_, &impl.io_object_data_, op_type);
0538     }
0539 
0540     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p,
0541           "socket", &impl, impl.socket_, "async_receive_with_flags"));
0542 
0543     start_op(impl, op_type, p.p, is_continuation, false);
0544     p.v = p.p = 0;
0545   }
0546 
0547   // Wait until data can be received without blocking.
0548   template <typename Handler, typename IoExecutor>
0549   void async_receive_with_flags(base_implementation_type& impl,
0550       const null_buffers&, socket_base::message_flags in_flags,
0551       socket_base::message_flags& out_flags, Handler& handler,
0552       const IoExecutor& io_ex)
0553   {
0554     bool is_continuation =
0555       boost_asio_handler_cont_helpers::is_continuation(handler);
0556 
0557     int op_type;
0558     int poll_flags;
0559     if ((in_flags & socket_base::message_out_of_band) != 0)
0560     {
0561       op_type = io_uring_service::except_op;
0562       poll_flags = POLLPRI;
0563     }
0564     else
0565     {
0566       op_type = io_uring_service::read_op;
0567       poll_flags = POLLIN;
0568     }
0569 
0570     associated_cancellation_slot_t<Handler> slot
0571       = boost::asio::get_associated_cancellation_slot(handler);
0572 
0573     // Allocate and construct an operation to wrap the handler.
0574     typedef io_uring_null_buffers_op<Handler, IoExecutor> op;
0575     typename op::ptr p = { boost::asio::detail::addressof(handler),
0576       op::ptr::allocate(handler), 0 };
0577     p.p = new (p.v) op(success_ec_, impl.socket_, poll_flags, handler, io_ex);
0578 
0579     // Optionally register for per-operation cancellation.
0580     if (slot.is_connected())
0581     {
0582       p.p->cancellation_key_ =
0583         &slot.template emplace<io_uring_op_cancellation>(
0584             &io_uring_service_, &impl.io_object_data_, op_type);
0585     }
0586 
0587     BOOST_ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, "socket",
0588           &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
0589 
0590     // Clear out_flags, since we cannot give it any other sensible value when
0591     // performing a null_buffers operation.
0592     out_flags = 0;
0593 
0594     start_op(impl, op_type, p.p, is_continuation, false);
0595     p.v = p.p = 0;
0596   }
0597 
0598 protected:
0599   // Open a new socket implementation.
0600   BOOST_ASIO_DECL boost::system::error_code do_open(
0601       base_implementation_type& impl, int af,
0602       int type, int protocol, boost::system::error_code& ec);
0603 
0604   // Assign a native socket to a socket implementation.
0605   BOOST_ASIO_DECL boost::system::error_code do_assign(
0606       base_implementation_type& impl, int type,
0607       const native_handle_type& native_socket, boost::system::error_code& ec);
0608 
0609   // Start the asynchronous read or write operation.
0610   BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
0611       io_uring_operation* op, bool is_continuation, bool noop);
0612 
0613   // Start the asynchronous accept operation.
0614   BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl,
0615       io_uring_operation* op, bool is_continuation, bool peer_is_open);
0616 
0617   // Helper class used to implement per-operation cancellation
0618   class io_uring_op_cancellation
0619   {
0620   public:
0621     io_uring_op_cancellation(io_uring_service* s,
0622         io_uring_service::per_io_object_data* p, int o)
0623       : io_uring_service_(s),
0624         io_object_data_(p),
0625         op_type_(o)
0626     {
0627     }
0628 
0629     void operator()(cancellation_type_t type)
0630     {
0631       if (!!(type &
0632             (cancellation_type::terminal
0633               | cancellation_type::partial
0634               | cancellation_type::total)))
0635       {
0636         io_uring_service_->cancel_ops_by_key(*io_object_data_, op_type_, this);
0637       }
0638     }
0639 
0640   private:
0641     io_uring_service* io_uring_service_;
0642     io_uring_service::per_io_object_data* io_object_data_;
0643     int op_type_;
0644   };
0645 
0646   // The io_uring_service that performs event demultiplexing for the service.
0647   io_uring_service& io_uring_service_;
0648 
0649   // Cached success value to avoid accessing category singleton.
0650   const boost::system::error_code success_ec_;
0651 };
0652 
0653 } // namespace detail
0654 } // namespace asio
0655 } // namespace boost
0656 
0657 #include <boost/asio/detail/pop_options.hpp>
0658 
0659 #if defined(BOOST_ASIO_HEADER_ONLY)
0660 # include <boost/asio/detail/impl/io_uring_socket_service_base.ipp>
0661 #endif // defined(BOOST_ASIO_HEADER_ONLY)
0662 
0663 #endif // defined(BOOST_ASIO_HAS_IO_URING)
0664 
0665 #endif // BOOST_ASIO_DETAIL_IO_URING_SOCKET_SERVICE_BASE_HPP