diff options
Diffstat (limited to '3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp')
-rw-r--r-- | 3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp | 274 |
1 files changed, 178 insertions, 96 deletions
diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp index 9040f7c9b96..faeaffa4c36 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -21,13 +21,12 @@ #include <cstring> #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/operation.hpp" @@ -51,7 +50,7 @@ namespace detail { template <typename Protocol> class win_iocp_socket_service : - public service_base<win_iocp_socket_service<Protocol> >, + public execution_context_service_base<win_iocp_socket_service<Protocol>>, public win_iocp_socket_service_base { public: @@ -129,9 +128,10 @@ public: }; // Constructor. - win_iocp_socket_service(asio::io_context& io_context) - : service_base<win_iocp_socket_service<Protocol> >(io_context), - win_iocp_socket_service_base(io_context) + win_iocp_socket_service(execution_context& context) + : execution_context_service_base< + win_iocp_socket_service<Protocol>>(context), + win_iocp_socket_service_base(context) { } @@ -143,7 +143,7 @@ public: // Move-construct a new socket implementation. void move_construct(implementation_type& impl, - implementation_type& other_impl) + implementation_type& other_impl) noexcept { this->base_move_construct(impl, other_impl); @@ -177,6 +177,7 @@ public: // Move-construct a new socket implementation from another protocol type. template <typename Protocol1> void converting_move_construct(implementation_type& impl, + win_iocp_socket_service<Protocol1>&, typename win_iocp_socket_service< Protocol1>::implementation_type& other_impl) { @@ -203,6 +204,8 @@ public: impl.have_remote_endpoint_ = false; impl.remote_endpoint_ = endpoint_type(); } + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -217,6 +220,8 @@ public: impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); impl.remote_endpoint_ = native_socket.remote_endpoint(); } + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -233,6 +238,8 @@ public: const endpoint_type& endpoint, asio::error_code& ec) { socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -244,6 +251,8 @@ public: socket_ops::setsockopt(impl.socket_, impl.state_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -258,6 +267,8 @@ public: option.data(impl.protocol_), &size, ec); if (!ec) option.resize(impl.protocol_, size); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -268,7 +279,10 @@ public: endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + { + ASIO_ERROR_LOCATION(ec); return endpoint_type(); + } endpoint.resize(addr_len); return endpoint; } @@ -281,7 +295,10 @@ public: std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, impl.have_remote_endpoint_, ec)) + { + ASIO_ERROR_LOCATION(ec); return endpoint_type(); + } endpoint.resize(addr_len); return endpoint; } @@ -304,9 +321,12 @@ public: buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); - return socket_ops::sync_sendto(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, + size_t n = socket_ops::sync_sendto(impl.socket_, + impl.state_, bufs.buffers(), bufs.count(), flags, destination.data(), destination.size(), ec); + + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be sent without blocking. @@ -316,50 +336,61 @@ public: { // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); - + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, - socket_base::message_flags flags, Handler& handler) + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; + typedef win_iocp_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + operation* o = p.p = new (p.v) op( + impl.cancel_token_, buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_send_to")); buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.socket_, o); + start_send_to_op(impl, bufs.buffers(), bufs.count(), destination.data(), static_cast<int>(destination.size()), - flags, p.p); + flags, o); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send_to(implementation_type& impl, const null_buffers&, - const endpoint_type&, socket_base::message_flags, Handler& handler) + const endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. - typedef win_iocp_null_buffers_op<Handler> op; + typedef win_iocp_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + reactor_op* o = p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_send_to(null_buffers)")); - start_reactor_op(impl, select_reactor::write_op, p.p); + start_reactor_op(impl, select_reactor::write_op, o); p.v = p.p = 0; } @@ -375,14 +406,15 @@ public: MutableBufferSequence> bufs(buffers); std::size_t addr_len = sender_endpoint.capacity(); - std::size_t bytes_recvd = socket_ops::sync_recvfrom( - impl.socket_, impl.state_, bufs.buffers(), bufs.count(), - flags, sender_endpoint.data(), &addr_len, ec); + std::size_t n = socket_ops::sync_recvfrom(impl.socket_, + impl.state_, bufs.buffers(), bufs.count(), flags, + sender_endpoint.data(), &addr_len, ec); if (!ec) sender_endpoint.resize(addr_len); - return bytes_recvd; + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be received without blocking. @@ -396,55 +428,85 @@ public: // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endp, - socket_base::message_flags flags, Handler& handler) + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_recvfrom_op< - MutableBufferSequence, endpoint_type, Handler> op; + typedef win_iocp_socket_recvfrom_op<MutableBufferSequence, + endpoint_type, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); + operation* o = p.p = new (p.v) op(sender_endp, + impl.cancel_token_, buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive_from")); buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.socket_, o); + start_receive_from_op(impl, bufs.buffers(), bufs.count(), - sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + sender_endp.data(), flags, &p.p->endpoint_size(), o); p.v = p.p = 0; } // Wait until data can be received without blocking. - template <typename Handler> - void async_receive_from(implementation_type& impl, - const null_buffers&, endpoint_type& sender_endpoint, - socket_base::message_flags flags, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_null_buffers_op<Handler> op; + typedef win_iocp_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive_from(null_buffers)")); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); - start_null_buffers_receive_op(impl, flags, p.p); + // Optionally register for per-operation cancellation. + operation* iocp_op = p.p; + if (slot.is_connected()) + { + p.p->cancellation_key_ = iocp_op = + &slot.template emplace<reactor_op_cancellation>( + impl.socket_, iocp_op); + } + + int op_type = start_null_buffers_receive_op(impl, flags, p.p, iocp_op); p.v = p.p = 0; + + // Update cancellation method if the reactor was used. + if (slot.is_connected() && op_type != -1) + { + static_cast<reactor_op_cancellation*>(iocp_op)->use_reactor( + &get_reactor(), &impl.reactor_data_, op_type); + } } // Accept a new connection. @@ -456,6 +518,7 @@ public: if (peer.is_open()) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -474,90 +537,87 @@ public: new_socket.release(); } + ASIO_ERROR_LOCATION(ec); return ec; } -#if defined(ASIO_HAS_MOVE) - // Accept a new connection. - typename Protocol::socket accept(implementation_type& impl, - io_context* peer_io_context, endpoint_type* peer_endpoint, - asio::error_code& ec) - { - typename Protocol::socket peer( - peer_io_context ? *peer_io_context : io_context_); - - std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; - socket_holder new_socket(socket_ops::sync_accept(impl.socket_, - impl.state_, peer_endpoint ? peer_endpoint->data() : 0, - peer_endpoint ? &addr_len : 0, ec)); - - // On success, assign new connection to peer socket object. - if (new_socket.get() != invalid_socket) - { - if (peer_endpoint) - peer_endpoint->resize(addr_len); - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - } - - return peer; - } -#endif // defined(ASIO_HAS_MOVE) - // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. - template <typename Socket, typename Handler> + template <typename Socket, typename Handler, typename IoExecutor> void async_accept(implementation_type& impl, Socket& peer, - endpoint_type* peer_endpoint, Handler& handler) + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op; + typedef win_iocp_socket_accept_op<Socket, + protocol_type, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; bool enable_connection_aborted = (impl.state_ & socket_ops::enable_connection_aborted) != 0; - p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, - peer_endpoint, enable_connection_aborted, handler); + operation* o = p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, + peer_endpoint, enable_connection_aborted, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_accept")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + accept_op_cancellation* c = + &slot.template emplace<accept_op_cancellation>(impl.socket_, o); + p.p->enable_cancellation(c->get_cancel_requested(), c); + o = c; + } + start_accept_op(impl, peer.is_open(), p.p->new_socket(), impl.protocol_.family(), impl.protocol_.type(), impl.protocol_.protocol(), p.p->output_buffer(), - p.p->address_length(), p.p); + p.p->address_length(), o); p.v = p.p = 0; } -#if defined(ASIO_HAS_MOVE) // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. - template <typename Handler> - void async_accept(implementation_type& impl, - asio::io_context* peer_io_context, - endpoint_type* peer_endpoint, Handler& handler) + template <typename PeerIoExecutor, typename Handler, typename IoExecutor> + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_move_accept_op<protocol_type, Handler> op; + typedef win_iocp_socket_move_accept_op< + protocol_type, PeerIoExecutor, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; bool enable_connection_aborted = (impl.state_ & socket_ops::enable_connection_aborted) != 0; - p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, - peer_io_context ? *peer_io_context : io_context_, - peer_endpoint, enable_connection_aborted, handler); + operation* o = p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, + peer_io_ex, peer_endpoint, enable_connection_aborted, + handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_accept")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + accept_op_cancellation* c = + &slot.template emplace<accept_op_cancellation>(impl.socket_, o); + p.p->enable_cancellation(c->get_cancel_requested(), c); + o = c; + } + start_accept_op(impl, false, p.p->new_socket(), impl.protocol_.family(), impl.protocol_.type(), impl.protocol_.protocol(), p.p->output_buffer(), - p.p->address_length(), p.p); + p.p->address_length(), o); p.v = p.p = 0; } -#endif // defined(ASIO_HAS_MOVE) // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, @@ -565,26 +625,48 @@ public: { socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); + ASIO_ERROR_LOCATION(ec); return ec; } // Start an asynchronous connect. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, Handler& handler) + const endpoint_type& peer_endpoint, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_connect_op<Handler> op; + typedef win_iocp_socket_connect_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, handler); + p.p = new (p.v) op(impl.socket_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_connect")); - start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(), - peer_endpoint.data(), static_cast<int>(peer_endpoint.size()), p.p); + // Optionally register for per-operation cancellation. + operation* iocp_op = p.p; + if (slot.is_connected()) + { + p.p->cancellation_key_ = iocp_op = + &slot.template emplace<reactor_op_cancellation>( + impl.socket_, iocp_op); + } + + int op_type = start_connect_op(impl, impl.protocol_.family(), + impl.protocol_.type(), peer_endpoint.data(), + static_cast<int>(peer_endpoint.size()), p.p, iocp_op); p.v = p.p = 0; + + // Update cancellation method if the reactor was used. + if (slot.is_connected() && op_type != -1) + { + static_cast<reactor_op_cancellation*>(iocp_op)->use_reactor( + &get_reactor(), &impl.reactor_data_, op_type); + } } }; |