Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 08:07:57

0001 //
0002 // detail/reactive_descriptor_service.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2024 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_REACTIVE_DESCRIPTOR_SERVICE_HPP
0012 #define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_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_WINDOWS) \
0021   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0022   && !defined(__CYGWIN__) \
0023   && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0024 
0025 #include <boost/asio/associated_cancellation_slot.hpp>
0026 #include <boost/asio/associated_immediate_executor.hpp>
0027 #include <boost/asio/buffer.hpp>
0028 #include <boost/asio/cancellation_type.hpp>
0029 #include <boost/asio/execution_context.hpp>
0030 #include <boost/asio/detail/bind_handler.hpp>
0031 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
0032 #include <boost/asio/detail/descriptor_ops.hpp>
0033 #include <boost/asio/detail/descriptor_read_op.hpp>
0034 #include <boost/asio/detail/descriptor_write_op.hpp>
0035 #include <boost/asio/detail/fenced_block.hpp>
0036 #include <boost/asio/detail/memory.hpp>
0037 #include <boost/asio/detail/noncopyable.hpp>
0038 #include <boost/asio/detail/reactive_null_buffers_op.hpp>
0039 #include <boost/asio/detail/reactive_wait_op.hpp>
0040 #include <boost/asio/detail/reactor.hpp>
0041 #include <boost/asio/posix/descriptor_base.hpp>
0042 
0043 #include <boost/asio/detail/push_options.hpp>
0044 
0045 namespace boost {
0046 namespace asio {
0047 namespace detail {
0048 
0049 class reactive_descriptor_service :
0050   public execution_context_service_base<reactive_descriptor_service>
0051 {
0052 public:
0053   // The native type of a descriptor.
0054   typedef int native_handle_type;
0055 
0056   // The implementation type of the descriptor.
0057   class implementation_type
0058     : private boost::asio::detail::noncopyable
0059   {
0060   public:
0061     // Default constructor.
0062     implementation_type()
0063       : descriptor_(-1),
0064         state_(0)
0065     {
0066     }
0067 
0068   private:
0069     // Only this service will have access to the internal values.
0070     friend class reactive_descriptor_service;
0071 
0072     // The native descriptor representation.
0073     int descriptor_;
0074 
0075     // The current state of the descriptor.
0076     descriptor_ops::state_type state_;
0077 
0078     // Per-descriptor data used by the reactor.
0079     reactor::per_descriptor_data reactor_data_;
0080   };
0081 
0082   // Constructor.
0083   BOOST_ASIO_DECL reactive_descriptor_service(execution_context& context);
0084 
0085   // Destroy all user-defined handler objects owned by the service.
0086   BOOST_ASIO_DECL void shutdown();
0087 
0088   // Construct a new descriptor implementation.
0089   BOOST_ASIO_DECL void construct(implementation_type& impl);
0090 
0091   // Move-construct a new descriptor implementation.
0092   BOOST_ASIO_DECL void move_construct(implementation_type& impl,
0093       implementation_type& other_impl) noexcept;
0094 
0095   // Move-assign from another descriptor implementation.
0096   BOOST_ASIO_DECL void move_assign(implementation_type& impl,
0097       reactive_descriptor_service& other_service,
0098       implementation_type& other_impl);
0099 
0100   // Destroy a descriptor implementation.
0101   BOOST_ASIO_DECL void destroy(implementation_type& impl);
0102 
0103   // Assign a native descriptor to a descriptor implementation.
0104   BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl,
0105       const native_handle_type& native_descriptor,
0106       boost::system::error_code& ec);
0107 
0108   // Determine whether the descriptor is open.
0109   bool is_open(const implementation_type& impl) const
0110   {
0111     return impl.descriptor_ != -1;
0112   }
0113 
0114   // Destroy a descriptor implementation.
0115   BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl,
0116       boost::system::error_code& ec);
0117 
0118   // Get the native descriptor representation.
0119   native_handle_type native_handle(const implementation_type& impl) const
0120   {
0121     return impl.descriptor_;
0122   }
0123 
0124   // Release ownership of the native descriptor representation.
0125   BOOST_ASIO_DECL native_handle_type release(implementation_type& impl);
0126 
0127   // Release ownership of the native descriptor representation.
0128   native_handle_type release(implementation_type& impl,
0129       boost::system::error_code& ec)
0130   {
0131     ec = success_ec_;
0132     return release(impl);
0133   }
0134 
0135   // Cancel all operations associated with the descriptor.
0136   BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
0137       boost::system::error_code& ec);
0138 
0139   // Perform an IO control command on the descriptor.
0140   template <typename IO_Control_Command>
0141   boost::system::error_code io_control(implementation_type& impl,
0142       IO_Control_Command& command, boost::system::error_code& ec)
0143   {
0144     descriptor_ops::ioctl(impl.descriptor_, impl.state_,
0145         command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
0146     BOOST_ASIO_ERROR_LOCATION(ec);
0147     return ec;
0148   }
0149 
0150   // Gets the non-blocking mode of the descriptor.
0151   bool non_blocking(const implementation_type& impl) const
0152   {
0153     return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
0154   }
0155 
0156   // Sets the non-blocking mode of the descriptor.
0157   boost::system::error_code non_blocking(implementation_type& impl,
0158       bool mode, boost::system::error_code& ec)
0159   {
0160     descriptor_ops::set_user_non_blocking(
0161         impl.descriptor_, impl.state_, mode, ec);
0162     BOOST_ASIO_ERROR_LOCATION(ec);
0163     return ec;
0164   }
0165 
0166   // Gets the non-blocking mode of the native descriptor implementation.
0167   bool native_non_blocking(const implementation_type& impl) const
0168   {
0169     return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
0170   }
0171 
0172   // Sets the non-blocking mode of the native descriptor implementation.
0173   boost::system::error_code native_non_blocking(implementation_type& impl,
0174       bool mode, boost::system::error_code& ec)
0175   {
0176     descriptor_ops::set_internal_non_blocking(
0177         impl.descriptor_, impl.state_, mode, ec);
0178     return ec;
0179   }
0180 
0181   // Wait for the descriptor to become ready to read, ready to write, or to have
0182   // pending error conditions.
0183   boost::system::error_code wait(implementation_type& impl,
0184       posix::descriptor_base::wait_type w, boost::system::error_code& ec)
0185   {
0186     switch (w)
0187     {
0188     case posix::descriptor_base::wait_read:
0189       descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
0190       break;
0191     case posix::descriptor_base::wait_write:
0192       descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
0193       break;
0194     case posix::descriptor_base::wait_error:
0195       descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);
0196       break;
0197     default:
0198       ec = boost::asio::error::invalid_argument;
0199       break;
0200     }
0201 
0202     BOOST_ASIO_ERROR_LOCATION(ec);
0203     return ec;
0204   }
0205 
0206   // Asynchronously wait for the descriptor to become ready to read, ready to
0207   // write, or to have pending error conditions.
0208   template <typename Handler, typename IoExecutor>
0209   void async_wait(implementation_type& impl,
0210       posix::descriptor_base::wait_type w,
0211       Handler& handler, const IoExecutor& io_ex)
0212   {
0213     bool is_continuation =
0214       boost_asio_handler_cont_helpers::is_continuation(handler);
0215 
0216     associated_cancellation_slot_t<Handler> slot
0217       = boost::asio::get_associated_cancellation_slot(handler);
0218 
0219     // Allocate and construct an operation to wrap the handler.
0220     typedef reactive_wait_op<Handler, IoExecutor> op;
0221     typename op::ptr p = { boost::asio::detail::addressof(handler),
0222       op::ptr::allocate(handler), 0 };
0223     p.p = new (p.v) op(success_ec_, handler, io_ex);
0224 
0225     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0226           &impl, impl.descriptor_, "async_wait"));
0227 
0228     int op_type;
0229     switch (w)
0230     {
0231     case posix::descriptor_base::wait_read:
0232       op_type = reactor::read_op;
0233       break;
0234     case posix::descriptor_base::wait_write:
0235       op_type = reactor::write_op;
0236       break;
0237     case posix::descriptor_base::wait_error:
0238       op_type = reactor::except_op;
0239       break;
0240     default:
0241       p.p->ec_ = boost::asio::error::invalid_argument;
0242       start_op(impl, reactor::read_op, p.p,
0243           is_continuation, false, true, false, &io_ex, 0);
0244       p.v = p.p = 0;
0245       return;
0246     }
0247 
0248     // Optionally register for per-operation cancellation.
0249     if (slot.is_connected())
0250     {
0251       p.p->cancellation_key_ =
0252         &slot.template emplace<reactor_op_cancellation>(
0253             &reactor_, &impl.reactor_data_, impl.descriptor_, op_type);
0254     }
0255 
0256     start_op(impl, op_type, p.p, is_continuation,
0257         false, false, false, &io_ex, 0);
0258     p.v = p.p = 0;
0259   }
0260 
0261   // Write some data to the descriptor.
0262   template <typename ConstBufferSequence>
0263   size_t write_some(implementation_type& impl,
0264       const ConstBufferSequence& buffers, boost::system::error_code& ec)
0265   {
0266     typedef buffer_sequence_adapter<boost::asio::const_buffer,
0267         ConstBufferSequence> bufs_type;
0268 
0269     size_t n;
0270     if (bufs_type::is_single_buffer)
0271     {
0272       n = descriptor_ops::sync_write1(impl.descriptor_,
0273           impl.state_, bufs_type::first(buffers).data(),
0274           bufs_type::first(buffers).size(), ec);
0275     }
0276     else
0277     {
0278       bufs_type bufs(buffers);
0279 
0280       n = descriptor_ops::sync_write(impl.descriptor_, impl.state_,
0281           bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
0282     }
0283 
0284     BOOST_ASIO_ERROR_LOCATION(ec);
0285     return n;
0286   }
0287 
0288   // Wait until data can be written without blocking.
0289   size_t write_some(implementation_type& impl,
0290       const null_buffers&, boost::system::error_code& ec)
0291   {
0292     // Wait for descriptor to become ready.
0293     descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
0294     BOOST_ASIO_ERROR_LOCATION(ec);
0295     return 0;
0296   }
0297 
0298   // Start an asynchronous write. The data being sent must be valid for the
0299   // lifetime of the asynchronous operation.
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     // Allocate and construct an operation to wrap the handler.
0312     typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op;
0313     typename op::ptr p = { boost::asio::detail::addressof(handler),
0314       op::ptr::allocate(handler), 0 };
0315     p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
0316 
0317     // Optionally register for per-operation cancellation.
0318     if (slot.is_connected())
0319     {
0320       p.p->cancellation_key_ =
0321         &slot.template emplace<reactor_op_cancellation>(
0322             &reactor_, &impl.reactor_data_,
0323             impl.descriptor_, reactor::write_op);
0324     }
0325 
0326     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0327           &impl, impl.descriptor_, "async_write_some"));
0328 
0329     start_op(impl, reactor::write_op, p.p, is_continuation, true,
0330         buffer_sequence_adapter<boost::asio::const_buffer,
0331           ConstBufferSequence>::all_empty(buffers), true, &io_ex, 0);
0332     p.v = p.p = 0;
0333   }
0334 
0335   // Start an asynchronous wait until data can be written without blocking.
0336   template <typename Handler, typename IoExecutor>
0337   void async_write_some(implementation_type& impl,
0338       const null_buffers&, Handler& handler, const IoExecutor& io_ex)
0339   {
0340     bool is_continuation =
0341       boost_asio_handler_cont_helpers::is_continuation(handler);
0342 
0343     associated_cancellation_slot_t<Handler> slot
0344       = boost::asio::get_associated_cancellation_slot(handler);
0345 
0346     // Allocate and construct an operation to wrap the handler.
0347     typedef reactive_null_buffers_op<Handler, IoExecutor> op;
0348     typename op::ptr p = { boost::asio::detail::addressof(handler),
0349       op::ptr::allocate(handler), 0 };
0350     p.p = new (p.v) op(success_ec_, handler, io_ex);
0351 
0352     // Optionally register for per-operation cancellation.
0353     if (slot.is_connected())
0354     {
0355       p.p->cancellation_key_ =
0356         &slot.template emplace<reactor_op_cancellation>(
0357             &reactor_, &impl.reactor_data_,
0358             impl.descriptor_, reactor::write_op);
0359     }
0360 
0361     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0362           &impl, impl.descriptor_, "async_write_some(null_buffers)"));
0363 
0364     start_op(impl, reactor::write_op, p.p,
0365         is_continuation, false, false, false, &io_ex, 0);
0366     p.v = p.p = 0;
0367   }
0368 
0369   // Read some data from the stream. Returns the number of bytes read.
0370   template <typename MutableBufferSequence>
0371   size_t read_some(implementation_type& impl,
0372       const MutableBufferSequence& buffers, boost::system::error_code& ec)
0373   {
0374     typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
0375         MutableBufferSequence> bufs_type;
0376 
0377     size_t n;
0378     if (bufs_type::is_single_buffer)
0379     {
0380       n = descriptor_ops::sync_read1(impl.descriptor_,
0381           impl.state_, 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_read(impl.descriptor_, impl.state_,
0389           bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
0390     }
0391 
0392     BOOST_ASIO_ERROR_LOCATION(ec);
0393     return n;
0394   }
0395 
0396   // Wait until data can be read without blocking.
0397   size_t read_some(implementation_type& impl,
0398       const null_buffers&, boost::system::error_code& ec)
0399   {
0400     // Wait for descriptor to become ready.
0401     descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
0402     BOOST_ASIO_ERROR_LOCATION(ec);
0403     return 0;
0404   }
0405 
0406   // Start an asynchronous read. The buffer for the data being read must be
0407   // valid for the lifetime of the asynchronous operation.
0408   template <typename MutableBufferSequence,
0409       typename Handler, typename IoExecutor>
0410   void async_read_some(implementation_type& impl,
0411       const MutableBufferSequence& buffers,
0412       Handler& handler, const IoExecutor& io_ex)
0413   {
0414     bool is_continuation =
0415       boost_asio_handler_cont_helpers::is_continuation(handler);
0416 
0417     associated_cancellation_slot_t<Handler> slot
0418       = boost::asio::get_associated_cancellation_slot(handler);
0419 
0420     // Allocate and construct an operation to wrap the handler.
0421     typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op;
0422     typename op::ptr p = { boost::asio::detail::addressof(handler),
0423       op::ptr::allocate(handler), 0 };
0424     p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
0425 
0426     // Optionally register for per-operation cancellation.
0427     if (slot.is_connected())
0428     {
0429       p.p->cancellation_key_ =
0430         &slot.template emplace<reactor_op_cancellation>(
0431             &reactor_, &impl.reactor_data_,
0432             impl.descriptor_, reactor::read_op);
0433     }
0434 
0435     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0436           &impl, impl.descriptor_, "async_read_some"));
0437 
0438     start_op(impl, reactor::read_op, p.p, is_continuation, true,
0439         buffer_sequence_adapter<boost::asio::mutable_buffer,
0440           MutableBufferSequence>::all_empty(buffers), true, &io_ex, 0);
0441     p.v = p.p = 0;
0442   }
0443 
0444   // Wait until data can be read without blocking.
0445   template <typename Handler, typename IoExecutor>
0446   void async_read_some(implementation_type& impl,
0447       const null_buffers&, Handler& handler, const IoExecutor& io_ex)
0448   {
0449     bool is_continuation =
0450       boost_asio_handler_cont_helpers::is_continuation(handler);
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 reactive_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_, 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<reactor_op_cancellation>(
0466             &reactor_, &impl.reactor_data_,
0467             impl.descriptor_, reactor::read_op);
0468     }
0469 
0470     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0471           &impl, impl.descriptor_, "async_read_some(null_buffers)"));
0472 
0473     start_op(impl, reactor::read_op, p.p,
0474         is_continuation, false, false, false, &io_ex, 0);
0475     p.v = p.p = 0;
0476   }
0477 
0478 private:
0479   // Start the asynchronous operation.
0480   BOOST_ASIO_DECL void do_start_op(implementation_type& impl,
0481       int op_type, reactor_op* op, bool is_continuation,
0482       bool allow_speculative, bool noop, bool needs_non_blocking,
0483       void (*on_immediate)(operation* op, bool, const void*),
0484       const void* immediate_arg);
0485 
0486   // Start the asynchronous operation for handlers that are specialised for
0487   // immediate completion.
0488   template <typename Op>
0489   void start_op(implementation_type& impl, int op_type, Op* op,
0490       bool is_continuation, bool allow_speculative, bool noop,
0491       bool needs_non_blocking, const void* io_ex, ...)
0492   {
0493     return do_start_op(impl, op_type, op, is_continuation, allow_speculative,
0494         noop, needs_non_blocking, &Op::do_immediate, io_ex);
0495   }
0496 
0497   // Start the asynchronous operation for handlers that are not specialised for
0498   // immediate completion.
0499   template <typename Op>
0500   void start_op(implementation_type& impl, int op_type,
0501       Op* op, bool is_continuation, bool allow_speculative,
0502       bool noop, bool needs_non_blocking, const void*,
0503       enable_if_t<
0504         is_same<
0505           typename associated_immediate_executor<
0506             typename Op::handler_type,
0507             typename Op::io_executor_type
0508           >::asio_associated_immediate_executor_is_unspecialised,
0509           void
0510         >::value
0511       >*)
0512   {
0513     return do_start_op(impl, op_type, op, is_continuation,
0514         allow_speculative, noop, needs_non_blocking,
0515         &reactor::call_post_immediate_completion, &reactor_);
0516   }
0517 
0518   // Helper class used to implement per-operation cancellation
0519   class reactor_op_cancellation
0520   {
0521   public:
0522     reactor_op_cancellation(reactor* r,
0523         reactor::per_descriptor_data* p, int d, int o)
0524       : reactor_(r),
0525         reactor_data_(p),
0526         descriptor_(d),
0527         op_type_(o)
0528     {
0529     }
0530 
0531     void operator()(cancellation_type_t type)
0532     {
0533       if (!!(type &
0534             (cancellation_type::terminal
0535               | cancellation_type::partial
0536               | cancellation_type::total)))
0537       {
0538         reactor_->cancel_ops_by_key(descriptor_,
0539             *reactor_data_, op_type_, this);
0540       }
0541     }
0542 
0543   private:
0544     reactor* reactor_;
0545     reactor::per_descriptor_data* reactor_data_;
0546     int descriptor_;
0547     int op_type_;
0548   };
0549 
0550   // The selector that performs event demultiplexing for the service.
0551   reactor& reactor_;
0552 
0553   // Cached success value to avoid accessing category singleton.
0554   const boost::system::error_code success_ec_;
0555 };
0556 
0557 } // namespace detail
0558 } // namespace asio
0559 } // namespace boost
0560 
0561 #include <boost/asio/detail/pop_options.hpp>
0562 
0563 #if defined(BOOST_ASIO_HEADER_ONLY)
0564 # include <boost/asio/detail/impl/reactive_descriptor_service.ipp>
0565 #endif // defined(BOOST_ASIO_HEADER_ONLY)
0566 
0567 #endif // !defined(BOOST_ASIO_WINDOWS)
0568        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0569        //   && !defined(__CYGWIN__)
0570        //   && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0571 
0572 #endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP