Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Net / System / Net / Sockets / _BaseOverlappedAsyncResult.cs / 5 / _BaseOverlappedAsyncResult.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net.Sockets { using System; using System.Net; using System.Runtime.InteropServices; using System.Threading; using Microsoft.Win32; // // BaseOverlappedAsyncResult - used to enable async Socket operation // such as the BeginSend, BeginSendTo, BeginReceive, BeginReceiveFrom, BeginSendFile, // BeginAccept, calls. // internal class BaseOverlappedAsyncResult : ContextAwareResult { // // internal class members // private SafeOverlappedFree m_UnmanagedBlob; // Handle for global memory. private AutoResetEvent m_OverlappedEvent; private int m_CleanupCount; private bool m_DisableOverlapped; private bool m_UseOverlappedIO; private GCHandle [] m_GCHandles; private OverlappedCache m_Cache; // // The WinNT Completion Port callback. // #if SOCKETTHREADPOOL internal #else private #endif unsafe static readonly IOCompletionCallback s_IOCallback = new IOCompletionCallback(CompletionPortCallback); // // Constructor. We take in the socket that's creating us, the caller's // state object, and callback. We save the socket and state, and allocate // an event for the WaitHandle. // internal BaseOverlappedAsyncResult(Socket socket, Object asyncState, AsyncCallback asyncCallback) : base(socket, asyncState, asyncCallback) { // // BeginAccept() allocates and returns an AcceptOverlappedAsyncResult that will call // this constructor. // m_UseOverlappedIO = Socket.UseOverlappedIO || socket.UseOnlyOverlappedIO; if (m_UseOverlappedIO) { // // since the binding between the event handle and the callback // happens after the IO was queued to the OS, there is no ---- // condition and the Cleanup code can be called at most once. // m_CleanupCount = 1; } else { // // since the binding between the event handle and the callback // has already happened there is a race condition and so the // Cleanup code can be called more than once and at most twice. // m_CleanupCount = 2; } } // // Constructor. We take in the socket that's creating us, and turn off Async // We save the socket and state. internal BaseOverlappedAsyncResult(Socket socket) : base(socket, null, null) { m_CleanupCount = 1; m_DisableOverlapped = true; } //PostCompletion returns the result object to be set before the user's callback is invoked. internal virtual object PostCompletion(int numBytes) { return numBytes; } // // SetUnmanagedStructures - // // This needs to be called for overlapped IO to function properly. // // Fills in Overlapped Structures used in an Async Overlapped Winsock call // these calls are outside the runtime and are unmanaged code, so we need // to prepare specific structures and ints that lie in unmanaged memory // since the Overlapped calls can be Async // internal void SetUnmanagedStructures(object objectsToPin) { if (!m_DisableOverlapped) { // Casting to object[] is very expensive. Only do it once. object[] objectsToPinArray = null; bool triedCastingToArray = false; bool useCache = false; if (m_Cache != null) { if (objectsToPin == null && m_Cache.PinnedObjects == null) { useCache = true; } else if (m_Cache.PinnedObjects != null) { if (m_Cache.PinnedObjectsArray == null) { if (objectsToPin == m_Cache.PinnedObjects) { useCache = true; } } else if (objectsToPin != null) { triedCastingToArray = true; objectsToPinArray = objectsToPin as object[]; if (objectsToPinArray != null && objectsToPinArray.Length == 0) { objectsToPinArray = null; } if (objectsToPinArray != null && objectsToPinArray.Length == m_Cache.PinnedObjectsArray.Length) { useCache = true; for (int i = 0; i < objectsToPinArray.Length; i++) { if (objectsToPinArray[i] != m_Cache.PinnedObjectsArray[i]) { useCache = false; break; } } } } } } if (!useCache && m_Cache != null) { GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::SetUnmanagedStructures() Cache miss - freeing cache."); m_Cache.Free(); m_Cache = null; } Socket s = (Socket) AsyncObject; if (m_UseOverlappedIO) { // // we're using overlapped IO, allocate an overlapped structure // consider using a static growing pool of allocated unmanaged memory. // GlobalLog.Assert(m_UnmanagedBlob == null, "BaseOverlappedAsyncResult#{0}::SetUnmanagedStructures()|Unmanaged blob already allocated. (Called twice?)", ValidationHelper.HashString(this)); m_UnmanagedBlob = SafeOverlappedFree.Alloc(s.SafeHandle); PinUnmanagedObjects(objectsToPin); // // create the event handle // m_OverlappedEvent = new AutoResetEvent(false); // // fill in the overlapped structure with the event handle. // Marshal.WriteIntPtr( m_UnmanagedBlob.DangerousGetHandle(), Win32.OverlappedhEventOffset, m_OverlappedEvent.SafeWaitHandle.DangerousGetHandle() ); } else { // // Bind the Win32 Socket Handle to the ThreadPool // s.BindToCompletionPort(); if (m_Cache == null) { GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() Creating new overlapped cache."); if (objectsToPinArray != null) { m_Cache = new OverlappedCache(new Overlapped(), objectsToPinArray, s_IOCallback); } else { m_Cache = new OverlappedCache(new Overlapped(), objectsToPin, s_IOCallback, triedCastingToArray); } } else { GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() Using cached overlapped."); } m_Cache.Overlapped.AsyncResult = this; #if DEBUG unsafe { m_InitialNativeOverlapped = *((NativeOverlapped *) m_Cache.NativeOverlapped); } #endif GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() overlapped:" + ValidationHelper.HashString(m_Cache.Overlapped) + " NativeOverlapped = " + m_Cache.NativeOverlapped.ToString("x")); } } } /* // Consider removing. internal void SetUnmanagedStructures(object objectsToPin, ref OverlappedCache overlappedCache) { SetupCache(ref overlappedCache); SetUnmanagedStructures(objectsToPin); } */ protected void SetupCache(ref OverlappedCache overlappedCache) { #if !NO_OVERLAPPED_CACHE GlobalLog.Assert(m_Cache == null, "BaseOverlappedAsyncResult#{0}::SetUnmanagedStructures()|Cache already set up. (Called twice?)", ValidationHelper.HashString(this)); if (!m_UseOverlappedIO && !m_DisableOverlapped) { m_Cache = overlappedCache == null ? null : Interlocked.Exchange(ref overlappedCache, null); // Need to hold on to the unmanaged structures until the cache is extracted. m_CleanupCount++; } #endif } // // This method pins unmanaged objects for Win9x and systems where completion ports are not found // protected void PinUnmanagedObjects(object objectsToPin) { if (m_Cache != null) { m_Cache.Free(); m_Cache = null; } if (objectsToPin != null) { if (objectsToPin.GetType() == typeof(object[])) { object [] objectsArray = (object []) objectsToPin; m_GCHandles = new GCHandle[objectsArray.Length]; for (int i=0; i (ref m_Cache, null); if (cache != null) { // If overlappedCache is null, just slap it in there. There's a chance for a conflict, // resulting in a OverlappedCache getting finalized, but it's better than // the interlocked. This won't be an issue in most 'correct' cases. if (overlappedCache == null) { overlappedCache = cache; } else { OverlappedCache oldCache = Interlocked.Exchange (ref overlappedCache, cache); if (oldCache != null) { oldCache.Free(); } } } ReleaseUnmanagedStructures(); } #endif } private unsafe static void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { #if DEBUG GlobalLog.SetThreadSource(ThreadKinds.CompletionPort); using (GlobalLog.SetThreadKind(ThreadKinds.System)) { #if TRAVE try { #endif #endif // // Create an Overlapped object out of the native pointer we're provided with. // (this will NOT free the unmanaged memory in the native overlapped structure) // Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)callbackOverlapped.AsyncResult; // The AsyncResult must be cleared before the callback is called (i.e. before ExtractCache is called). // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object, // which points to the Socket (as well as user data), which points to the OverlappedCache, preventing the OverlappedCache // finalizer from freeing the pinned OverlappedData. callbackOverlapped.AsyncResult = null; object returnObject = null; GlobalLog.Assert(!asyncResult.InternalPeekCompleted, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|asyncResult.IsCompleted", ValidationHelper.HashString(asyncResult)); GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::CompletionPortCallback" + " errorCode:" + errorCode.ToString() + " numBytes:" + numBytes.ToString() + " pOverlapped:" + ((int)nativeOverlapped).ToString()); // // complete the IO and invoke the user's callback // SocketError socketError = (SocketError)errorCode; if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) { // There are cases where passed errorCode does not reflect the details of the underlined socket error. // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may // be other differences as well." Socket socket = asyncResult.AsyncObject as Socket; if (socket == null) { socketError = SocketError.NotSocket; } else if (socket.CleanedUp) { socketError = SocketError.OperationAborted; } else { try { // // The Async IO completed with a failure. // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error. // SocketFlags ignore; bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult( socket.SafeHandle, (IntPtr)nativeOverlapped, out numBytes, false, out ignore); if (!success) { socketError = (SocketError)Marshal.GetLastWin32Error(); GlobalLog.Assert(socketError != 0, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|socketError:0 numBytes:{1}", ValidationHelper.HashString(asyncResult), numBytes); } GlobalLog.Assert(!success, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|Unexpectedly succeeded. errorCode:{1} numBytes:{2}", ValidationHelper.HashString(asyncResult), errorCode, numBytes); } // CleanedUp check above does not always work since this code is subject to race conditions catch (ObjectDisposedException) { socketError = SocketError.OperationAborted; } } } asyncResult.ErrorCode = (int)socketError; returnObject = asyncResult.PostCompletion((int)numBytes); asyncResult.ReleaseUnmanagedStructures(); asyncResult.InvokeCallback(returnObject); #if DEBUG #if TRAVE } catch(Exception exception) { if (!NclUtilities.IsFatal(exception)){ GlobalLog.Assert("BaseOverlappedAsyncResult::CompletionPortCallback", "Exception in completion callback type:" + exception.GetType().ToString() + " message:" + exception.Message); } throw; } #endif } #endif } // // The overlapped function called (either by the thread pool or the socket) // when IO completes. (only called on Win9x) // private void OverlappedCallback(object stateObject, bool Signaled) { #if DEBUG // GlobalLog.SetThreadSource(ThreadKinds.Worker); Because of change 1077887, need logic to determine thread type here. using (GlobalLog.SetThreadKind(ThreadKinds.System)) { #endif BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)stateObject; GlobalLog.Assert(!asyncResult.InternalPeekCompleted, "AcceptOverlappedAsyncResult#{0}::OverlappedCallback()|asyncResult.IsCompleted", ValidationHelper.HashString(asyncResult)); // // the IO completed asynchronously, see if there was a failure the Internal // field in the Overlapped structure will be non zero. to optimize the non // error case, we look at it without calling WSAGetOverlappedResult(). // uint errorCode = (uint)Marshal.ReadInt32(IntPtrHelper.Add(asyncResult.m_UnmanagedBlob.DangerousGetHandle(), Win32.OverlappedInternalOffset)); uint numBytes = errorCode!=0 ? unchecked((uint)-1) : (uint)Marshal.ReadInt32(IntPtrHelper.Add(asyncResult.m_UnmanagedBlob.DangerousGetHandle(), Win32.OverlappedInternalHighOffset)); // // this will release the unmanaged pin handles and unmanaged overlapped ptr // asyncResult.ErrorCode = (int)errorCode; object returnObject = asyncResult.PostCompletion((int)numBytes); asyncResult.ReleaseUnmanagedStructures(); asyncResult.InvokeCallback(returnObject); #if DEBUG } #endif } #if DEBUG private SocketError m_SavedErrorCode = unchecked((SocketError) 0xDEADBEEF); private NativeOverlapped m_InitialNativeOverlapped; private NativeOverlapped m_IntermediateNativeOverlapped; #endif // // This method is called after an asynchronous call is made for the user, // it checks and acts accordingly if the IO: // 1) completed synchronously. // 2) was pended. // 3) failed. // internal unsafe SocketError CheckAsyncCallOverlappedResult(SocketError errorCode) { #if DEBUG m_SavedErrorCode = errorCode; #endif // // Check if the Async IO call: // 1) was pended. // 2) completed synchronously. // 3) failed. // if (m_UseOverlappedIO) { // // we're using overlapped IO under Win9x (or NT with registry setting overriding // completion port usage) // switch (errorCode) { case 0: case SocketError.IOPending: // // the Async IO call was pended: // Queue our event to the thread pool. // GlobalLog.Assert(m_UnmanagedBlob != null, "BaseOverlappedAsyncResult#{0}::CheckAsyncCallOverlappedResult()|Unmanaged blob isn't allocated.", ValidationHelper.HashString(this)); ThreadPool.UnsafeRegisterWaitForSingleObject( m_OverlappedEvent, new WaitOrTimerCallback(OverlappedCallback), this, -1, true ); // // we're done, completion will be asynchronous // in the callback. return // return SocketError.Success; default: // // the Async IO call failed: // set the number of bytes transferred to -1 (error) // ErrorCode = (int)errorCode; Result = -1; ReleaseUnmanagedStructures(); break; } } else { #if DEBUG OverlappedCache cache = m_Cache; if (cache != null) unsafe { NativeOverlapped* nativeOverlappedPtr = (NativeOverlapped *) cache.NativeOverlapped; if (nativeOverlappedPtr != null) m_IntermediateNativeOverlapped = *nativeOverlappedPtr; } #endif // // We're using completion ports under WinNT. Release one reference on the structures for // the main thread. // ReleaseUnmanagedStructures(); switch (errorCode) { // // ignore cases in which a completion packet will be queued: // we'll deal with this IO in the callback // case 0: case SocketError.IOPending: // // ignore, do nothing // return SocketError.Success; // // in the remaining cases a completion packet will NOT be queued: // we'll have to call the callback explicitly signaling an error // default: // // call the callback with error code // ErrorCode = (int)errorCode; Result = -1; // The AsyncResult must be cleared since the callback isn't going to be called. // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object, // which points to the Socket (as well as user data) and to the OverlappedCache, preventing the OverlappedCache // finalizer from freeing the pinned OverlappedData. if (m_Cache != null) { // Could be null only if SetUnmanagedStructures weren't called. m_Cache.Overlapped.AsyncResult = null; } ReleaseUnmanagedStructures(); // Additional release for the completion that won't happen. break; } } return errorCode; } // // The following property returns the Win32 unsafe pointer to // whichever Overlapped structure we're using for IO. // internal unsafe IntPtr OverlappedHandle { get { if (m_UseOverlappedIO) { // // on Win9x we allocate our own overlapped structure // and we use a win32 event for IO completion // return the native pointer to unmanaged memory // return (m_UnmanagedBlob == null || m_UnmanagedBlob.IsInvalid)? IntPtr.Zero: m_UnmanagedBlob.DangerousGetHandle(); } else { // // on WinNT we need to use (due to the current implementation) // an Overlapped object in order to bind the socket to the // ThreadPool's completion port, so return the native handle // return m_Cache == null ? IntPtr.Zero : m_Cache.NativeOverlapped; } } } // OverlappedHandle private void ReleaseUnmanagedStructures() { if (Interlocked.Decrement(ref m_CleanupCount) == 0) { ForceReleaseUnmanagedStructures(); } } protected override void Cleanup() { base.Cleanup(); // If we get all the way to here and it's still not cleaned up... if (m_CleanupCount > 0 && Interlocked.Exchange(ref m_CleanupCount, 0) > 0) { ForceReleaseUnmanagedStructures(); } } // Utility cleanup routine. Frees the overlapped structure. // This should be overriden to free pinned and unmanaged memory in the subclass. // It needs to also be invoked from the subclass. protected virtual void ForceReleaseUnmanagedStructures() { // // free the unmanaged memory if allocated. // ReleaseGCHandles(); GC.SuppressFinalize(this); if (m_UnmanagedBlob != null && !m_UnmanagedBlob.IsInvalid) { m_UnmanagedBlob.Close(true); m_UnmanagedBlob = null; } // This is interlocked because Cleanup() can be called simultaneously with ExtractCache(). OverlappedCache.InterlockedFree(ref m_Cache); if (m_OverlappedEvent != null) { m_OverlappedEvent.Close(); m_OverlappedEvent = null; } } ~BaseOverlappedAsyncResult() { ReleaseGCHandles(); } private void ReleaseGCHandles() { GCHandle[] gcHandles = m_GCHandles; if (gcHandles != null) { for (int i = 0; i < gcHandles.Length; i++) { if (gcHandles[i].IsAllocated) { gcHandles[i].Free(); } } } } } internal class OverlappedCache { internal Overlapped m_Overlapped; internal IntPtr m_NativeOverlapped; internal object m_PinnedObjects; internal object[] m_PinnedObjectsArray; internal OverlappedCache(Overlapped overlapped, object[] pinnedObjectsArray, IOCompletionCallback callback) { m_Overlapped = overlapped; m_PinnedObjects = pinnedObjectsArray; m_PinnedObjectsArray = pinnedObjectsArray; unsafe { m_NativeOverlapped = (IntPtr) overlapped.UnsafePack(callback, pinnedObjectsArray); } } internal OverlappedCache(Overlapped overlapped, object pinnedObjects, IOCompletionCallback callback, bool alreadyTriedCast) { m_Overlapped = overlapped; m_PinnedObjects = pinnedObjects; m_PinnedObjectsArray = alreadyTriedCast ? null : NclConstants.EmptyObjectArray; unsafe { m_NativeOverlapped = (IntPtr) overlapped.UnsafePack(callback, pinnedObjects); } } internal Overlapped Overlapped { get { return m_Overlapped; } } internal IntPtr NativeOverlapped { get { return m_NativeOverlapped; } } internal object PinnedObjects { get { return m_PinnedObjects; } } internal object[] PinnedObjectsArray { get { object[] pinnedObjectsArray = m_PinnedObjectsArray; if (pinnedObjectsArray != null && pinnedObjectsArray.Length == 0) { pinnedObjectsArray = m_PinnedObjects as object[]; if (pinnedObjectsArray != null && pinnedObjectsArray.Length == 0) { m_PinnedObjectsArray = null; } else { m_PinnedObjectsArray = pinnedObjectsArray; } } return m_PinnedObjectsArray; } } // This must only be called once. internal void Free() { InternalFree(); GC.SuppressFinalize(this); } private void InternalFree() { m_Overlapped = null; m_PinnedObjects = null; if (m_NativeOverlapped != IntPtr.Zero) { unsafe { Overlapped.Free((NativeOverlapped*) m_NativeOverlapped); } m_NativeOverlapped = IntPtr.Zero; } } internal static void InterlockedFree(ref OverlappedCache overlappedCache) { OverlappedCache cache = overlappedCache == null ? null : Interlocked.Exchange (ref overlappedCache, null); if (cache != null) { cache.Free(); } } ~OverlappedCache() { if (!NclUtilities.HasShutdownStarted) { InternalFree(); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net.Sockets { using System; using System.Net; using System.Runtime.InteropServices; using System.Threading; using Microsoft.Win32; // // BaseOverlappedAsyncResult - used to enable async Socket operation // such as the BeginSend, BeginSendTo, BeginReceive, BeginReceiveFrom, BeginSendFile, // BeginAccept, calls. // internal class BaseOverlappedAsyncResult : ContextAwareResult { // // internal class members // private SafeOverlappedFree m_UnmanagedBlob; // Handle for global memory. private AutoResetEvent m_OverlappedEvent; private int m_CleanupCount; private bool m_DisableOverlapped; private bool m_UseOverlappedIO; private GCHandle [] m_GCHandles; private OverlappedCache m_Cache; // // The WinNT Completion Port callback. // #if SOCKETTHREADPOOL internal #else private #endif unsafe static readonly IOCompletionCallback s_IOCallback = new IOCompletionCallback(CompletionPortCallback); // // Constructor. We take in the socket that's creating us, the caller's // state object, and callback. We save the socket and state, and allocate // an event for the WaitHandle. // internal BaseOverlappedAsyncResult(Socket socket, Object asyncState, AsyncCallback asyncCallback) : base(socket, asyncState, asyncCallback) { // // BeginAccept() allocates and returns an AcceptOverlappedAsyncResult that will call // this constructor. // m_UseOverlappedIO = Socket.UseOverlappedIO || socket.UseOnlyOverlappedIO; if (m_UseOverlappedIO) { // // since the binding between the event handle and the callback // happens after the IO was queued to the OS, there is no ---- // condition and the Cleanup code can be called at most once. // m_CleanupCount = 1; } else { // // since the binding between the event handle and the callback // has already happened there is a race condition and so the // Cleanup code can be called more than once and at most twice. // m_CleanupCount = 2; } } // // Constructor. We take in the socket that's creating us, and turn off Async // We save the socket and state. internal BaseOverlappedAsyncResult(Socket socket) : base(socket, null, null) { m_CleanupCount = 1; m_DisableOverlapped = true; } //PostCompletion returns the result object to be set before the user's callback is invoked. internal virtual object PostCompletion(int numBytes) { return numBytes; } // // SetUnmanagedStructures - // // This needs to be called for overlapped IO to function properly. // // Fills in Overlapped Structures used in an Async Overlapped Winsock call // these calls are outside the runtime and are unmanaged code, so we need // to prepare specific structures and ints that lie in unmanaged memory // since the Overlapped calls can be Async // internal void SetUnmanagedStructures(object objectsToPin) { if (!m_DisableOverlapped) { // Casting to object[] is very expensive. Only do it once. object[] objectsToPinArray = null; bool triedCastingToArray = false; bool useCache = false; if (m_Cache != null) { if (objectsToPin == null && m_Cache.PinnedObjects == null) { useCache = true; } else if (m_Cache.PinnedObjects != null) { if (m_Cache.PinnedObjectsArray == null) { if (objectsToPin == m_Cache.PinnedObjects) { useCache = true; } } else if (objectsToPin != null) { triedCastingToArray = true; objectsToPinArray = objectsToPin as object[]; if (objectsToPinArray != null && objectsToPinArray.Length == 0) { objectsToPinArray = null; } if (objectsToPinArray != null && objectsToPinArray.Length == m_Cache.PinnedObjectsArray.Length) { useCache = true; for (int i = 0; i < objectsToPinArray.Length; i++) { if (objectsToPinArray[i] != m_Cache.PinnedObjectsArray[i]) { useCache = false; break; } } } } } } if (!useCache && m_Cache != null) { GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::SetUnmanagedStructures() Cache miss - freeing cache."); m_Cache.Free(); m_Cache = null; } Socket s = (Socket) AsyncObject; if (m_UseOverlappedIO) { // // we're using overlapped IO, allocate an overlapped structure // consider using a static growing pool of allocated unmanaged memory. // GlobalLog.Assert(m_UnmanagedBlob == null, "BaseOverlappedAsyncResult#{0}::SetUnmanagedStructures()|Unmanaged blob already allocated. (Called twice?)", ValidationHelper.HashString(this)); m_UnmanagedBlob = SafeOverlappedFree.Alloc(s.SafeHandle); PinUnmanagedObjects(objectsToPin); // // create the event handle // m_OverlappedEvent = new AutoResetEvent(false); // // fill in the overlapped structure with the event handle. // Marshal.WriteIntPtr( m_UnmanagedBlob.DangerousGetHandle(), Win32.OverlappedhEventOffset, m_OverlappedEvent.SafeWaitHandle.DangerousGetHandle() ); } else { // // Bind the Win32 Socket Handle to the ThreadPool // s.BindToCompletionPort(); if (m_Cache == null) { GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() Creating new overlapped cache."); if (objectsToPinArray != null) { m_Cache = new OverlappedCache(new Overlapped(), objectsToPinArray, s_IOCallback); } else { m_Cache = new OverlappedCache(new Overlapped(), objectsToPin, s_IOCallback, triedCastingToArray); } } else { GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() Using cached overlapped."); } m_Cache.Overlapped.AsyncResult = this; #if DEBUG unsafe { m_InitialNativeOverlapped = *((NativeOverlapped *) m_Cache.NativeOverlapped); } #endif GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(this) + "::EnableCompletionPort() overlapped:" + ValidationHelper.HashString(m_Cache.Overlapped) + " NativeOverlapped = " + m_Cache.NativeOverlapped.ToString("x")); } } } /* // Consider removing. internal void SetUnmanagedStructures(object objectsToPin, ref OverlappedCache overlappedCache) { SetupCache(ref overlappedCache); SetUnmanagedStructures(objectsToPin); } */ protected void SetupCache(ref OverlappedCache overlappedCache) { #if !NO_OVERLAPPED_CACHE GlobalLog.Assert(m_Cache == null, "BaseOverlappedAsyncResult#{0}::SetUnmanagedStructures()|Cache already set up. (Called twice?)", ValidationHelper.HashString(this)); if (!m_UseOverlappedIO && !m_DisableOverlapped) { m_Cache = overlappedCache == null ? null : Interlocked.Exchange(ref overlappedCache, null); // Need to hold on to the unmanaged structures until the cache is extracted. m_CleanupCount++; } #endif } // // This method pins unmanaged objects for Win9x and systems where completion ports are not found // protected void PinUnmanagedObjects(object objectsToPin) { if (m_Cache != null) { m_Cache.Free(); m_Cache = null; } if (objectsToPin != null) { if (objectsToPin.GetType() == typeof(object[])) { object [] objectsArray = (object []) objectsToPin; m_GCHandles = new GCHandle[objectsArray.Length]; for (int i=0; i (ref m_Cache, null); if (cache != null) { // If overlappedCache is null, just slap it in there. There's a chance for a conflict, // resulting in a OverlappedCache getting finalized, but it's better than // the interlocked. This won't be an issue in most 'correct' cases. if (overlappedCache == null) { overlappedCache = cache; } else { OverlappedCache oldCache = Interlocked.Exchange (ref overlappedCache, cache); if (oldCache != null) { oldCache.Free(); } } } ReleaseUnmanagedStructures(); } #endif } private unsafe static void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { #if DEBUG GlobalLog.SetThreadSource(ThreadKinds.CompletionPort); using (GlobalLog.SetThreadKind(ThreadKinds.System)) { #if TRAVE try { #endif #endif // // Create an Overlapped object out of the native pointer we're provided with. // (this will NOT free the unmanaged memory in the native overlapped structure) // Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)callbackOverlapped.AsyncResult; // The AsyncResult must be cleared before the callback is called (i.e. before ExtractCache is called). // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object, // which points to the Socket (as well as user data), which points to the OverlappedCache, preventing the OverlappedCache // finalizer from freeing the pinned OverlappedData. callbackOverlapped.AsyncResult = null; object returnObject = null; GlobalLog.Assert(!asyncResult.InternalPeekCompleted, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|asyncResult.IsCompleted", ValidationHelper.HashString(asyncResult)); GlobalLog.Print("BaseOverlappedAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::CompletionPortCallback" + " errorCode:" + errorCode.ToString() + " numBytes:" + numBytes.ToString() + " pOverlapped:" + ((int)nativeOverlapped).ToString()); // // complete the IO and invoke the user's callback // SocketError socketError = (SocketError)errorCode; if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) { // There are cases where passed errorCode does not reflect the details of the underlined socket error. // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may // be other differences as well." Socket socket = asyncResult.AsyncObject as Socket; if (socket == null) { socketError = SocketError.NotSocket; } else if (socket.CleanedUp) { socketError = SocketError.OperationAborted; } else { try { // // The Async IO completed with a failure. // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error. // SocketFlags ignore; bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult( socket.SafeHandle, (IntPtr)nativeOverlapped, out numBytes, false, out ignore); if (!success) { socketError = (SocketError)Marshal.GetLastWin32Error(); GlobalLog.Assert(socketError != 0, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|socketError:0 numBytes:{1}", ValidationHelper.HashString(asyncResult), numBytes); } GlobalLog.Assert(!success, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|Unexpectedly succeeded. errorCode:{1} numBytes:{2}", ValidationHelper.HashString(asyncResult), errorCode, numBytes); } // CleanedUp check above does not always work since this code is subject to race conditions catch (ObjectDisposedException) { socketError = SocketError.OperationAborted; } } } asyncResult.ErrorCode = (int)socketError; returnObject = asyncResult.PostCompletion((int)numBytes); asyncResult.ReleaseUnmanagedStructures(); asyncResult.InvokeCallback(returnObject); #if DEBUG #if TRAVE } catch(Exception exception) { if (!NclUtilities.IsFatal(exception)){ GlobalLog.Assert("BaseOverlappedAsyncResult::CompletionPortCallback", "Exception in completion callback type:" + exception.GetType().ToString() + " message:" + exception.Message); } throw; } #endif } #endif } // // The overlapped function called (either by the thread pool or the socket) // when IO completes. (only called on Win9x) // private void OverlappedCallback(object stateObject, bool Signaled) { #if DEBUG // GlobalLog.SetThreadSource(ThreadKinds.Worker); Because of change 1077887, need logic to determine thread type here. using (GlobalLog.SetThreadKind(ThreadKinds.System)) { #endif BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)stateObject; GlobalLog.Assert(!asyncResult.InternalPeekCompleted, "AcceptOverlappedAsyncResult#{0}::OverlappedCallback()|asyncResult.IsCompleted", ValidationHelper.HashString(asyncResult)); // // the IO completed asynchronously, see if there was a failure the Internal // field in the Overlapped structure will be non zero. to optimize the non // error case, we look at it without calling WSAGetOverlappedResult(). // uint errorCode = (uint)Marshal.ReadInt32(IntPtrHelper.Add(asyncResult.m_UnmanagedBlob.DangerousGetHandle(), Win32.OverlappedInternalOffset)); uint numBytes = errorCode!=0 ? unchecked((uint)-1) : (uint)Marshal.ReadInt32(IntPtrHelper.Add(asyncResult.m_UnmanagedBlob.DangerousGetHandle(), Win32.OverlappedInternalHighOffset)); // // this will release the unmanaged pin handles and unmanaged overlapped ptr // asyncResult.ErrorCode = (int)errorCode; object returnObject = asyncResult.PostCompletion((int)numBytes); asyncResult.ReleaseUnmanagedStructures(); asyncResult.InvokeCallback(returnObject); #if DEBUG } #endif } #if DEBUG private SocketError m_SavedErrorCode = unchecked((SocketError) 0xDEADBEEF); private NativeOverlapped m_InitialNativeOverlapped; private NativeOverlapped m_IntermediateNativeOverlapped; #endif // // This method is called after an asynchronous call is made for the user, // it checks and acts accordingly if the IO: // 1) completed synchronously. // 2) was pended. // 3) failed. // internal unsafe SocketError CheckAsyncCallOverlappedResult(SocketError errorCode) { #if DEBUG m_SavedErrorCode = errorCode; #endif // // Check if the Async IO call: // 1) was pended. // 2) completed synchronously. // 3) failed. // if (m_UseOverlappedIO) { // // we're using overlapped IO under Win9x (or NT with registry setting overriding // completion port usage) // switch (errorCode) { case 0: case SocketError.IOPending: // // the Async IO call was pended: // Queue our event to the thread pool. // GlobalLog.Assert(m_UnmanagedBlob != null, "BaseOverlappedAsyncResult#{0}::CheckAsyncCallOverlappedResult()|Unmanaged blob isn't allocated.", ValidationHelper.HashString(this)); ThreadPool.UnsafeRegisterWaitForSingleObject( m_OverlappedEvent, new WaitOrTimerCallback(OverlappedCallback), this, -1, true ); // // we're done, completion will be asynchronous // in the callback. return // return SocketError.Success; default: // // the Async IO call failed: // set the number of bytes transferred to -1 (error) // ErrorCode = (int)errorCode; Result = -1; ReleaseUnmanagedStructures(); break; } } else { #if DEBUG OverlappedCache cache = m_Cache; if (cache != null) unsafe { NativeOverlapped* nativeOverlappedPtr = (NativeOverlapped *) cache.NativeOverlapped; if (nativeOverlappedPtr != null) m_IntermediateNativeOverlapped = *nativeOverlappedPtr; } #endif // // We're using completion ports under WinNT. Release one reference on the structures for // the main thread. // ReleaseUnmanagedStructures(); switch (errorCode) { // // ignore cases in which a completion packet will be queued: // we'll deal with this IO in the callback // case 0: case SocketError.IOPending: // // ignore, do nothing // return SocketError.Success; // // in the remaining cases a completion packet will NOT be queued: // we'll have to call the callback explicitly signaling an error // default: // // call the callback with error code // ErrorCode = (int)errorCode; Result = -1; // The AsyncResult must be cleared since the callback isn't going to be called. // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object, // which points to the Socket (as well as user data) and to the OverlappedCache, preventing the OverlappedCache // finalizer from freeing the pinned OverlappedData. if (m_Cache != null) { // Could be null only if SetUnmanagedStructures weren't called. m_Cache.Overlapped.AsyncResult = null; } ReleaseUnmanagedStructures(); // Additional release for the completion that won't happen. break; } } return errorCode; } // // The following property returns the Win32 unsafe pointer to // whichever Overlapped structure we're using for IO. // internal unsafe IntPtr OverlappedHandle { get { if (m_UseOverlappedIO) { // // on Win9x we allocate our own overlapped structure // and we use a win32 event for IO completion // return the native pointer to unmanaged memory // return (m_UnmanagedBlob == null || m_UnmanagedBlob.IsInvalid)? IntPtr.Zero: m_UnmanagedBlob.DangerousGetHandle(); } else { // // on WinNT we need to use (due to the current implementation) // an Overlapped object in order to bind the socket to the // ThreadPool's completion port, so return the native handle // return m_Cache == null ? IntPtr.Zero : m_Cache.NativeOverlapped; } } } // OverlappedHandle private void ReleaseUnmanagedStructures() { if (Interlocked.Decrement(ref m_CleanupCount) == 0) { ForceReleaseUnmanagedStructures(); } } protected override void Cleanup() { base.Cleanup(); // If we get all the way to here and it's still not cleaned up... if (m_CleanupCount > 0 && Interlocked.Exchange(ref m_CleanupCount, 0) > 0) { ForceReleaseUnmanagedStructures(); } } // Utility cleanup routine. Frees the overlapped structure. // This should be overriden to free pinned and unmanaged memory in the subclass. // It needs to also be invoked from the subclass. protected virtual void ForceReleaseUnmanagedStructures() { // // free the unmanaged memory if allocated. // ReleaseGCHandles(); GC.SuppressFinalize(this); if (m_UnmanagedBlob != null && !m_UnmanagedBlob.IsInvalid) { m_UnmanagedBlob.Close(true); m_UnmanagedBlob = null; } // This is interlocked because Cleanup() can be called simultaneously with ExtractCache(). OverlappedCache.InterlockedFree(ref m_Cache); if (m_OverlappedEvent != null) { m_OverlappedEvent.Close(); m_OverlappedEvent = null; } } ~BaseOverlappedAsyncResult() { ReleaseGCHandles(); } private void ReleaseGCHandles() { GCHandle[] gcHandles = m_GCHandles; if (gcHandles != null) { for (int i = 0; i < gcHandles.Length; i++) { if (gcHandles[i].IsAllocated) { gcHandles[i].Free(); } } } } } internal class OverlappedCache { internal Overlapped m_Overlapped; internal IntPtr m_NativeOverlapped; internal object m_PinnedObjects; internal object[] m_PinnedObjectsArray; internal OverlappedCache(Overlapped overlapped, object[] pinnedObjectsArray, IOCompletionCallback callback) { m_Overlapped = overlapped; m_PinnedObjects = pinnedObjectsArray; m_PinnedObjectsArray = pinnedObjectsArray; unsafe { m_NativeOverlapped = (IntPtr) overlapped.UnsafePack(callback, pinnedObjectsArray); } } internal OverlappedCache(Overlapped overlapped, object pinnedObjects, IOCompletionCallback callback, bool alreadyTriedCast) { m_Overlapped = overlapped; m_PinnedObjects = pinnedObjects; m_PinnedObjectsArray = alreadyTriedCast ? null : NclConstants.EmptyObjectArray; unsafe { m_NativeOverlapped = (IntPtr) overlapped.UnsafePack(callback, pinnedObjects); } } internal Overlapped Overlapped { get { return m_Overlapped; } } internal IntPtr NativeOverlapped { get { return m_NativeOverlapped; } } internal object PinnedObjects { get { return m_PinnedObjects; } } internal object[] PinnedObjectsArray { get { object[] pinnedObjectsArray = m_PinnedObjectsArray; if (pinnedObjectsArray != null && pinnedObjectsArray.Length == 0) { pinnedObjectsArray = m_PinnedObjects as object[]; if (pinnedObjectsArray != null && pinnedObjectsArray.Length == 0) { m_PinnedObjectsArray = null; } else { m_PinnedObjectsArray = pinnedObjectsArray; } } return m_PinnedObjectsArray; } } // This must only be called once. internal void Free() { InternalFree(); GC.SuppressFinalize(this); } private void InternalFree() { m_Overlapped = null; m_PinnedObjects = null; if (m_NativeOverlapped != IntPtr.Zero) { unsafe { Overlapped.Free((NativeOverlapped*) m_NativeOverlapped); } m_NativeOverlapped = IntPtr.Zero; } } internal static void InterlockedFree(ref OverlappedCache overlappedCache) { OverlappedCache cache = overlappedCache == null ? null : Interlocked.Exchange (ref overlappedCache, null); if (cache != null) { cache.Free(); } } ~OverlappedCache() { if (!NclUtilities.HasShutdownStarted) { InternalFree(); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataGridDefaultColumnWidthTypeConverter.cs
- VisualTreeHelper.cs
- DbParameterCollectionHelper.cs
- codemethodreferenceexpression.cs
- ToolboxBitmapAttribute.cs
- AnnotationMap.cs
- DateRangeEvent.cs
- HelpKeywordAttribute.cs
- SchemaTableOptionalColumn.cs
- WhereQueryOperator.cs
- __Filters.cs
- ReturnType.cs
- Misc.cs
- CellTreeNodeVisitors.cs
- DiscreteKeyFrames.cs
- HttpModuleAction.cs
- TextEvent.cs
- MessageBox.cs
- OletxVolatileEnlistment.cs
- AppDomainResourcePerfCounters.cs
- UrlPath.cs
- ListControl.cs
- TextUtf8RawTextWriter.cs
- Point3DCollectionValueSerializer.cs
- BinaryNode.cs
- CompoundFileStorageReference.cs
- LoadItemsEventArgs.cs
- AttributeAction.cs
- HMACSHA512.cs
- TypedTableGenerator.cs
- KeyTimeConverter.cs
- VectorAnimationBase.cs
- InfoCardService.cs
- IgnoreFileBuildProvider.cs
- SamlSerializer.cs
- GlyphRun.cs
- CreateUserErrorEventArgs.cs
- FontStyles.cs
- CodeThrowExceptionStatement.cs
- SiteMapSection.cs
- keycontainerpermission.cs
- IEnumerable.cs
- ServiceEndpoint.cs
- WebPartPersonalization.cs
- MessageBuilder.cs
- ToolStripManager.cs
- UInt32Converter.cs
- OuterGlowBitmapEffect.cs
- AsyncOperation.cs
- HttpApplicationStateWrapper.cs
- CellParaClient.cs
- XPathNodeList.cs
- Rights.cs
- DictionaryContent.cs
- LicenseManager.cs
- TargetConverter.cs
- precedingquery.cs
- HitTestParameters.cs
- Rect3DValueSerializer.cs
- MulticastDelegate.cs
- DataGridViewSelectedRowCollection.cs
- TextBox.cs
- DurableServiceAttribute.cs
- BitmapCacheBrush.cs
- WmpBitmapDecoder.cs
- ComponentResourceManager.cs
- SiteMapPath.cs
- SoapIgnoreAttribute.cs
- SQLResource.cs
- AutoCompleteStringCollection.cs
- AccessDataSource.cs
- EventLogQuery.cs
- ConfigXmlCDataSection.cs
- FixedTextContainer.cs
- PropertyInfoSet.cs
- DataControlPagerLinkButton.cs
- RuntimeComponentFilter.cs
- Vector3dCollection.cs
- RectangleConverter.cs
- HtmlToClrEventProxy.cs
- ChannelManagerService.cs
- ObjectStateFormatter.cs
- GeometryHitTestResult.cs
- GatewayIPAddressInformationCollection.cs
- WindowsGraphicsWrapper.cs
- StrokeNodeOperations2.cs
- ScrollItemPatternIdentifiers.cs
- DataGridViewCellLinkedList.cs
- CodeMemberEvent.cs
- ManipulationDevice.cs
- TextFindEngine.cs
- HierarchicalDataSourceControl.cs
- activationcontext.cs
- KeyFrames.cs
- PeerCustomResolverBindingElement.cs
- PersonalizableTypeEntry.cs
- GACIdentityPermission.cs
- RemotingSurrogateSelector.cs
- SafeNativeMethods.cs
- QueryOpeningEnumerator.cs