Boost logo

Boost-Commit :

From: chris_at_[hidden]
Date: 2008-03-03 08:21:06


Author: chris_kohlhoff
Date: 2008-03-03 08:21:05 EST (Mon, 03 Mar 2008)
New Revision: 43469
URL: http://svn.boost.org/trac/boost/changeset/43469

Log:
Disable use of CancelIo by default, due to the possibility of silent
failure on some system configurations. Swallow error returned by CancelIoEx
if there are no operations to be cancelled.

Text files modified:
   trunk/boost/asio/basic_socket.hpp | 74 ++++++++++++++++++++++++++++++++++++++-
   trunk/boost/asio/detail/win_iocp_socket_service.hpp | 42 +++++++++++++++++++++-
   trunk/libs/asio/doc/using.qbk | 31 ++++++++++++++++
   3 files changed, 143 insertions(+), 4 deletions(-)

Modified: trunk/boost/asio/basic_socket.hpp
==============================================================================
--- trunk/boost/asio/basic_socket.hpp (original)
+++ trunk/boost/asio/basic_socket.hpp 2008-03-03 08:21:05 EST (Mon, 03 Mar 2008)
@@ -17,6 +17,10 @@
 
 #include <boost/asio/detail/push_options.hpp>
 
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
 #include <boost/asio/basic_io_object.hpp>
 #include <boost/asio/error.hpp>
 #include <boost/asio/socket_base.hpp>
@@ -296,7 +300,40 @@
    * will be passed the boost::asio::error::operation_aborted error.
    *
    * @throws boost::system::system_error Thrown on failure.
- */
+ *
+ * @note Calls to cancel() will always fail with
+ * boost::asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * BOOST_ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(BOOST_ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
   void cancel()
   {
     boost::system::error_code ec;
@@ -311,7 +348,40 @@
    * will be passed the boost::asio::error::operation_aborted error.
    *
    * @param ec Set to indicate what error occurred, if any.
- */
+ *
+ * @note Calls to cancel() will always fail with
+ * boost::asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * BOOST_ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(BOOST_ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
   boost::system::error_code cancel(boost::system::error_code& ec)
   {
     return this->service.cancel(this->implementation, ec);

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 2008-03-03 08:21:05 EST (Mon, 03 Mar 2008)
@@ -156,11 +156,13 @@
     // The protocol associated with the socket.
     protocol_type protocol_;
 
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     // The ID of the thread from which it is safe to cancel asynchronous
     // operations. 0 means no asynchronous operations have been started yet.
     // ~0 means asynchronous operations have been started from more than one
     // thread, and cancellation is not supported for the socket.
     DWORD safe_cancellation_thread_id_;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Pointers to adjacent socket implementations in linked list.
     implementation_type* next_;
@@ -204,7 +206,9 @@
     impl.socket_ = invalid_socket;
     impl.flags_ = 0;
     impl.cancel_token_.reset();
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Insert implementation into linked list of all implementations.
     boost::asio::detail::mutex::scoped_lock lock(mutex_);
@@ -306,7 +310,9 @@
       impl.socket_ = invalid_socket;
       impl.flags_ = 0;
       impl.cancel_token_.reset();
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
       impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
     }
 
     ec = boost::system::error_code();
@@ -338,14 +344,25 @@
       if (!cancel_io_ex(sock_as_handle, 0))
       {
         DWORD last_error = ::GetLastError();
- ec = boost::system::error_code(last_error,
- boost::asio::error::get_system_category());
+ if (last_error == ERROR_NOT_FOUND)
+ {
+ // ERROR_NOT_FOUND means that there were no operations to be
+ // cancelled. We swallow this error to match the behaviour on other
+ // platforms.
+ ec = boost::system::error_code();
+ }
+ else
+ {
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
       }
       else
       {
         ec = boost::system::error_code();
       }
     }
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     else if (impl.safe_cancellation_thread_id_ == 0)
     {
       // No operations have been started, so there's nothing to cancel.
@@ -374,6 +391,13 @@
       // so cancellation is not safe.
       ec = boost::asio::error::operation_not_supported;
     }
+#else // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ else
+ {
+ // Cancellation is not supported as CancelIo may not be used.
+ ec = boost::asio::error::operation_not_supported;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     return ec;
   }
@@ -773,11 +797,13 @@
       return;
     }
 
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     // Update the ID of the thread from which cancellation is safe.
     if (impl.safe_cancellation_thread_id_ == 0)
       impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
     else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
       impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Allocate and construct an operation to wrap the handler.
     typedef send_operation<ConstBufferSequence, Handler> value_type;
@@ -964,11 +990,13 @@
       return;
     }
 
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     // Update the ID of the thread from which cancellation is safe.
     if (impl.safe_cancellation_thread_id_ == 0)
       impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
     else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
       impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Allocate and construct an operation to wrap the handler.
     typedef send_to_operation<ConstBufferSequence, Handler> value_type;
@@ -1175,11 +1203,13 @@
       return;
     }
 
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     // Update the ID of the thread from which cancellation is safe.
     if (impl.safe_cancellation_thread_id_ == 0)
       impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
     else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
       impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Allocate and construct an operation to wrap the handler.
     typedef receive_operation<MutableBufferSequence, Handler> value_type;
@@ -1395,11 +1425,13 @@
       return;
     }
 
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     // Update the ID of the thread from which cancellation is safe.
     if (impl.safe_cancellation_thread_id_ == 0)
       impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
     else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
       impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Allocate and construct an operation to wrap the handler.
     typedef receive_from_operation<MutableBufferSequence, Handler> value_type;
@@ -1719,11 +1751,13 @@
       return;
     }
 
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     // Update the ID of the thread from which cancellation is safe.
     if (impl.safe_cancellation_thread_id_ == 0)
       impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
     else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
       impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Create a new socket for the connection.
     boost::system::error_code ec;
@@ -1893,11 +1927,13 @@
       return;
     }
 
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
     // Update the ID of the thread from which cancellation is safe.
     if (impl.safe_cancellation_thread_id_ == 0)
       impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
     else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
       impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
 
     // Check if the reactor was already obtained from the io_service.
     reactor_type* reactor = static_cast<reactor_type*>(
@@ -1997,7 +2033,9 @@
       impl.socket_ = invalid_socket;
       impl.flags_ = 0;
       impl.cancel_token_.reset();
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
       impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
     }
   }
 

Modified: trunk/libs/asio/doc/using.qbk
==============================================================================
--- trunk/libs/asio/doc/using.qbk (original)
+++ trunk/libs/asio/doc/using.qbk 2008-03-03 08:21:05 EST (Mon, 03 Mar 2008)
@@ -224,6 +224,37 @@
       function. Defaults to 5.
     ]
   ]
+ [
+ [`BOOST_ASIO_ENABLE_CANCELIO`]
+ [
+ Enables use of the `CancelIo` function on older versions of Windows. If
+ not enabled, calls to `cancel()` on a socket object will always fail with
+ `asio::error::operation_not_supported` when run on Windows XP, Windows
+ Server 2003, and earlier versions of Windows. When running on Windows
+ Vista, Windows Server 2008, and later, the `CancelIoEx` function is
+ always used.
+
+ The `CancelIo` function has two issues that should be considered before
+ enabling its use:
+
+ * It will only cancel asynchronous operations that were initiated in the
+ current thread.
+
+ * It can appear to complete without error, but the request
+ to cancel the unfinished operations may be silently ignored by the
+ operating system. Whether it works or not seems to depend on the
+ drivers that are installed.
+
+ For portable cancellation, consider using one of the following
+ alternatives:
+
+ * Disable asio's I/O completion port backend by defining
+ BOOST_ASIO_DISABLE_IOCP.
+
+ * Use the socket object's close() function to simultaneously
+ cancel the outstanding operations and close the socket.
+ ]
+ ]
 ]
 
 [endsect]


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