Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // detail/reactive_descriptor_service.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_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, &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, false, false, &io_ex, 0);
0257     p.v = p.p = 0;
0258   }
0259 
0260   // Write some data to the descriptor.
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   // Wait until data can be written without blocking.
0288   size_t write_some(implementation_type& impl,
0289       const null_buffers&, boost::system::error_code& ec)
0290   {
0291     // Wait for descriptor to become ready.
0292     descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
0293     BOOST_ASIO_ERROR_LOCATION(ec);
0294     return 0;
0295   }
0296 
0297   // Start an asynchronous write. The data being sent must be valid for the
0298   // lifetime of the asynchronous operation.
0299   template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
0300   void async_write_some(implementation_type& impl,
0301       const ConstBufferSequence& buffers, Handler& handler,
0302       const IoExecutor& io_ex)
0303   {
0304     bool is_continuation =
0305       boost_asio_handler_cont_helpers::is_continuation(handler);
0306 
0307     associated_cancellation_slot_t<Handler> slot
0308       = boost::asio::get_associated_cancellation_slot(handler);
0309 
0310     // Allocate and construct an operation to wrap the handler.
0311     typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op;
0312     typename op::ptr p = { boost::asio::detail::addressof(handler),
0313       op::ptr::allocate(handler), 0 };
0314     p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
0315 
0316     // Optionally register for per-operation cancellation.
0317     if (slot.is_connected())
0318     {
0319       p.p->cancellation_key_ =
0320         &slot.template emplace<reactor_op_cancellation>(
0321             &reactor_, &impl.reactor_data_,
0322             impl.descriptor_, reactor::write_op);
0323     }
0324 
0325     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0326           &impl, impl.descriptor_, "async_write_some"));
0327 
0328     start_op(impl, reactor::write_op, p.p, is_continuation, true,
0329         buffer_sequence_adapter<boost::asio::const_buffer,
0330           ConstBufferSequence>::all_empty(buffers), &io_ex, 0);
0331     p.v = p.p = 0;
0332   }
0333 
0334   // Start an asynchronous wait until data can be written without blocking.
0335   template <typename Handler, typename IoExecutor>
0336   void async_write_some(implementation_type& impl,
0337       const null_buffers&, Handler& handler, const IoExecutor& io_ex)
0338   {
0339     bool is_continuation =
0340       boost_asio_handler_cont_helpers::is_continuation(handler);
0341 
0342     associated_cancellation_slot_t<Handler> slot
0343       = boost::asio::get_associated_cancellation_slot(handler);
0344 
0345     // Allocate and construct an operation to wrap the handler.
0346     typedef reactive_null_buffers_op<Handler, IoExecutor> op;
0347     typename op::ptr p = { boost::asio::detail::addressof(handler),
0348       op::ptr::allocate(handler), 0 };
0349     p.p = new (p.v) op(success_ec_, handler, io_ex);
0350 
0351     // Optionally register for per-operation cancellation.
0352     if (slot.is_connected())
0353     {
0354       p.p->cancellation_key_ =
0355         &slot.template emplace<reactor_op_cancellation>(
0356             &reactor_, &impl.reactor_data_,
0357             impl.descriptor_, reactor::write_op);
0358     }
0359 
0360     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0361           &impl, impl.descriptor_, "async_write_some(null_buffers)"));
0362 
0363     start_op(impl, reactor::write_op, p.p,
0364         is_continuation, false, false, &io_ex, 0);
0365     p.v = p.p = 0;
0366   }
0367 
0368   // Read some data from the stream. Returns the number of bytes read.
0369   template <typename MutableBufferSequence>
0370   size_t read_some(implementation_type& impl,
0371       const MutableBufferSequence& buffers, boost::system::error_code& ec)
0372   {
0373     typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
0374         MutableBufferSequence> bufs_type;
0375 
0376     size_t n;
0377     if (bufs_type::is_single_buffer)
0378     {
0379       n = descriptor_ops::sync_read1(impl.descriptor_,
0380           impl.state_, bufs_type::first(buffers).data(),
0381           bufs_type::first(buffers).size(), ec);
0382     }
0383     else
0384     {
0385       bufs_type bufs(buffers);
0386 
0387       n = descriptor_ops::sync_read(impl.descriptor_, impl.state_,
0388           bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
0389     }
0390 
0391     BOOST_ASIO_ERROR_LOCATION(ec);
0392     return n;
0393   }
0394 
0395   // Wait until data can be read without blocking.
0396   size_t read_some(implementation_type& impl,
0397       const null_buffers&, boost::system::error_code& ec)
0398   {
0399     // Wait for descriptor to become ready.
0400     descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
0401     BOOST_ASIO_ERROR_LOCATION(ec);
0402     return 0;
0403   }
0404 
0405   // Start an asynchronous read. The buffer for the data being read must be
0406   // valid for the lifetime of the asynchronous operation.
0407   template <typename MutableBufferSequence,
0408       typename Handler, typename IoExecutor>
0409   void async_read_some(implementation_type& impl,
0410       const MutableBufferSequence& buffers,
0411       Handler& handler, const IoExecutor& io_ex)
0412   {
0413     bool is_continuation =
0414       boost_asio_handler_cont_helpers::is_continuation(handler);
0415 
0416     associated_cancellation_slot_t<Handler> slot
0417       = boost::asio::get_associated_cancellation_slot(handler);
0418 
0419     // Allocate and construct an operation to wrap the handler.
0420     typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op;
0421     typename op::ptr p = { boost::asio::detail::addressof(handler),
0422       op::ptr::allocate(handler), 0 };
0423     p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
0424 
0425     // Optionally register for per-operation cancellation.
0426     if (slot.is_connected())
0427     {
0428       p.p->cancellation_key_ =
0429         &slot.template emplace<reactor_op_cancellation>(
0430             &reactor_, &impl.reactor_data_,
0431             impl.descriptor_, reactor::read_op);
0432     }
0433 
0434     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0435           &impl, impl.descriptor_, "async_read_some"));
0436 
0437     start_op(impl, reactor::read_op, p.p, is_continuation, true,
0438         buffer_sequence_adapter<boost::asio::mutable_buffer,
0439           MutableBufferSequence>::all_empty(buffers), &io_ex, 0);
0440     p.v = p.p = 0;
0441   }
0442 
0443   // Wait until data can be read without blocking.
0444   template <typename Handler, typename IoExecutor>
0445   void async_read_some(implementation_type& impl,
0446       const null_buffers&, Handler& handler, const IoExecutor& io_ex)
0447   {
0448     bool is_continuation =
0449       boost_asio_handler_cont_helpers::is_continuation(handler);
0450 
0451     associated_cancellation_slot_t<Handler> slot
0452       = boost::asio::get_associated_cancellation_slot(handler);
0453 
0454     // Allocate and construct an operation to wrap the handler.
0455     typedef reactive_null_buffers_op<Handler, IoExecutor> op;
0456     typename op::ptr p = { boost::asio::detail::addressof(handler),
0457       op::ptr::allocate(handler), 0 };
0458     p.p = new (p.v) op(success_ec_, handler, io_ex);
0459 
0460     // Optionally register for per-operation cancellation.
0461     if (slot.is_connected())
0462     {
0463       p.p->cancellation_key_ =
0464         &slot.template emplace<reactor_op_cancellation>(
0465             &reactor_, &impl.reactor_data_,
0466             impl.descriptor_, reactor::read_op);
0467     }
0468 
0469     BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
0470           &impl, impl.descriptor_, "async_read_some(null_buffers)"));
0471 
0472     start_op(impl, reactor::read_op, p.p,
0473         is_continuation, false, false, &io_ex, 0);
0474     p.v = p.p = 0;
0475   }
0476 
0477 private:
0478   // Start the asynchronous operation.
0479   BOOST_ASIO_DECL void do_start_op(implementation_type& impl, int op_type,
0480       reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop,
0481       void (*on_immediate)(operation* op, bool, const void*),
0482       const void* immediate_arg);
0483 
0484   // Start the asynchronous operation for handlers that are specialised for
0485   // immediate completion.
0486   template <typename Op>
0487   void start_op(implementation_type& impl, int op_type, Op* op,
0488       bool is_continuation, bool is_non_blocking, bool noop,
0489       const void* io_ex, ...)
0490   {
0491     return do_start_op(impl, op_type, op, is_continuation,
0492         is_non_blocking, noop, &Op::do_immediate, io_ex);
0493   }
0494 
0495   // Start the asynchronous operation for handlers that are not specialised for
0496   // immediate completion.
0497   template <typename Op>
0498   void start_op(implementation_type& impl, int op_type, Op* op,
0499       bool is_continuation, bool is_non_blocking, bool noop, const void*,
0500       enable_if_t<
0501         is_same<
0502           typename associated_immediate_executor<
0503             typename Op::handler_type,
0504             typename Op::io_executor_type
0505           >::asio_associated_immediate_executor_is_unspecialised,
0506           void
0507         >::value
0508       >*)
0509   {
0510     return do_start_op(impl, op_type, op, is_continuation, is_non_blocking,
0511         noop, &reactor::call_post_immediate_completion, &reactor_);
0512   }
0513 
0514   // Helper class used to implement per-operation cancellation
0515   class reactor_op_cancellation
0516   {
0517   public:
0518     reactor_op_cancellation(reactor* r,
0519         reactor::per_descriptor_data* p, int d, int o)
0520       : reactor_(r),
0521         reactor_data_(p),
0522         descriptor_(d),
0523         op_type_(o)
0524     {
0525     }
0526 
0527     void operator()(cancellation_type_t type)
0528     {
0529       if (!!(type &
0530             (cancellation_type::terminal
0531               | cancellation_type::partial
0532               | cancellation_type::total)))
0533       {
0534         reactor_->cancel_ops_by_key(descriptor_,
0535             *reactor_data_, op_type_, this);
0536       }
0537     }
0538 
0539   private:
0540     reactor* reactor_;
0541     reactor::per_descriptor_data* reactor_data_;
0542     int descriptor_;
0543     int op_type_;
0544   };
0545 
0546   // The selector that performs event demultiplexing for the service.
0547   reactor& reactor_;
0548 
0549   // Cached success value to avoid accessing category singleton.
0550   const boost::system::error_code success_ec_;
0551 };
0552 
0553 } // namespace detail
0554 } // namespace asio
0555 } // namespace boost
0556 
0557 #include <boost/asio/detail/pop_options.hpp>
0558 
0559 #if defined(BOOST_ASIO_HEADER_ONLY)
0560 # include <boost/asio/detail/impl/reactive_descriptor_service.ipp>
0561 #endif // defined(BOOST_ASIO_HEADER_ONLY)
0562 
0563 #endif // !defined(BOOST_ASIO_WINDOWS)
0564        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0565        //   && !defined(__CYGWIN__)
0566        //   && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0567 
0568 #endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP