File indexing completed on 2025-06-30 08:07:57
0001
0002
0003
0004
0005
0006
0007
0008
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
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
0054 typedef int native_handle_type;
0055
0056
0057 class implementation_type
0058 : private boost::asio::detail::noncopyable
0059 {
0060 public:
0061
0062 implementation_type()
0063 : descriptor_(-1),
0064 state_(0)
0065 {
0066 }
0067
0068 private:
0069
0070 friend class reactive_descriptor_service;
0071
0072
0073 int descriptor_;
0074
0075
0076 descriptor_ops::state_type state_;
0077
0078
0079 reactor::per_descriptor_data reactor_data_;
0080 };
0081
0082
0083 BOOST_ASIO_DECL reactive_descriptor_service(execution_context& context);
0084
0085
0086 BOOST_ASIO_DECL void shutdown();
0087
0088
0089 BOOST_ASIO_DECL void construct(implementation_type& impl);
0090
0091
0092 BOOST_ASIO_DECL void move_construct(implementation_type& impl,
0093 implementation_type& other_impl) noexcept;
0094
0095
0096 BOOST_ASIO_DECL void move_assign(implementation_type& impl,
0097 reactive_descriptor_service& other_service,
0098 implementation_type& other_impl);
0099
0100
0101 BOOST_ASIO_DECL void destroy(implementation_type& impl);
0102
0103
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
0109 bool is_open(const implementation_type& impl) const
0110 {
0111 return impl.descriptor_ != -1;
0112 }
0113
0114
0115 BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl,
0116 boost::system::error_code& ec);
0117
0118
0119 native_handle_type native_handle(const implementation_type& impl) const
0120 {
0121 return impl.descriptor_;
0122 }
0123
0124
0125 BOOST_ASIO_DECL native_handle_type release(implementation_type& impl);
0126
0127
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
0136 BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
0137 boost::system::error_code& ec);
0138
0139
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
0151 bool non_blocking(const implementation_type& impl) const
0152 {
0153 return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
0154 }
0155
0156
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
0167 bool native_non_blocking(const implementation_type& impl) const
0168 {
0169 return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
0170 }
0171
0172
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
0182
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
0207
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
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
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
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
0289 size_t write_some(implementation_type& impl,
0290 const null_buffers&, boost::system::error_code& ec)
0291 {
0292
0293 descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
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 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
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
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
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
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
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
0397 size_t read_some(implementation_type& impl,
0398 const null_buffers&, boost::system::error_code& ec)
0399 {
0400
0401 descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
0402 BOOST_ASIO_ERROR_LOCATION(ec);
0403 return 0;
0404 }
0405
0406
0407
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
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
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
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
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
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
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
0487
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
0498
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
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
0551 reactor& reactor_;
0552
0553
0554 const boost::system::error_code success_ec_;
0555 };
0556
0557 }
0558 }
0559 }
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
0566
0567 #endif
0568
0569
0570
0571
0572 #endif