private bool SetAsyncEventSelect(AsyncEventBits blockEventBits) { GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "blockEventBits:" + blockEventBits.ToString() + " m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString()); GlobalLog.Assert(blockEventBits != AsyncEventBits.FdNone, "Socket#{0}::SetAsyncEventSelect|Use UnsetAsyncEventSelect for FdNone.", ValidationHelper.HashString(this)); GlobalLog.Assert(m_BlockEventBits == AsyncEventBits.FdNone || m_BlockEventBits == blockEventBits, "Socket#{0}::SetAsyncEventSelect|Can't change from one active wait to another.", ValidationHelper.HashString(this)); GlobalLog.Assert(m_RegisteredWait == null, "Socket#{0}::SetAsyncEventSelect|Already actively waiting on an op.", ValidationHelper.HashString(this)); // This check is bogus, too late diggin into a historical reason for it. // Make sure the upper level will fail with ObjectDisposedException if (m_RegisteredWait != null) return false; // // This will put us into non-blocking mode. Create the event if it isn't, and register a wait. // if (m_AsyncEvent == null) { Interlocked.CompareExchange<ManualResetEvent>(ref m_AsyncEvent, new ManualResetEvent(false), null); if (s_RegisteredWaitCallback == null) s_RegisteredWaitCallback = new WaitOrTimerCallback(RegisteredWaitCallback); } // // Try to win over Dispose is there is a ---- // if (Interlocked.CompareExchange(ref m_IntCleanedUp, 2, 0) != 0) { GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() Already Cleaned up, returning ... ", string.Empty); return false; } try { m_BlockEventBits = blockEventBits; m_RegisteredWait = ThreadPool.UnsafeRegisterWaitForSingleObject(m_AsyncEvent, s_RegisteredWaitCallback, this, Timeout.Infinite, true); } finally { // // Release dispose if any is waiting // Interlocked.Exchange(ref m_IntCleanedUp, 0); } SocketError errorCode = SocketError.NotSocket; // // issue the native call // try { errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_Handle, m_AsyncEvent.SafeWaitHandle, blockEventBits); } catch (Exception e) { if (NclUtilities.IsFatal(e)) throw; GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect() !!! (converting to ObjectDisposed) Exception :" + e.ToString()); GlobalLog.Assert(CleanedUp, "Socket#{0}::SetAsyncEventSelect|WSAEventSelect got exception and CleanedUp not set.", ValidationHelper.HashString(this)); } if (errorCode==SocketError.SocketError) { // // update our internal state after this socket error // we won't throw since this is an internal method // UpdateStatusAfterSocketError(errorCode); } // // the call to WSAEventSelect will put us in non-blocking mode, // hence we need update internal status // willBlockInternal = false; GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString()); return errorCode == SocketError.Success; }
// // Does internal initalization before async winsock // call to BeginConnect() or BeginAccept(). // internal void SetAsyncEventSelect(AsyncEventBits blockEventBits) { GlobalLog.Enter("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "blockEventBits:" + blockEventBits.ToString() + " m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString()); if (blockEventBits==m_BlockEventBits) { // // nothing for us to do, nothing is going to change // GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "nothing to do"); return; } // // We need to select socket first, enabling us to listen to events // then submit the event to the thread pool, and then finally // call the function we wish to call. // the following event is not used in Send/Receive async APIs // IntPtr eventHandle; if (blockEventBits==AsyncEventBits.FdNone) { // // this will cancel any previous WSAEventSelect() and will put us back // into blocking mode. custom build the native parameters // if (m_AsyncEvent!=null) { m_AsyncEvent = null; } eventHandle = IntPtr.Zero; } else { // // this will put us into non-blocking mode. // we'll need the real pointer here // if (m_AsyncEvent==null) { m_AsyncEvent = new AutoResetEvent(false); } eventHandle = m_AsyncEvent.Handle; } // // save blockEventBits // m_BlockEventBits = blockEventBits; // // issue the native call // int errorCode = UnsafeNclNativeMethods.OSSOCK.WSAEventSelect( m_Handle, eventHandle, m_BlockEventBits ); if (errorCode==SocketErrors.SocketError) { // // update our internal state after this socket error // we won't throw since this is an internal method // UpdateStatusAfterSocketError(); } // // the call to WSAEventSelect might have caused us to change // blocking mode, hence we need update internal status // willBlockInternal = willBlockInternal && m_BlockEventBits==AsyncEventBits.FdNone; GlobalLog.Leave("Socket#" + ValidationHelper.HashString(this) + "::SetAsyncEventSelect", "m_BlockEventBits:" + m_BlockEventBits.ToString() + " willBlockInternal:" + willBlockInternal.ToString()); }