AsyncResult.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 / cdf / src / System.Runtime.DurableInstancing / System / Runtime / AsyncResult.cs / 1305376 / AsyncResult.cs

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

namespace System.Runtime 
{
    using System; 
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis;
    using System.Threading; 
    using System.Transactions;

    // AsyncResult starts acquired; Complete releases.
    [Fx.Tag.SynchronizationPrimitive(Fx.Tag.BlocksUsing.ManualResetEvent, SupportsAsync = true, ReleaseMethod = "Complete")] 
    abstract class AsyncResult : IAsyncResult
    { 
        static AsyncCallback asyncCompletionWrapperCallback; 
        AsyncCallback callback;
        bool completedSynchronously; 
        bool endCalled;
        Exception exception;
        bool isCompleted;
        AsyncCompletion nextAsyncCompletion; 
        IAsyncResult deferredTransactionalResult;
        TransactionSignalScope transactionContext; 
        object state; 

        [Fx.Tag.SynchronizationObject] 
        ManualResetEvent manualResetEvent;

        [Fx.Tag.SynchronizationObject(Blocking = false)]
        object thisLock; 

#if DEBUG 
        StackTrace endStack; 
        StackTrace completeStack;
        UncompletedAsyncResultMarker marker; 
#endif

        protected AsyncResult(AsyncCallback callback, object state)
        { 
            this.callback = callback;
            this.state = state; 
            this.thisLock = new object(); 

#if DEBUG 
            this.marker = new UncompletedAsyncResultMarker(this);
#endif
        }
 
        public object AsyncState
        { 
            get 
            {
                return state; 
            }
        }

        public WaitHandle AsyncWaitHandle 
        {
            get 
            { 
                if (manualResetEvent != null)
                { 
                    return manualResetEvent;
                }

                lock (ThisLock) 
                {
                    if (manualResetEvent == null) 
                    { 
                        manualResetEvent = new ManualResetEvent(isCompleted);
                    } 
                }

                return manualResetEvent;
            } 
        }
 
        public bool CompletedSynchronously 
        {
            get 
            {
                return completedSynchronously;
            }
        } 

        public bool HasCallback 
        { 
            get
            { 
                return this.callback != null;
            }
        }
 
        public bool IsCompleted
        { 
            get 
            {
                return isCompleted; 
            }
        }

        // used in conjunction with PrepareAsyncCompletion to allow for finally blocks 
        protected Action OnCompleting { get; set; }
 
        object ThisLock 
        {
            get 
            {
                return this.thisLock;
            }
        } 

        // subclasses like TraceAsyncResult can use this to wrap the callback functionality in a scope 
        protected Action VirtualCallback 
        {
            get; 
            set;
        }

        protected void Complete(bool completedSynchronously) 
        {
            if (this.isCompleted) 
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.AsyncResultCompletedTwice(GetType())));
            } 

#if DEBUG
            this.marker.AsyncResult = null;
            this.marker = null; 
            if (!Fx.FastDebug && completeStack == null)
            { 
                completeStack = new StackTrace(); 
            }
#endif 

            this.completedSynchronously = completedSynchronously;
            if (OnCompleting != null)
            { 
                // Allow exception replacement, like a catch/throw pattern.
                try 
                { 
                    OnCompleting(this, this.exception);
                } 
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    { 
                        throw;
                    } 
                    this.exception = exception; 
                }
            } 

            if (completedSynchronously)
            {
                // If we completedSynchronously, then there's no chance that the manualResetEvent was created so 
                // we don't need to worry about a ----
                Fx.Assert(this.manualResetEvent == null, "No ManualResetEvent should be created for a synchronous AsyncResult."); 
                this.isCompleted = true; 
            }
            else 
            {
                lock (ThisLock)
                {
                    this.isCompleted = true; 
                    if (this.manualResetEvent != null)
                    { 
                        this.manualResetEvent.Set(); 
                    }
                } 
            }

            if (this.callback != null)
            { 
                try
                { 
                    if (VirtualCallback != null) 
                    {
                        VirtualCallback(this.callback, this); 
                    }
                    else
                    {
                        this.callback(this); 
                    }
                } 
#pragma warning disable 1634 
#pragma warning suppress 56500 // transferring exception to another thread
                catch (Exception e) 
                {
                    if (Fx.IsFatal(e))
                    {
                        throw; 
                    }
 
                    throw Fx.Exception.AsError(new CallbackException(SRCore.AsyncCallbackThrewException, e)); 
                }
#pragma warning restore 1634 
            }
        }

        protected void Complete(bool completedSynchronously, Exception exception) 
        {
            this.exception = exception; 
            Complete(completedSynchronously); 
        }
 
        static void AsyncCompletionWrapperCallback(IAsyncResult result)
        {
            if (result == null)
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InvalidNullAsyncResult));
            } 
            if (result.CompletedSynchronously) 
            {
                return; 
            }

            AsyncResult thisPtr = (AsyncResult)result.AsyncState;
 
            if (thisPtr.transactionContext != null && !thisPtr.transactionContext.Signal(result))
            { 
                // The TransactionScope isn't cleaned up yet and can't be done on this thread.  Must defer 
                // the callback (which is likely to attempt to commit the transaction) until later.
                return; 
            }

            AsyncCompletion callback = thisPtr.GetNextCompletion();
            if (callback == null) 
            {
                ThrowInvalidAsyncResult(result); 
            } 

            bool completeSelf = false; 
            Exception completionException = null;
            try
            {
                completeSelf = callback(result); 
            }
            catch (Exception e) 
            { 
                if (Fx.IsFatal(e))
                { 
                    throw;
                }
                completeSelf = true;
                completionException = e; 
            }
 
            if (completeSelf) 
            {
                thisPtr.Complete(false, completionException); 
            }
        }

        protected AsyncCallback PrepareAsyncCompletion(AsyncCompletion callback) 
        {
            if (this.transactionContext != null) 
            { 
                // It might be an old, leftover one, if an exception was thrown within the last using (PrepareTransactionalCall()) block.
                if (this.transactionContext.IsPotentiallyAbandoned) 
                {
                    this.transactionContext = null;
                }
                else 
                {
                    this.transactionContext.Prepared(); 
                } 
            }
 
            this.nextAsyncCompletion = callback;
            if (AsyncResult.asyncCompletionWrapperCallback == null)
            {
                AsyncResult.asyncCompletionWrapperCallback = Fx.ThunkCallback(new AsyncCallback(AsyncCompletionWrapperCallback)); 
            }
            return AsyncResult.asyncCompletionWrapperCallback; 
        } 

        protected IDisposable PrepareTransactionalCall(Transaction transaction) 
        {
            if (this.transactionContext != null && !this.transactionContext.IsPotentiallyAbandoned)
            {
                ThrowInvalidAsyncResult("PrepareTransactionalCall should only be called as the object of non-nested using statements. If the Begin succeeds, Check/SyncContinue must be called before another PrepareTransactionalCall."); 
            }
            return this.transactionContext = transaction == null ? null : new TransactionSignalScope(this, transaction); 
        } 

        protected bool CheckSyncContinue(IAsyncResult result) 
        {
            AsyncCompletion dummy;
            return TryContinueHelper(result, out dummy);
        } 

        protected bool SyncContinue(IAsyncResult result) 
        { 
            AsyncCompletion callback;
            if (TryContinueHelper(result, out callback)) 
            {
                return callback(result);
            }
            else 
            {
                return false; 
            } 
        }
 
        bool TryContinueHelper(IAsyncResult result, out AsyncCompletion callback)
        {
            if (result == null)
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InvalidNullAsyncResult));
            } 
 
            callback = null;
 
            if (result.CompletedSynchronously)
            {
                // Once we pass the check, we know that we own forward progress, so transactionContext is correct. Verify its state.
                if (this.transactionContext != null) 
                {
                    if (this.transactionContext.State != TransactionSignalState.Completed) 
                    { 
                        ThrowInvalidAsyncResult("Check/SyncContinue cannot be called from within the PrepareTransactionalCall using block.");
                    } 
                    else if (this.transactionContext.IsSignalled)
                    {
                        // This is most likely to happen when result.CompletedSynchronously registers differently here and in the callback, which
                        // is the fault of 'result'. 
                        ThrowInvalidAsyncResult(result);
                    } 
                } 
            }
            else if (object.ReferenceEquals(result, this.deferredTransactionalResult)) 
            {
                // The transactionContext may not be current if forward progress has been made via the callback. Instead,
                // use deferredTransactionalResult to see if we are supposed to execute a post-transaction callback.
                // 
                // Once we pass the check, we know that we own forward progress, so transactionContext is correct. Verify its state.
                if (this.transactionContext == null || !this.transactionContext.IsSignalled) 
                { 
                    ThrowInvalidAsyncResult(result);
                } 
                this.deferredTransactionalResult = null;
            }
            else
            { 
                return false;
            } 
 
            callback = GetNextCompletion();
            if (callback == null) 
            {
                ThrowInvalidAsyncResult("Only call Check/SyncContinue once per async operation (once per PrepareAsyncCompletion).");
            }
            return true; 
        }
 
        AsyncCompletion GetNextCompletion() 
        {
            AsyncCompletion result = this.nextAsyncCompletion; 
            this.transactionContext = null;
            this.nextAsyncCompletion = null;
            return result;
        } 

        static void ThrowInvalidAsyncResult(IAsyncResult result) 
        { 
            throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InvalidAsyncResultImplementation(result.GetType())));
        } 

        static void ThrowInvalidAsyncResult(string debugText)
        {
            string message = SRCore.InvalidAsyncResultImplementationGeneric; 
            if (debugText != null)
            { 
#if DEBUG 
                message += " " + debugText;
#endif 
            }
            throw Fx.Exception.AsError(new InvalidOperationException(message));
        }
 
        [Fx.Tag.Blocking(Conditional = "!asyncResult.isCompleted")]
        protected static TAsyncResult End(IAsyncResult result) 
            where TAsyncResult : AsyncResult 
        {
            if (result == null) 
            {
                throw Fx.Exception.ArgumentNull("result");
            }
 
            TAsyncResult asyncResult = result as TAsyncResult;
 
            if (asyncResult == null) 
            {
                throw Fx.Exception.Argument("result", SRCore.InvalidAsyncResult); 
            }

            if (asyncResult.endCalled)
            { 
                throw Fx.Exception.AsError(new InvalidOperationException(SRCore.AsyncResultAlreadyEnded));
            } 
 
#if DEBUG
            if (!Fx.FastDebug && asyncResult.endStack == null) 
            {
                asyncResult.endStack = new StackTrace();
            }
#endif 

            asyncResult.endCalled = true; 
 
            if (!asyncResult.isCompleted)
            { 
                asyncResult.AsyncWaitHandle.WaitOne();
            }

            if (asyncResult.manualResetEvent != null) 
            {
                asyncResult.manualResetEvent.Close(); 
            } 

            if (asyncResult.exception != null) 
            {
                throw Fx.Exception.AsError(asyncResult.exception);
            }
 
            return asyncResult;
        } 
 
        enum TransactionSignalState
        { 
            Ready = 0,
            Prepared,
            Completed,
            Abandoned, 
        }
 
        class TransactionSignalScope : SignalGate, IDisposable 
        {
            TransactionScope transactionScope; 
            AsyncResult parent;

            public TransactionSignalScope(AsyncResult result, Transaction transaction)
            { 
                Fx.Assert(transaction != null, "Null Transaction provided to AsyncResult.TransactionSignalScope.");
                this.parent = result; 
                this.transactionScope = Fx.CreateTransactionScope(transaction); 
            }
 
            public TransactionSignalState State { get; private set; }

            public bool IsPotentiallyAbandoned
            { 
                get
                { 
                    return State == TransactionSignalState.Abandoned || (State == TransactionSignalState.Completed && !IsSignalled); 
                }
            } 

            public void Prepared()
            {
                if (State != TransactionSignalState.Ready) 
                {
                    AsyncResult.ThrowInvalidAsyncResult("PrepareAsyncCompletion should only be called once per PrepareTransactionalCall."); 
                } 
                State = TransactionSignalState.Prepared;
            } 

            void IDisposable.Dispose()
            {
                if (State == TransactionSignalState.Ready) 
                {
                    State = TransactionSignalState.Abandoned; 
                } 
                else if (State == TransactionSignalState.Prepared)
                { 
                    State = TransactionSignalState.Completed;
                }
                else
                { 
                    AsyncResult.ThrowInvalidAsyncResult("PrepareTransactionalCall should only be called in a using. Dispose called multiple times.");
                } 
 
                try
                { 
                    Fx.CompleteTransactionScope(ref this.transactionScope);
                }
                catch (Exception exception)
                { 
                    if (Fx.IsFatal(exception))
                    { 
                        throw; 
                    }
 
                    // Complete and Dispose are not expected to throw.  If they do it can mess up the AsyncResult state machine.
                    throw Fx.Exception.AsError(new InvalidOperationException(SRCore.AsyncTransactionException));
                }
 
                // This will release the callback to run, or tell us that we need to defer the callback to Check/SyncContinue.
                // 
                // It's possible to avoid this Interlocked when CompletedSynchronously is true, but we have no way of knowing that 
                // from here, and adding a way would add complexity to the AsyncResult transactional calling pattern. This
                // unnecessary Interlocked only happens when: PrepareTransactionalCall is called with a non-null transaction, 
                // PrepareAsyncCompletion is reached, and the operation completes synchronously or with an exception.
                IAsyncResult result;
                if (State == TransactionSignalState.Completed && Unlock(out result))
                { 
                    if (this.parent.deferredTransactionalResult != null)
                    { 
                        AsyncResult.ThrowInvalidAsyncResult(this.parent.deferredTransactionalResult); 
                    }
                    this.parent.deferredTransactionalResult = result; 
                }
            }
        }
 
        // can be utilized by subclasses to write core completion code for both the [....] and async paths
        // in one location, signalling chainable synchronous completion with the boolean result, 
        // and leveraging PrepareAsyncCompletion for conversion to an AsyncCallback. 
        // NOTE: requires that "this" is passed in as the state object to the asynchronous sub-call being used with a completion routine.
        protected delegate bool AsyncCompletion(IAsyncResult result); 

#if DEBUG
        class UncompletedAsyncResultMarker
        { 
            public UncompletedAsyncResultMarker(AsyncResult result)
            { 
                AsyncResult = result; 
            }
 
            [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode,
                Justification = "Debug-only facility")]
            public AsyncResult AsyncResult { get; set; }
        } 
#endif
    } 
} 

// 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