_BaseOverlappedAsyncResult.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / Sockets / _BaseOverlappedAsyncResult.cs / 1305376 / _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.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK