|
Boost-Commit : |
From: chris_at_[hidden]
Date: 2007-08-20 10:17:15
Author: chris_kohlhoff
Date: 2007-08-20 10:17:15 EDT (Mon, 20 Aug 2007)
New Revision: 38788
URL: http://svn.boost.org/trac/boost/changeset/38788
Log:
Increase number of buffers that may be sent or received in a single operation.
Clean up win_iocp_socket_service's close-on-destruction handling to ensure
non-blocking socket destructors.
Text files modified:
trunk/boost/asio/detail/reactive_socket_service.hpp | 2
trunk/boost/asio/detail/socket_types.hpp | 6 ++
trunk/boost/asio/detail/win_iocp_socket_service.hpp | 97 ++++++++++++++++++++++++++-------------
3 files changed, 72 insertions(+), 33 deletions(-)
Modified: trunk/boost/asio/detail/reactive_socket_service.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_service.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_service.hpp 2007-08-20 10:17:15 EDT (Mon, 20 Aug 2007)
@@ -87,7 +87,7 @@
};
// The maximum number of buffers to support in a single operation.
- enum { max_buffers = 16 };
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
// Constructor.
reactive_socket_service(boost::asio::io_service& io_service)
Modified: trunk/boost/asio/detail/socket_types.hpp
==============================================================================
--- trunk/boost/asio/detail/socket_types.hpp (original)
+++ trunk/boost/asio/detail/socket_types.hpp 2007-08-20 10:17:15 EDT (Mon, 20 Aug 2007)
@@ -142,6 +142,11 @@
const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE;
+# if defined (_WIN32_WINNT)
+const int max_iov_len = 64;
+# else
+const int max_iov_len = 16;
+# endif
#else
typedef int socket_type;
const int invalid_socket = -1;
@@ -167,6 +172,7 @@
const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE;
+const int max_iov_len = IOV_MAX;
#endif
const int custom_socket_option_level = 0xA5100000;
const int enable_connection_aborted_option = 1;
Modified: trunk/boost/asio/detail/win_iocp_socket_service.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_socket_service.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_socket_service.hpp 2007-08-20 10:17:15 EDT (Mon, 20 Aug 2007)
@@ -138,7 +138,7 @@
enum
{
enable_connection_aborted = 1, // User wants connection_aborted errors.
- user_set_linger = 2, // The user set the linger option.
+ close_might_block = 2, // User set linger option for blocking close.
user_set_non_blocking = 4 // The user wants a non-blocking socket.
};
@@ -171,7 +171,7 @@
typedef detail::select_reactor<true> reactor_type;
// The maximum number of buffers to support in a single operation.
- enum { max_buffers = 16 };
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
// Constructor.
win_iocp_socket_service(boost::asio::io_service& io_service)
@@ -193,7 +193,7 @@
while (impl)
{
boost::system::error_code ignored_ec;
- close(*impl, ignored_ec);
+ close_for_destruction(*impl);
impl = impl->next_;
}
}
@@ -218,34 +218,7 @@
// Destroy a socket implementation.
void destroy(implementation_type& impl)
{
- if (impl.socket_ != invalid_socket)
- {
- // 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_type* reactor = static_cast<reactor_type*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (reactor)
- reactor->close_descriptor(impl.socket_);
-
- if (impl.flags_ & implementation_type::user_set_linger)
- {
- ::linger opt;
- opt.l_onoff = 0;
- opt.l_linger = 0;
- boost::system::error_code ignored_ec;
- socket_ops::setsockopt(impl.socket_,
- SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
- }
-
- boost::system::error_code ignored_ec;
- socket_ops::close(impl.socket_, ignored_ec);
- impl.socket_ = invalid_socket;
- impl.flags_ = 0;
- impl.cancel_token_.reset();
- impl.safe_cancellation_thread_id_ = 0;
- }
+ close_for_destruction(impl);
// Remove implementation from linked list of all implementations.
boost::asio::detail::mutex::scoped_lock lock(mutex_);
@@ -354,6 +327,24 @@
{
ec = boost::asio::error::bad_descriptor;
}
+ else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+ ::GetModuleHandle("KERNEL32"), "CancelIoEx"))
+ {
+ // The version of Windows supports cancellation from any thread.
+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+ cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+ socket_type sock = impl.socket_;
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+ if (!cancel_io_ex(sock_as_handle, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error, boost::system::native_ecat);
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+ }
else if (impl.safe_cancellation_thread_id_ == 0)
{
// No operations have been started, so there's nothing to cancel.
@@ -476,7 +467,12 @@
if (option.level(impl.protocol_) == SOL_SOCKET
&& option.name(impl.protocol_) == SO_LINGER)
{
- impl.flags_ |= implementation_type::user_set_linger;
+ const ::linger* linger_option =
+ reinterpret_cast<const ::linger*>(option.data(impl.protocol_));
+ if (linger_option->l_onoff != 0 && linger_option->l_linger != 0)
+ impl.flags_ |= implementation_type::close_might_block;
+ else
+ impl.flags_ &= ~implementation_type::close_might_block;
}
socket_ops::setsockopt(impl.socket_,
@@ -1951,6 +1947,43 @@
}
private:
+ // Helper function to close a socket when the associated object is being
+ // destroyed.
+ void close_for_destruction(implementation_type& impl)
+ {
+ if (is_open(impl))
+ {
+ // 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_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (reactor)
+ reactor->close_descriptor(impl.socket_);
+
+ // The socket destructor must not block. If the user has changed the
+ // linger option to block in the foreground, we will change it back to the
+ // default so that the closure is performed in the background.
+ if (impl.flags_ & implementation_type::close_might_block)
+ {
+ ::linger opt;
+ opt.l_onoff = 0;
+ opt.l_linger = 0;
+ boost::system::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_,
+ SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
+ }
+
+ boost::system::error_code ignored_ec;
+ socket_ops::close(impl.socket_, ignored_ec);
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset();
+ impl.safe_cancellation_thread_id_ = 0;
+ }
+ }
+
// Helper function to emulate InterlockedCompareExchangePointer functionality
// for:
// - very old Platform SDKs; and
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk