diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 6f030f00..49e03a36 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -269,6 +269,16 @@ public: p.p = new (p.v) op(success_ec_, impl.socket_, buffers, destination, flags, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to")); @@ -291,6 +301,16 @@ public: op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to(null_buffers)")); @@ -368,6 +388,16 @@ public: p.p = new (p.v) op(success_ec_, impl.socket_, protocol, buffers, sender_endpoint, flags, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_from")); @@ -393,6 +423,16 @@ public: op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_from(null_buffers)")); @@ -452,6 +492,16 @@ public: p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, peer, impl.protocol_, peer_endpoint, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected() && !peer.is_open()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); @@ -478,6 +528,16 @@ public: p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_, impl.state_, impl.protocol_, peer_endpoint, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); @@ -510,6 +570,16 @@ public: op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::connect_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_connect")); diff --git a/include/boost/asio/detail/reactive_socket_service_base.hpp b/include/boost/asio/detail/reactive_socket_service_base.hpp index fbe5dc39..33ae6f51 100644 --- a/include/boost/asio/detail/reactive_socket_service_base.hpp +++ b/include/boost/asio/detail/reactive_socket_service_base.hpp @@ -20,6 +20,7 @@ #if !defined(BOOST_ASIO_HAS_IOCP) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#include #include #include #include @@ -228,6 +229,16 @@ public: return; } + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, op_type); + } + start_op(impl, op_type, p.p, is_continuation, false, false); p.v = p.p = 0; } @@ -283,6 +294,16 @@ public: p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, buffers, flags, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send")); @@ -307,6 +328,16 @@ public: op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send(null_buffers)")); @@ -366,6 +397,16 @@ public: p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, buffers, flags, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive")); @@ -395,6 +436,16 @@ public: op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive(null_buffers)")); @@ -455,6 +506,16 @@ public: p.p = new (p.v) op(success_ec_, impl.socket_, buffers, in_flags, out_flags, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags")); @@ -482,6 +543,16 @@ public: op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, handler, io_ex); + // Optionally register for per-operation cancellation. + typename associated_cancellation_slot::type slot + = boost::asio::get_associated_cancellation_slot(handler); + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); @@ -520,6 +591,31 @@ protected: reactor_op* op, bool is_continuation, const socket_addr_type* addr, size_t addrlen); + // Helper class used to implement per-operation cancellation + class reactor_op_cancellation + { + public: + reactor_op_cancellation(reactor* r, + reactor::per_descriptor_data* p, int d, int o) + : reactor_(r), + reactor_data_(p), + descriptor_(d), + op_type_(o) + { + } + + void operator()() + { + reactor_->cancel_ops_by_key(descriptor_, *reactor_data_, op_type_, this); + } + + private: + reactor* reactor_; + reactor::per_descriptor_data* reactor_data_; + int descriptor_; + int op_type_; + }; + // The selector that performs event demultiplexing for the service. reactor& reactor_;