summaryrefslogtreecommitdiff
path: root/boost/asio/detail/impl/win_iocp_socket_service_base.ipp
diff options
context:
space:
mode:
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.ipp90
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)
{