diff options
Diffstat (limited to 'boost/asio/detail/impl/win_iocp_socket_service_base.ipp')
-rw-r--r-- | boost/asio/detail/impl/win_iocp_socket_service_base.ipp | 90 |
1 files changed, 72 insertions, 18 deletions
diff --git a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp index 93f5ed0713..e9a5049345 100644 --- a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp +++ b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -28,24 +28,24 @@ namespace asio { namespace detail { win_iocp_socket_service_base::win_iocp_socket_service_base( - boost::asio::io_service& io_service) - : io_service_(io_service), - iocp_service_(use_service<win_iocp_io_service>(io_service)), + boost::asio::io_context& io_context) + : io_context_(io_context), + iocp_service_(use_service<win_iocp_io_context>(io_context)), reactor_(0), connect_ex_(0), + nt_set_info_(0), mutex_(), impl_list_(0) { } -void win_iocp_socket_service_base::shutdown_service() +void win_iocp_socket_service_base::base_shutdown() { // Close all implementations, causing all operations to complete. boost::asio::detail::mutex::scoped_lock lock(mutex_); base_implementation_type* impl = impl_list_; while (impl) { - boost::system::error_code ignored_ec; close_for_destruction(*impl); impl = impl->next_; } @@ -167,12 +167,13 @@ boost::system::error_code win_iocp_socket_service_base::close( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) @@ -198,6 +199,39 @@ boost::system::error_code win_iocp_socket_service_base::close( return ec; } +socket_type win_iocp_socket_service_base::release( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + return invalid_socket; + + cancel(impl, ec); + if (ec) + return invalid_socket; + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = boost::asio::error::operation_not_supported; + return invalid_socket; + } + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_); + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(sock_as_handle, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = boost::asio::error::operation_not_supported; + return invalid_socket; + } + + socket_type tmp = impl.socket_; + impl.socket_ = invalid_socket; + return tmp; +} + boost::system::error_code win_iocp_socket_service_base::cancel( win_iocp_socket_service_base::base_implementation_type& impl, boost::system::error_code& ec) @@ -208,7 +242,8 @@ boost::system::error_code win_iocp_socket_service_base::cancel( return ec; } - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "cancel")); if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) @@ -279,7 +314,7 @@ boost::system::error_code win_iocp_socket_service_base::cancel( // Cancel any operations started via the reactor. if (!ec) { - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) @@ -445,7 +480,7 @@ void win_iocp_socket_service_base::start_null_buffers_receive_op( { start_reactor_op(impl, (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, + ? select_reactor::except_op : select_reactor::read_op, op); } } @@ -537,7 +572,7 @@ void win_iocp_socket_service_base::start_reactor_op( win_iocp_socket_service_base::base_implementation_type& impl, int op_type, reactor_op* op) { - reactor& r = get_reactor(); + select_reactor& r = get_reactor(); update_cancellation_thread_id(impl); if (is_open(impl)) @@ -598,7 +633,7 @@ void win_iocp_socket_service_base::start_connect_op( } // Otherwise, fall back to a reactor-based implementation. - reactor& r = get_reactor(); + select_reactor& r = get_reactor(); update_cancellation_thread_id(impl); if ((impl.state_ & socket_ops::non_blocking) != 0 @@ -611,7 +646,7 @@ void win_iocp_socket_service_base::start_connect_op( || op->ec_ == boost::asio::error::would_block) { op->ec_ = boost::system::error_code(); - r.start_op(reactor::connect_op, impl.socket_, + r.start_op(select_reactor::connect_op, impl.socket_, impl.reactor_data_, op, false, false); return; } @@ -626,12 +661,13 @@ void win_iocp_socket_service_base::close_for_destruction( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) @@ -665,14 +701,14 @@ void win_iocp_socket_service_base::update_cancellation_thread_id( #endif // defined(BOOST_ASIO_ENABLE_CANCELIO) } -reactor& win_iocp_socket_service_base::get_reactor() +select_reactor& win_iocp_socket_service_base::get_reactor() { - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (!r) { - r = &(use_service<reactor>(io_service_)); + r = &(use_service<select_reactor>(io_context_)); interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r); } return *r; @@ -713,6 +749,24 @@ win_iocp_socket_service_base::get_connect_ex( #endif // defined(BOOST_ASIO_DISABLE_CONNECTEX) } +win_iocp_socket_service_base::nt_set_info_fn +win_iocp_socket_service_base::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr); +} + void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( void** dest, void* exch, void* cmp) { |