$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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