OverlappedContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / OverlappedContext.cs / 1 / OverlappedContext.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.ServiceModel.Channels 
{
    using System.Threading; 
    using System.Diagnostics; 
    using System.ServiceModel.Diagnostics;
    using System.Runtime.InteropServices; 


    delegate void OverlappedIOCompleteCallback(bool haveResult, int error, int bytesRead);
 
    unsafe class OverlappedContext
    { 
        const int HandleOffsetFromOverlapped32 = -4; 
        const int HandleOffsetFromOverlapped64 = -3;
 
        static IOCompletionCallback completeCallback;
        static WaitOrTimerCallback eventCallback;
        static WaitOrTimerCallback cleanupCallback;
        static byte[] dummyBuffer = new byte[0]; 

        object[] bufferHolder; 
        byte* bufferPtr; 
        NativeOverlapped* nativeOverlapped;
        GCHandle pinnedHandle; 
        object pinnedTarget;
        Overlapped overlapped;
        RootedHolder rootedHolder;
        OverlappedIOCompleteCallback pendingCallback;  // Null when no async I/O is pending. 
        bool deferredFree;
        bool syncOperationPending; 
        ManualResetEvent completionEvent; 
        IntPtr eventHandle;
 
        // Only used by unbound I/O.
        RegisteredWaitHandle registration;

#if DEBUG_EXPENSIVE 
        StackTrace freeStack;
#endif 
 

        public OverlappedContext() 
        {
            if (OverlappedContext.completeCallback == null)
            {
                OverlappedContext.completeCallback = DiagnosticUtility.Utility.ThunkCallback(new IOCompletionCallback(CompleteCallback)); 
            }
            if (OverlappedContext.eventCallback == null) 
            { 
                OverlappedContext.eventCallback = DiagnosticUtility.Utility.ThunkCallback(new WaitOrTimerCallback(EventCallback));
            } 
            if (OverlappedContext.cleanupCallback == null)
            {
                OverlappedContext.cleanupCallback = DiagnosticUtility.Utility.ThunkCallback(new WaitOrTimerCallback(CleanupCallback));
            } 

            this.bufferHolder = new object[] { OverlappedContext.dummyBuffer }; 
            this.overlapped = new Overlapped(); 
            this.nativeOverlapped = this.overlapped.UnsafePack(OverlappedContext.completeCallback, this.bufferHolder);
 
            // When replacing the buffer, we need to provoke the CLR to fix up the handle of the pin.
            this.pinnedHandle = GCHandle.FromIntPtr(*((IntPtr*) nativeOverlapped +
                (IntPtr.Size == 4 ? HandleOffsetFromOverlapped32 : HandleOffsetFromOverlapped64)));
            this.pinnedTarget = this.pinnedHandle.Target; 

            // Create the permanently rooted holder and put it in the Overlapped. 
            this.rootedHolder = new RootedHolder(); 
            this.overlapped.AsyncResult = rootedHolder;
        } 

        ~OverlappedContext()
        {
            if (this.nativeOverlapped != null && !AppDomain.CurrentDomain.IsFinalizingForUnload() && !Environment.HasShutdownStarted) 
            {
                if (this.syncOperationPending) 
                { 
                    DiagnosticUtility.DebugAssert(this.rootedHolder != null, "rootedHolder null in Finalize.");
                    DiagnosticUtility.DebugAssert(this.rootedHolder.EventHolder != null, "rootedHolder.EventHolder null in Finalize."); 
                    DiagnosticUtility.DebugAssert(OverlappedContext.cleanupCallback != null, "cleanupCallback null in Finalize.");

                    // Can't free the overlapped.  Register a callback to deal with this.
                    // This will ressurect the OverlappedContext. 
                    // The completionEvent will still be alive (not finalized) since it's rooted by the pending Overlapped in the holder.
                    // We own it now and will close it in the callback. 
                    ThreadPool.UnsafeRegisterWaitForSingleObject(this.rootedHolder.EventHolder, OverlappedContext.cleanupCallback, this, Timeout.Infinite, true); 
                }
                else 
                {
                    Overlapped.Free(this.nativeOverlapped);
                }
            } 
        }
 
        // None of the OverlappedContext methods are threadsafe. 
        // Free or FreeOrDefer can only be called once.  FreeIfDeferred can be called any number of times, as long as it's only
        // called once after FreeOrDefer. 
        public void Free()
        {
            if (this.pendingCallback != null)
            { 
                DiagnosticUtility.DebugAssert("OverlappedContext.Free called while async operation is pending.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            } 
            if (this.syncOperationPending)
            { 
                DiagnosticUtility.DebugAssert("OverlappedContext.Free called while sync operation is pending.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            }
            if (this.nativeOverlapped == null) 
            {
                DiagnosticUtility.DebugAssert("OverlappedContext.Free called multiple times."); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }
 
#if DEBUG_EXPENSIVE
            this.freeStack = new StackTrace();
#endif
 
            NativeOverlapped* nativePtr = this.nativeOverlapped;
            this.nativeOverlapped = null; 
            Overlapped.Free(nativePtr); 

            if (this.completionEvent != null) 
            {
                this.completionEvent.Close();
            }
 
            GC.SuppressFinalize(this);
        } 
 
        public void FreeOrDefer()
        { 
            if (this.pendingCallback != null || this.syncOperationPending)
            {
                this.deferredFree = true;
            } 
            else
            { 
                Free(); 
            }
        } 

        public void FreeIfDeferred()
        {
            if (this.deferredFree) 
            {
                FreeOrDefer(); 
            } 
        }
 
        public void StartAsyncOperation(byte[] buffer, OverlappedIOCompleteCallback callback, bool bound)
        {
            if (callback == null)
            { 
                DiagnosticUtility.DebugAssert("StartAsyncOperation called with null callback.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            } 
            if (this.pendingCallback != null)
            { 
                DiagnosticUtility.DebugAssert("StartAsyncOperation called while another is in progress.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            }
            if (this.syncOperationPending) 
            {
                DiagnosticUtility.DebugAssert("StartAsyncOperation called while a sync operation was already pending."); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }
            if (this.nativeOverlapped == null) 
            {
                DiagnosticUtility.DebugAssert("StartAsyncOperation called on freed OverlappedContext.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            } 

            this.pendingCallback = callback; 
 
            if (buffer != null)
            { 
                DiagnosticUtility.DebugAssert(object.ReferenceEquals(this.bufferHolder[0], OverlappedContext.dummyBuffer), "StartAsyncOperation: buffer holder corrupted.");
                this.bufferHolder[0] = buffer;
                this.pinnedHandle.Target = this.pinnedTarget;
                this.bufferPtr = (byte*) Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); 
            }
 
            if (bound) 
            {
                this.overlapped.EventHandleIntPtr = IntPtr.Zero; 

                // For completion ports, the back-reference is this member.
                this.rootedHolder.ThisHolder = this;
            } 
            else
            { 
                // Need to do this since we register the wait before posting the I/O. 
                if (this.completionEvent != null)
                { 
                    this.completionEvent.Reset();
                }

                this.overlapped.EventHandleIntPtr = EventHandle; 

                // For unbound, the back-reference is this registration. 
                this.registration = ThreadPool.UnsafeRegisterWaitForSingleObject(this.completionEvent, OverlappedContext.eventCallback, this, Timeout.Infinite, true); 
            }
        } 

        public void CancelAsyncOperation()
        {
            this.rootedHolder.ThisHolder = null; 
            if (this.registration != null)
            { 
                this.registration.Unregister(null); 
                this.registration = null;
            } 
            this.bufferPtr = null;
            this.bufferHolder[0] = OverlappedContext.dummyBuffer;
            this.pendingCallback = null;
        } 

        //  public void StartSyncOperation(byte[] buffer) 
        //  { 
        //      StartSyncOperation(buffer, ref this.bufferHolder[0], false);
        //  } 

        // The only holder allowed is Holder[0].  It can be passed in as a ref to prevent repeated expensive array lookups.
        public void StartSyncOperation(byte[] buffer, ref object holder)
        { 
            if (this.syncOperationPending)
            { 
                DiagnosticUtility.DebugAssert("StartSyncOperation called while an operation was already pending."); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            } 
            if (this.pendingCallback != null)
            {
                DiagnosticUtility.DebugAssert("StartSyncOperation called while an async operation was already pending.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }
            if (this.nativeOverlapped == null) 
            { 
                DiagnosticUtility.DebugAssert("StartSyncOperation called on freed OverlappedContext.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }

            this.overlapped.EventHandleIntPtr = EventHandle;
 
            // Sync operations do NOT root this object.  If it gets finalized, we need to know not to free the buffer.
            // We do root the event. 
            this.rootedHolder.EventHolder = this.completionEvent; 
            this.syncOperationPending = true;
 
            if (buffer != null)
            {
                DiagnosticUtility.DebugAssert(object.ReferenceEquals(holder, OverlappedContext.dummyBuffer), "StartSyncOperation: buffer holder corrupted.");
                holder = buffer; 
                this.pinnedHandle.Target = this.pinnedTarget;
                this.bufferPtr = (byte*) Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); 
            } 
        }
 
        // If this returns false, the OverlappedContext is no longer usable.  It shouldn't be freed or anything.
        public bool WaitForSyncOperation(TimeSpan timeout)
        {
            return WaitForSyncOperation(timeout, ref this.bufferHolder[0]); 
        }
 
        // The only holder allowed is Holder[0].  It can be passed in as a ref to prevent repeated expensive array lookups. 
        public bool WaitForSyncOperation(TimeSpan timeout, ref object holder)
        { 
            if (!this.syncOperationPending)
            {
                DiagnosticUtility.DebugAssert("WaitForSyncOperation called while no operation was pending.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }
 
            if (!UnsafeNativeMethods.HasOverlappedIoCompleted(this.nativeOverlapped)) 
            {
                if (!TimeoutHelper.WaitOne(this.completionEvent, timeout, false)) 
                {
                    // We can't free ourselves until the operation is done.  The only way to do that is register a callback.
                    // This will root the object.  No longer any need for the finalizer.  This instance is unusable after this.
                    GC.SuppressFinalize(this); 
                    ThreadPool.UnsafeRegisterWaitForSingleObject(this.completionEvent, OverlappedContext.cleanupCallback, this, Timeout.Infinite, true);
                    return false; 
                } 
            }
 
            DiagnosticUtility.DebugAssert(this.bufferPtr == null || this.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) holder, 0),
                "The buffer moved during a sync call!");

            CancelSyncOperation(ref holder); 
            return true;
        } 
 
        //  public void CancelSyncOperation()
        //  { 
        //      CancelSyncOperation(ref this.bufferHolder[0]);
        //  }

        // The only holder allowed is Holder[0].  It can be passed in as a ref to prevent repeated expensive array lookups. 
        public void CancelSyncOperation(ref object holder)
        { 
            this.bufferPtr = null; 
            holder = OverlappedContext.dummyBuffer;
            DiagnosticUtility.DebugAssert(object.ReferenceEquals(this.bufferHolder[0], OverlappedContext.dummyBuffer), "Bad holder passed to CancelSyncOperation."); 

            this.syncOperationPending = false;
            this.rootedHolder.EventHolder = null;
        } 

        // This should ONLY be used to make a 'ref object' parameter to the zeroth element, to prevent repeated expensive array lookups. 
        public object[] Holder 
        {
            get 
            {
                return this.bufferHolder;
            }
        } 

        public byte* BufferPtr 
        { 
            get
            { 
                byte* ptr = this.bufferPtr;
                if (ptr == null)
                {
                    DiagnosticUtility.DebugAssert("Pointer requested while no operation pending or no buffer provided."); 
#pragma warning suppress 56503 // [....], not a publicly accessible API
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                } 
                return ptr;
            } 
        }

        public NativeOverlapped* NativeOverlapped
        { 
            get
            { 
                NativeOverlapped* ptr = this.nativeOverlapped; 
                if (ptr == null)
                { 
                    DiagnosticUtility.DebugAssert("NativeOverlapped pointer requested after it was freed.");
#pragma warning suppress 56503 // [....], not a publicly accessible API
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                } 
                return ptr;
            } 
        } 

        IntPtr EventHandle 
        {
            get
            {
                if (this.completionEvent == null) 
                {
                    this.completionEvent = new ManualResetEvent(false); 
                    this.eventHandle = (IntPtr) (1 | (long) this.completionEvent.SafeWaitHandle.DangerousGetHandle()); 
                }
                return this.eventHandle; 
            }
        }

        static void CompleteCallback(uint error, uint numBytes, NativeOverlapped* nativeOverlapped) 
        {
            // Empty out the AsyncResult ASAP to close the leak window. 
            Overlapped overlapped = Overlapped.Unpack(nativeOverlapped); 
            OverlappedContext pThis = ((RootedHolder) overlapped.AsyncResult).ThisHolder;
            DiagnosticUtility.DebugAssert(pThis != null, "Overlapped.AsyncResult not set. I/O completed multiple times, or cancelled I/O completed."); 
            DiagnosticUtility.DebugAssert(object.ReferenceEquals(pThis.overlapped, overlapped), "CompleteCallback completed with corrupt OverlappedContext.overlapped.");
            DiagnosticUtility.DebugAssert(object.ReferenceEquals(pThis.rootedHolder, overlapped.AsyncResult), "CompleteCallback completed with corrupt OverlappedContext.rootedHolder.");
            pThis.rootedHolder.ThisHolder = null;
 
            DiagnosticUtility.DebugAssert(pThis.bufferPtr == null || pThis.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) pThis.bufferHolder[0], 0),
                "Buffer moved during bound async operation!"); 
 
            // Release the pin.
            pThis.bufferPtr = null; 
            pThis.bufferHolder[0] = OverlappedContext.dummyBuffer;

            OverlappedIOCompleteCallback callback = pThis.pendingCallback;
            pThis.pendingCallback = null; 
            DiagnosticUtility.DebugAssert(callback != null, "PendingCallback not set. I/O completed multiple times, or cancelled I/O completed.");
 
            callback(true, (int) error, checked((int) numBytes)); 
        }
 
        static void EventCallback(object state, bool timedOut)
        {
            OverlappedContext pThis = state as OverlappedContext;
            DiagnosticUtility.DebugAssert(pThis != null, "OverlappedContext.EventCallback registered wait doesn't have an OverlappedContext as state."); 

            if (timedOut) 
            { 
                DiagnosticUtility.DebugAssert("OverlappedContext.EventCallback registered wait timed out.");
 
                // Turn this into a leak.  Don't let ourselves get cleaned up - could scratch the heap.
                if (pThis == null || pThis.rootedHolder == null)
                {
                    // We're doomed to do a wild write and corrupt the process. 
                    DiagnosticUtility.FailFast("Can't prevent heap corruption.");
                } 
                pThis.rootedHolder.ThisHolder = pThis; 
                return;
            } 

            pThis.registration = null;

            DiagnosticUtility.DebugAssert(pThis.bufferPtr == null || pThis.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) pThis.bufferHolder[0], 0), 
                "Buffer moved during unbound async operation!");
 
            // Release the pin. 
            pThis.bufferPtr = null;
            pThis.bufferHolder[0] = OverlappedContext.dummyBuffer; 

            OverlappedIOCompleteCallback callback = pThis.pendingCallback;
            pThis.pendingCallback = null;
            DiagnosticUtility.DebugAssert(callback != null, "PendingCallback not set. I/O completed multiple times, or cancelled I/O completed."); 

            callback(false, 0, 0); 
        } 

        static void CleanupCallback(object state, bool timedOut) 
        {
            OverlappedContext pThis = state as OverlappedContext;
            DiagnosticUtility.DebugAssert(pThis != null, "OverlappedContext.CleanupCallback registered wait doesn't have an OverlappedContext as state.");
 
            if (timedOut)
            { 
                DiagnosticUtility.DebugAssert("OverlappedContext.CleanupCallback registered wait timed out."); 

                // Turn this into a leak. 
                return;
            }

            DiagnosticUtility.DebugAssert(pThis.bufferPtr == null || pThis.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) pThis.bufferHolder[0], 0), 
                "Buffer moved during synchronous deferred cleanup!");
 
            DiagnosticUtility.DebugAssert(pThis.syncOperationPending, "OverlappedContext.CleanupCallback called with no sync operation pending."); 
            pThis.rootedHolder.EventHolder.Close();
            Overlapped.Free(pThis.nativeOverlapped); 
        }

        // This class is always held onto (rooted) by the packed Overlapped.  The OverlappedContext instance moves itself in and out of
        // this object to root itself.  It's also used to root the ManualResetEvent during sync operations. 
        // It needs to be an IAsyncResult since that's what Overlapped takes.
        class RootedHolder : IAsyncResult 
        { 
            OverlappedContext overlappedBuffer;
            ManualResetEvent eventHolder; 


            public OverlappedContext ThisHolder
            { 
                get
                { 
                    return this.overlappedBuffer; 
                }
 
                set
                {
                    this.overlappedBuffer = value;
                } 
            }
 
            public ManualResetEvent EventHolder 
            {
                get 
                {
                    return this.eventHolder;
                }
 
                set
                { 
                    this.eventHolder = value; 
                }
            } 


            // Unused IAsyncResult implementation.
            object IAsyncResult.AsyncState 
            {
                get 
                { 
                    DiagnosticUtility.DebugAssert("RootedHolder.AsyncState called.");
#pragma warning suppress 56503 // [....], not a publicly accessible API 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                }
            }
 
            WaitHandle IAsyncResult.AsyncWaitHandle
            { 
                get 
                {
                    DiagnosticUtility.DebugAssert("RootedHolder.AsyncWaitHandle called."); 
#pragma warning suppress 56503 // [....], not a publicly accessible API
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                }
            } 

            bool IAsyncResult.CompletedSynchronously 
            { 
                get
                { 
                    DiagnosticUtility.DebugAssert("RootedHolder.CompletedSynchronously called.");
#pragma warning suppress 56503 // [....], not a publicly accessible API
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                } 
            }
 
            bool IAsyncResult.IsCompleted 
            {
                get 
                {
                    DiagnosticUtility.DebugAssert("RootedHolder.IsCompleted called.");
#pragma warning suppress 56503 // [....], not a publicly accessible API
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                }
            } 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

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