File indexing completed on 2025-01-18 09:28:42
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, &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, false, false, &io_ex, 0);
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 BOOST_ASIO_ERROR_LOCATION(ec);
0294 return 0;
0295 }
0296
0297
0298
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
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
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
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
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
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
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
0396 size_t read_some(implementation_type& impl,
0397 const null_buffers&, boost::system::error_code& ec)
0398 {
0399
0400 descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
0401 BOOST_ASIO_ERROR_LOCATION(ec);
0402 return 0;
0403 }
0404
0405
0406
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
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
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
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
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
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
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
0485
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
0496
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
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
0547 reactor& reactor_;
0548
0549
0550 const boost::system::error_code success_ec_;
0551 };
0552
0553 }
0554 }
0555 }
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
0562
0563 #endif
0564
0565
0566
0567
0568 #endif