$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r60869 - trunk/boost/asio/detail
From: chris_at_[hidden]
Date: 2010-03-27 06:54:44
Author: chris_kohlhoff
Date: 2010-03-27 06:54:44 EDT (Sat, 27 Mar 2010)
New Revision: 60869
URL: http://svn.boost.org/trac/boost/changeset/60869
Log:
Always call ioctl on underlying descriptor when modifying blocking mode. Refs #3307.
Text files modified: 
   trunk/boost/asio/detail/reactive_descriptor_service.hpp |    32 +++++++++++++++++++--------             
   trunk/boost/asio/detail/reactive_socket_service.hpp     |    45 ++++++++++++++------------------------- 
   2 files changed, 38 insertions(+), 39 deletions(-)
Modified: trunk/boost/asio/detail/reactive_descriptor_service.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_descriptor_service.hpp	(original)
+++ trunk/boost/asio/detail/reactive_descriptor_service.hpp	2010-03-27 06:54:44 EDT (Sat, 27 Mar 2010)
@@ -68,7 +68,7 @@
       // The descriptor has been set non-blocking.
       internal_non_blocking = 2,
 
-      // Helper "flag" used to determine whether the socket is non-blocking.
+      // Helper "flag" used to determine whether the descriptor is non-blocking.
       non_blocking = user_set_non_blocking | internal_non_blocking
     };
 
@@ -214,19 +214,31 @@
       return ec;
     }
 
-    if (command.name() == static_cast<int>(FIONBIO))
+    descriptor_ops::ioctl(impl.descriptor_, command.name(),
+        static_cast<ioctl_arg_type*>(command.data()), ec);
+
+    // When updating the non-blocking mode we always perform the ioctl syscall,
+    // even if the flags would otherwise indicate that the descriptor is
+    // already in the correct state. This ensures that the underlying
+    // descriptor is put into the state that has been requested by the user. If
+    // the ioctl syscall was successful then we need to update the flags to
+    // match.
+    if (!ec && command.name() == static_cast<int>(FIONBIO))
     {
-      if (command.get())
+      if (*static_cast<ioctl_arg_type*>(command.data()))
+      {
         impl.flags_ |= implementation_type::user_set_non_blocking;
+      }
       else
-        impl.flags_ &= ~implementation_type::user_set_non_blocking;
-      ec = boost::system::error_code();
-    }
-    else
-    {
-      descriptor_ops::ioctl(impl.descriptor_, command.name(),
-          static_cast<ioctl_arg_type*>(command.data()), ec);
+      {
+        // Clearing the non-blocking mode always overrides any internally-set
+        // non-blocking flag. Any subsequent asynchronous operations will need
+        // to re-enable non-blocking I/O.
+        impl.flags_ &= ~(implementation_type::user_set_non_blocking
+            | implementation_type::internal_non_blocking);
+      }
     }
+
     return ec;
   }
 
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	2010-03-27 06:54:44 EDT (Sat, 27 Mar 2010)
@@ -445,43 +445,30 @@
       return ec;
     }
 
-    if (command.name() == static_cast<int>(FIONBIO))
+    socket_ops::ioctl(impl.socket_, command.name(),
+        static_cast<ioctl_arg_type*>(command.data()), ec);
+
+    // When updating the non-blocking mode we always perform the ioctl
+    // syscall, even if the flags would otherwise indicate that the socket is
+    // already in the correct state. This ensures that the underlying socket
+    // is put into the state that has been requested by the user. If the ioctl
+    // syscall was successful then we need to update the flags to match.
+    if (!ec && command.name() == static_cast<int>(FIONBIO))
     {
-      // Flags are manipulated in a temporary variable so that the socket
-      // implementation is not updated unless the ioctl operation succeeds.
-      unsigned char new_flags = impl.flags_;
       if (*static_cast<ioctl_arg_type*>(command.data()))
-        new_flags |= implementation_type::user_set_non_blocking;
-      else
-        new_flags &= ~implementation_type::user_set_non_blocking;
-
-      // Perform ioctl on socket if the non-blocking state has changed.
-      if (!(impl.flags_ & implementation_type::non_blocking)
-          && (new_flags & implementation_type::non_blocking))
-      {
-        ioctl_arg_type non_blocking = 1;
-        socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
-      }
-      else if ((impl.flags_ & implementation_type::non_blocking)
-          && !(new_flags & implementation_type::non_blocking))
       {
-        ioctl_arg_type non_blocking = 0;
-        socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+        impl.flags_ |= implementation_type::user_set_non_blocking;
       }
       else
       {
-        ec = boost::system::error_code();
+        // Clearing the non-blocking mode always overrides any internally-set
+        // non-blocking flag. Any subsequent asynchronous operations will need
+        // to re-enable non-blocking I/O.
+        impl.flags_ &= ~(implementation_type::user_set_non_blocking
+            | implementation_type::internal_non_blocking);
       }
-
-      // Update socket implementation's flags only if successful.
-      if (!ec)
-        impl.flags_ = new_flags;
-    }
-    else
-    {
-      socket_ops::ioctl(impl.socket_, command.name(),
-          static_cast<ioctl_arg_type*>(command.data()), ec);
     }
+
     return ec;
   }