ActivityExecutor.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 / NetFx40 / System.Activities / System / Activities / Runtime / ActivityExecutor.cs / 1305376 / ActivityExecutor.cs

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

namespace System.Activities.Runtime 
{
    using System; 
    using System.Activities.Debugger; 
    using System.Activities.Hosting;
    using System.Activities.Tracking; 
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime; 
    using System.Runtime.Diagnostics;
    using System.Runtime.DurableInstancing; 
    using System.Runtime.Serialization; 
    using System.Security;
    using System.Threading; 
    using System.Transactions;

    [DataContract(Name = XD.Executor.Name, Namespace = XD.Runtime.Namespace)]
    class ActivityExecutor : IEnlistmentNotification 
    {
        static ReadOnlyCollection emptyBookmarkInfoCollection; 
 
        [DataMember(Name = XD.Executor.BookmarkManager, EmitDefaultValue = false)]
        BookmarkManager bookmarkManager; 

        [DataMember(Name = XD.Executor.BookmarkScopeManager, EmitDefaultValue = false)]
        BookmarkScopeManager bookmarkScopeManager;
 
        DebugController debugController;
        bool hasRaisedWorkflowStarted; 
 
        Guid instanceId;
        bool instanceIdSet; 

        Activity rootElement;
        Dictionary activeOperations;
        WorkflowInstance host; 

        ActivityInstanceMap instanceMap; 
        MappableObjectManager mappableObjectManager; 

        [DataMember(EmitDefaultValue = false)] 
        bool hasTrackedStarted;

        [DataMember(EmitDefaultValue = false)]
        long nextTrackingRecordNumber; 

        [DataMember(Name = XD.Executor.RootInstance, EmitDefaultValue = false)] 
        ActivityInstance rootInstance; 
        List executingSecondaryRootInstances;
 
        [DataMember(Name = XD.Executor.SchedulerMember, EmitDefaultValue = false)]
        Scheduler scheduler;

        [DataMember(Name = XD.Executor.CompletionException, EmitDefaultValue = false)] 
        Exception completionException;
 
        [DataMember(Name = XD.Executor.ShouldRaiseMainBodyComplete, EmitDefaultValue = false)] 
        bool shouldRaiseMainBodyComplete;
 
        [DataMember(Name = XD.Executor.LastInstanceId, EmitDefaultValue = false)]
        long lastInstanceId;

        [DataMember(Name = XD.Executor.RootEnvironment, EmitDefaultValue = false)] 
        LocationEnvironment rootEnvironment;
 
        [DataMember(Name = XD.Executor.WorkflowOutputs, EmitDefaultValue = false)] 
        IDictionary workflowOutputs;
 
        [DataMember(Name = XD.Executor.MainRootCompleteBookmark, EmitDefaultValue = false)]
        Bookmark mainRootCompleteBookmark;

        // This field reflects our best guess at our future completion state. 
        // We set it when the main root completes but might revise the value
        // depending on what actions are taken (like CancelRootActivity being 
        // called). 
        [DataMember(Name = XD.Executor.ExecutionState, EmitDefaultValue = false)]
        ActivityInstanceState executionState; 

        Queue persistenceWaiters;

        Quack transactionContextWaiters; 
        RuntimeTransactionData runtimeTransaction;
 
        bool isAbortPending; 
        bool isDisposed;
        bool shouldPauseOnCanPersist; 

        bool isTerminatePending;
        Exception terminationPendingException;
 
        int noPersistCount;
 
        SymbolResolver symbolResolver; 

        ActivityContext cachedResolutionContext; 

        // work item pools (for performance)
        Pool emptyWorkItemPool;
        Pool executeActivityWorkItemPool; 
        Pool completionWorkItemPool;
        Pool resolveNextArgumentWorkItemPool; 
 
        // context pools (for performance)
        Pool codeActivityContextPool; 
        Pool nativeActivityContextPool;

        // root handles (for default Tx, Correlation, etc)
        ExecutionPropertyManager rootPropertyManager; 

        // This list keeps track of handles that are created and initialized. 
        [DataMember(EmitDefaultValue = false)] 
        List handles;
 
        public ActivityExecutor(WorkflowInstance host)
        {
            Fx.Assert(host != null, "There must be a host.");
 
            this.host = host;
 
            this.bookmarkManager = new BookmarkManager(); 
            this.scheduler = new Scheduler(new Scheduler.Callbacks(this));
        } 

        public Pool EmptyWorkItemPool
        {
            get 
            {
                if (this.emptyWorkItemPool == null) 
                { 
                    this.emptyWorkItemPool = new PoolOfEmptyWorkItems();
                } 

                return this.emptyWorkItemPool;
            }
        } 

        Pool ExecuteActivityWorkItemPool 
        { 
            get
            { 
                if (this.executeActivityWorkItemPool == null)
                {
                    this.executeActivityWorkItemPool = new PoolOfExecuteActivityWorkItems();
                } 

                return this.executeActivityWorkItemPool; 
            } 
        }
 
        public Pool CompletionWorkItemPool
        {
            get
            { 
                if (this.completionWorkItemPool == null)
                { 
                    this.completionWorkItemPool = new PoolOfCompletionWorkItems(); 
                }
 
                return this.completionWorkItemPool;
            }
        }
 
        public Pool CodeActivityContextPool
        { 
            get 
            {
                if (this.codeActivityContextPool == null) 
                {
                    this.codeActivityContextPool = new PoolOfCodeActivityContexts();
                }
 
                return this.codeActivityContextPool;
            } 
        } 

        public Pool NativeActivityContextPool 
        {
            get
            {
                if (this.nativeActivityContextPool == null) 
                {
                    this.nativeActivityContextPool = new PoolOfNativeActivityContexts(); 
                } 

                return this.nativeActivityContextPool; 
            }
        }

        public Pool ResolveNextArgumentWorkItemPool 
        {
            get 
            { 
                if (this.resolveNextArgumentWorkItemPool == null)
                { 
                    this.resolveNextArgumentWorkItemPool = new PoolOfResolveNextArgumentWorkItems();
                }

                return this.resolveNextArgumentWorkItemPool; 
            }
        } 
 
        public Activity RootActivity
        { 
            get
            {
                return this.rootElement;
            } 
        }
 
        public bool IsInitialized 
        {
            get 
            {
                return this.host != null;
            }
        } 

        public bool HasPendingTrackingRecords 
        { 
            get
            { 
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.HasPendingRecords;
            }
        }
 
        public bool ShouldTrack
        { 
            get 
            {
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrack; 
            }
        }

        public bool ShouldTrackBookmarkResumptionRecords 
        {
            get 
            { 
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrackBookmarkResumptionRecords;
            } 
        }

        public bool ShouldTrackActivityScheduledRecords
        { 
            get
            { 
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrackActivityScheduledRecords; 
            }
        } 

        public bool ShouldTrackActivityStateRecords
        {
            get 
            {
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrackActivityStateRecords; 
            } 
        }
 
        public bool ShouldTrackActivityStateRecordsExecutingState
        {
            get
            { 
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrackActivityStateRecordsExecutingState;
            } 
        } 

        public bool ShouldTrackActivityStateRecordsClosedState 
        {
            get
            {
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrackActivityStateRecordsClosedState; 
            }
        } 
 
        public bool ShouldTrackCancelRequestedRecords
        { 
            get
            {
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrackCancelRequestedRecords;
            } 
        }
 
        public bool ShouldTrackFaultPropagationRecords 
        {
            get 
            {
                return this.host.HasTrackingParticipant && this.host.TrackingProvider.ShouldTrackFaultPropagationRecords;
            }
        } 

        public SymbolResolver SymbolResolver 
        { 
            get
            { 
                if (this.symbolResolver == null)
                {
                    try
                    { 
                        this.symbolResolver = this.host.GetExtension();
                    } 
                    catch (Exception e) 
                    {
                        if (Fx.IsFatal(e)) 
                        {
                            throw;
                        }
                        throw FxTrace.Exception.AsError(new CallbackException(SR.CallbackExceptionFromHostGetExtension(this.WorkflowInstanceId), e)); 
                    }
                } 
 
                return this.symbolResolver;
            } 
        }

        // This only gets accessed by root activities which are resolving arguments.  Since that
        // could at most be the real root and any secondary roots it doesn't seem necessary 
        // to cache the empty environment.
        public LocationEnvironment EmptyEnvironment 
        { 
            get
            { 
                return new LocationEnvironment(this, null);
            }
        }
 
        public ActivityInstanceState State
        { 
            get 
            {
                if ((this.executingSecondaryRootInstances != null && this.executingSecondaryRootInstances.Count > 0) || 
                    (this.rootInstance != null && !this.rootInstance.IsCompleted))
                {
                    // As long as some root is executing we need to return executing
                    return ActivityInstanceState.Executing; 
                }
                else 
                { 
                    return this.executionState;
                } 
            }
        }

        [DataMember] 
        public Guid WorkflowInstanceId
        { 
            get 
            {
                if (!this.instanceIdSet) 
                {
                    WorkflowInstanceId = this.host.Id;
                    if (!this.instanceIdSet)
                    { 
                        throw FxTrace.Exception.AsError(new InvalidOperationException(SR.EmptyIdReturnedFromHost(this.host.GetType())));
                    } 
                } 

                return this.instanceId; 
            }
            private set
            {
                this.instanceId = value; 
                this.instanceIdSet = value != Guid.Empty;
            } 
        } 

        public Exception TerminationException 
        {
            get
            {
                return this.completionException; 
            }
        } 
 
        public bool IsRunning
        { 
            get
            {
                return !this.isDisposed && this.scheduler.IsRunning;
            } 
        }
 
        public bool IsPersistable 
        {
            get 
            {
                return this.noPersistCount == 0;
            }
        } 

        public bool IsAbortPending 
        { 
            get
            { 
                return this.isAbortPending;
            }
        }
 
        public bool IsIdle
        { 
            get 
            {
                return this.isDisposed || this.scheduler.IsIdle; 
            }
        }

        public bool IsTerminatePending 
        {
            get 
            { 
                return this.isTerminatePending;
            } 
        }

        public bool KeysAllowed
        { 
            get
            { 
                return this.host.SupportsInstanceKeys; 
            }
        } 

        public IDictionary WorkflowOutputs
        {
            get 
            {
                return this.workflowOutputs; 
            } 
        }
 
        internal BookmarkScopeManager BookmarkScopeManager
        {
            get
            { 
                if (this.bookmarkScopeManager == null)
                { 
                    this.bookmarkScopeManager = new BookmarkScopeManager(); 
                }
 
                return this.bookmarkScopeManager;
            }
        }
 
        internal BookmarkScopeManager RawBookmarkScopeManager
        { 
            get 
            {
                return this.bookmarkScopeManager; 
            }
        }

        internal BookmarkManager RawBookmarkManager 
        {
            get 
            { 
                return this.bookmarkManager;
            } 
        }

        internal MappableObjectManager MappableObjectManager
        { 
            get
            { 
                if (this.mappableObjectManager == null) 
                {
                    this.mappableObjectManager = new MappableObjectManager(); 
                }

                return this.mappableObjectManager;
            } 
        }
 
        public bool RequiresTransactionContextWaiterExists 
        {
            get 
            {
                return this.transactionContextWaiters != null && this.transactionContextWaiters.Count > 0 && this.transactionContextWaiters[0].IsRequires;
            }
        } 

        public bool HasRuntimeTransaction 
        { 
            get { return this.runtimeTransaction != null; }
        } 

        public Transaction CurrentTransaction
        {
            get 
            {
                if (this.runtimeTransaction != null) 
                { 
                    return this.runtimeTransaction.ClonedTransaction;
                } 
                else
                {
                    return null;
                } 
            }
        } 
 
        static ReadOnlyCollection EmptyBookmarkInfoCollection
        { 
            get
            {
                if (emptyBookmarkInfoCollection == null)
                { 
                    emptyBookmarkInfoCollection = new ReadOnlyCollection(new List(0));
                } 
 
                return emptyBookmarkInfoCollection;
            } 
        }

        [DataMember(Name = XD.Executor.TransactionContextWaiters, EmitDefaultValue = false)]
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Used by serialization")] 
        TransactionContextWaiter[] SerializedTransactionContextWaiters
        { 
            get 
            {
                if (this.transactionContextWaiters != null && this.transactionContextWaiters.Count > 0) 
                {
                    return this.transactionContextWaiters.ToArray();
                }
                else 
                {
                    return null; 
                } 
            }
            set 
            {
                Fx.Assert(value != null, "We don't serialize out null.");
                this.transactionContextWaiters = new Quack(value);
            } 
        }
 
        [DataMember(Name = XD.Executor.PersistenceWaiters, EmitDefaultValue = false)] 
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Used by serialization")]
        Queue SerializedPersistenceWaiters 
        {
            get
            {
                if (this.persistenceWaiters == null || this.persistenceWaiters.Count == 0) 
                {
                    return null; 
                } 
                else
                { 
                    return this.persistenceWaiters;
                }
            }
            set 
            {
                Fx.Assert(value != null, "We don't serialize out null."); 
                this.persistenceWaiters = value; 
            }
        } 

        [DataMember(Name = XD.Executor.SecondaryRootInstances, EmitDefaultValue = false)]
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Used by serialization")]
        List SerializedExecutingSecondaryRootInstances 
        {
            get 
            { 
                if (this.executingSecondaryRootInstances != null && this.executingSecondaryRootInstances.Count > 0)
                { 
                    return this.executingSecondaryRootInstances;
                }
                else
                { 
                    return null;
                } 
            } 
            set
            { 
                Fx.Assert(value != null, "We don't serialize out null.");
                this.executingSecondaryRootInstances = value;
            }
        } 

        [DataMember(Name = XD.Executor.MappableObjectManager, EmitDefaultValue = false)] 
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Used by serialization")] 
        MappableObjectManager SerializedMappableObjectManager
        { 
            get
            {
                if (this.mappableObjectManager == null || this.mappableObjectManager.Count == 0)
                { 
                    return null;
                } 
 
                return this.mappableObjectManager;
            } 

            set
            {
                Fx.Assert(value != null, "value from serialization should never be null"); 
                this.mappableObjectManager = value;
            } 
        } 

        // map from activity names to (active) associated activity instances 
        [DataMember(Name = XD.Executor.ActivityInstanceMap, EmitDefaultValue = false)]
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "called from serialization")]
        ActivityInstanceMap SerializedProgramMapping
        { 
            get
            { 
                if (this.instanceMap == null && !this.isDisposed) 
                {
                    this.instanceMap = new ActivityInstanceMap(); 

                    this.rootInstance.FillInstanceMap(this.instanceMap);
                    this.scheduler.FillInstanceMap(this.instanceMap);
 
                    if (this.executingSecondaryRootInstances != null && this.executingSecondaryRootInstances.Count > 0)
                    { 
                        foreach (ActivityInstance secondaryRoot in this.executingSecondaryRootInstances) 
                        {
                            secondaryRoot.FillInstanceMap(this.instanceMap); 

                            LocationEnvironment environment = secondaryRoot.Environment;

                            if (secondaryRoot.IsEnvironmentOwner) 
                            {
                                environment = environment.Parent; 
                            } 

                            while (environment != null) 
                            {
                                if (environment.HasOwnerCompleted)
                                {
                                    this.instanceMap.AddEntry(environment, true); 
                                }
 
                                environment = environment.Parent; 
                            }
                        } 
                    }
                }

                return this.instanceMap; 
            }
 
            set 
            {
                Fx.Assert(value != null, "value from serialization should never be null"); 
                this.instanceMap = value;
            }
        }
 
        // may be null
        internal ExecutionPropertyManager RootPropertyManager 
        { 
            get
            { 
                return this.rootPropertyManager;
            }
        }
 
        [DataMember(Name = XD.ActivityInstance.PropertyManager, EmitDefaultValue = false)]
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Called from Serialization")] 
        ExecutionPropertyManager SerializedPropertyManager 
        {
            get 
            {
                return this.rootPropertyManager;
            }
            set 
            {
                Fx.Assert(value != null, "We don't emit the default value so this should never be null."); 
                this.rootPropertyManager = value; 
                this.rootPropertyManager.OnDeserialized(null, null, null, this);
            } 
        }

        internal List Handles
        { 
            get { return this.handles; }
        } 
 
        // get a resolution context to use for argument/variable expression fast-path optimizations
        public ActivityContext GetResolutionContext(ActivityInstance activityInstance) 
        {
            if (this.cachedResolutionContext == null)
            {
                this.cachedResolutionContext = new ActivityContext(activityInstance, this); 
            }
            else 
            { 
                this.cachedResolutionContext.Reinitialize(activityInstance, this);
            } 

            return this.cachedResolutionContext;
        }
 
        // Whether it is being debugged.
        bool IsDebugged() 
        { 
            if (this.debugController == null)
            { 
#if DEBUG
                if (Fx.StealthDebugger)
                {
                    return false; 
                }
#endif 
                if (System.Diagnostics.Debugger.IsAttached) 
                {
                    this.debugController = new DebugController(this.host); 
                }
            }
            return this.debugController != null;
        } 

        public void DebugActivityCompleted(ActivityInstance instance) 
        { 
            if (this.debugController != null)   // Don't use IsDebugged() for perf reason.
            { 
                this.debugController.ActivityCompleted(instance);
            }
        }
 
        public void AddTrackingRecord(TrackingRecord record)
        { 
            Fx.Assert(this.host.TrackingProvider != null, "We should only add records if we have a tracking provider."); 

            this.host.TrackingProvider.AddRecord(record); 
        }

        public bool ShouldTrackActivity(string name)
        { 
            Fx.Assert(this.host.TrackingProvider != null, "We should only add records if we have a tracking provider.");
            return this.host.TrackingProvider.ShouldTrackActivity(name); 
        } 

        public IAsyncResult BeginTrackPendingRecords(AsyncCallback callback, object state) 
        {
            Fx.Assert(this.host.TrackingProvider != null, "We should only try to track if we have a tracking provider.");
            return this.host.BeginFlushTrackingRecords(callback, state);
        } 

        public void EndTrackPendingRecords(IAsyncResult result) 
        { 
            Fx.Assert(this.host.TrackingProvider != null, "We should only try to track if we have a tracking provider.");
            this.host.EndFlushTrackingRecords(result); 
        }

        internal IDictionary GatherMappableVariables()
        { 
            if (this.mappableObjectManager != null)
            { 
                return this.MappableObjectManager.GatherMappableVariables(); 
            }
            return null; 
        }

        internal void OnSchedulerThreadAcquired()
        { 
            if (this.IsDebugged() && !this.hasRaisedWorkflowStarted)
            { 
                this.hasRaisedWorkflowStarted = true; 
                this.debugController.WorkflowStarted();
            } 
        }

        public void Dispose()
        { 
            Dispose(true);
        } 
 
        void Dispose(bool aborting)
        { 
            if (!this.isDisposed)
            {
                if (this.debugController != null)   // Don't use IsDebugged() because it may create debugController unnecessarily.
                { 
                    this.debugController.WorkflowCompleted();
                    this.debugController = null; 
                } 

                if (this.activeOperations != null && this.activeOperations.Count > 0) 
                {
                    Fx.Assert(aborting, "shouldn't get here in the g----ful close case");
                    Abort(new OperationCanceledException());
                } 
                else
                { 
                    this.scheduler.ClearAllWorkItems(this); 

                    if (!aborting) 
                    {
                        this.scheduler = null;
                        this.bookmarkManager = null;
                        this.lastInstanceId = 0; 
                        this.rootInstance = null;
                    } 
 
                    this.isDisposed = true;
                } 
            }
        }

        // Called from an arbitrary thread 
        public void PauseWhenPersistable()
        { 
            this.shouldPauseOnCanPersist = true; 
        }
 
        public void EnterNoPersist()
        {
            this.noPersistCount++;
 
            if (TD.EnterNoPersistBlockIsEnabled())
            { 
                TD.EnterNoPersistBlock(); 
            }
        } 

        public void ExitNoPersist()
        {
            this.noPersistCount--; 

            if (TD.ExitNoPersistBlockIsEnabled()) 
            { 
                TD.ExitNoPersistBlock();
            } 

            if (this.shouldPauseOnCanPersist && this.IsPersistable)
            {
                // shouldPauseOnCanPersist is reset at the next pause 
                // notification
                this.scheduler.Pause(); 
            } 
        }
 
        void IEnlistmentNotification.Commit(Enlistment enlistment)
        {
            // Because of ordering we might get this notification after we've already
            // determined the outcome 

            // Get a local copy of this.runtimeTransaction because it is possible for 
            // this.runtimeTransaction to be nulled out between the time we check for null 
            // and the time we try to lock it.
            RuntimeTransactionData localRuntimeTransaction = this.runtimeTransaction; 

            if (localRuntimeTransaction != null)
            {
                AsyncWaitHandle completionEvent = null; 

                lock (localRuntimeTransaction) 
                { 
                    completionEvent = localRuntimeTransaction.CompletionEvent;
 
                    localRuntimeTransaction.TransactionStatus = TransactionStatus.Committed;
                }

                enlistment.Done(); 

                if (completionEvent != null) 
                { 
                    completionEvent.Set();
                } 
            }
            else
            {
                enlistment.Done(); 
            }
        } 
 
        void IEnlistmentNotification.InDoubt(Enlistment enlistment)
        { 
            ((IEnlistmentNotification)this).Rollback(enlistment);
        }

        //Note - There is a scenario in the TransactedReceiveScope while dealing with server side WCF dispatcher created transactions, 
        //the activity instance will end up calling BeginCommit before finishing up its execution. By this we allow the executing TransactedReceiveScope activity to
        //complete and the executor is "free" to respond to this Prepare notification as part of the commit processing of that server side transaction 
        void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment) 
        {
            // Because of ordering we might get this notification after we've already 
            // determined the outcome

            // Get a local copy of this.runtimeTransaction because it is possible for
            // this.runtimeTransaction to be nulled out between the time we check for null 
            // and the time we try to lock it.
            RuntimeTransactionData localRuntimeTransaction = this.runtimeTransaction; 
 
            if (localRuntimeTransaction != null)
            { 
                bool callPrepared = false;

                lock (localRuntimeTransaction)
                { 
                    if (localRuntimeTransaction.HasPrepared)
                    { 
                        callPrepared = true; 
                    }
                    else 
                    {
                        localRuntimeTransaction.PendingPreparingEnlistment = preparingEnlistment;
                    }
                } 

                if (callPrepared) 
                { 
                    preparingEnlistment.Prepared();
                } 
            }
            else
            {
                preparingEnlistment.Prepared(); 
            }
        } 
 
        void IEnlistmentNotification.Rollback(Enlistment enlistment)
        { 
            // Because of ordering we might get this notification after we've already
            // determined the outcome

            // Get a local copy of this.runtimeTransaction because it is possible for 
            // this.runtimeTransaction to be nulled out between the time we check for null
            // and the time we try to lock it. 
            RuntimeTransactionData localRuntimeTransaction = this.runtimeTransaction; 

            if (localRuntimeTransaction != null) 
            {
                AsyncWaitHandle completionEvent = null;

                lock (localRuntimeTransaction) 
                {
                    completionEvent = localRuntimeTransaction.CompletionEvent; 
 
                    localRuntimeTransaction.TransactionStatus = TransactionStatus.Aborted;
                } 

                enlistment.Done();

                if (completionEvent != null) 
                {
                    completionEvent.Set(); 
                } 
            }
            else 
            {
                enlistment.Done();
            }
        } 

        public void RequestTransactionContext(ActivityInstance instance, bool isRequires, RuntimeTransactionHandle handle, Action callback, object state) 
        { 
            if (isRequires)
            { 
                EnterNoPersist();
            }

            if (this.transactionContextWaiters == null) 
            {
                this.transactionContextWaiters = new Quack(); 
            } 

            TransactionContextWaiter waiter = new TransactionContextWaiter(instance, isRequires, handle, new TransactionContextWaiterCallbackWrapper(callback,instance), state); 

            if (isRequires)
            {
                Fx.Assert(this.transactionContextWaiters.Count == 0 || !this.transactionContextWaiters[0].IsRequires, "Either we don't have any waiters or the first one better not be IsRequires == true"); 

                this.transactionContextWaiters.PushFront(waiter); 
            } 
            else
            { 
                this.transactionContextWaiters.Enqueue(waiter);
            }

            instance.IncrementBusyCount(); 
            instance.WaitingForTransactionContext = true;
        } 
 
        public void SetTransaction(RuntimeTransactionHandle handle, Transaction transaction, ActivityInstance isolationScope, ActivityInstance transactionOwner)
        { 
            this.runtimeTransaction = new RuntimeTransactionData(handle, transaction, isolationScope);
            EnterNoPersist();

            // no more work to do for a host-declared transaction 
            if (transactionOwner == null)
            { 
                return; 
            }
 
            Exception abortException = null;

            try
            { 
                transaction.EnlistVolatile(this, EnlistmentOptions.EnlistDuringPrepareRequired);
            } 
            catch (Exception e) 
            {
                if (Fx.IsFatal(e)) 
                {
                    throw;
                }
 
                abortException = e;
            } 
 
            if (abortException != null)
            { 
                AbortWorkflowInstance(abortException);
            }
            else
            { 
                if (TD.RuntimeTransactionSetIsEnabled())
                { 
                    Fx.Assert(transactionOwner != null, "isolationScope and transactionOwner are either both null or both non-null"); 
                    TD.RuntimeTransactionSet(transactionOwner.Activity.GetType().ToString(), transactionOwner.Activity.DisplayName, transactionOwner.Id, isolationScope.Activity.GetType().ToString(), isolationScope.Activity.DisplayName, isolationScope.Id);
                } 
            }
        }

        public void CompleteTransaction(RuntimeTransactionHandle handle, BookmarkCallback callback, ActivityInstance callbackOwner) 
        {
            if (callback != null) 
            { 
                Bookmark bookmark = this.bookmarkManager.CreateBookmark(callback, callbackOwner, BookmarkOptions.None);
                ActivityExecutionWorkItem workItem; 

                ActivityInstance isolationScope = null;

                if (this.runtimeTransaction != null) 
                {
                    isolationScope = this.runtimeTransaction.IsolationScope; 
                } 

                this.bookmarkManager.TryGenerateWorkItem(this, false, ref bookmark, null, isolationScope, out workItem); 
                this.scheduler.EnqueueWork(workItem);
            }

            if (this.runtimeTransaction != null && this.runtimeTransaction.TransactionHandle == handle) 
            {
                this.runtimeTransaction.ShouldScheduleCompletion = true; 
 
                if (TD.RuntimeTransactionCompletionRequestedIsEnabled())
                { 
                    TD.RuntimeTransactionCompletionRequested(callbackOwner.Activity.GetType().ToString(), callbackOwner.Activity.DisplayName, callbackOwner.Id);
                }
            }
        } 

        void SchedulePendingCancelation() 
        { 
            if (this.runtimeTransaction.IsRootCancelPending)
            { 
                if (!this.rootInstance.IsCancellationRequested && !this.rootInstance.IsCompleted)
                {
                    this.rootInstance.IsCancellationRequested = true;
                    this.scheduler.PushWork(new CancelActivityWorkItem(this.rootInstance)); 
                }
 
                this.runtimeTransaction.IsRootCancelPending = false; 
            }
        } 

        public EmptyWorkItem CreateEmptyWorkItem(ActivityInstance instance)
        {
            EmptyWorkItem workItem = this.EmptyWorkItemPool.Acquire(); 
            workItem.Initialize(instance);
 
            return workItem; 
        }
 
        public bool IsCompletingTransaction(ActivityInstance instance)
        {
            if (this.runtimeTransaction != null && this.runtimeTransaction.IsolationScope == instance)
            { 
                // We add an empty work item to keep the instance alive
                this.scheduler.PushWork(CreateEmptyWorkItem(instance)); 
 
                // This will schedule the appopriate work item at the end of this work item
                this.runtimeTransaction.ShouldScheduleCompletion = true; 

                if (TD.RuntimeTransactionCompletionRequestedIsEnabled())
                {
                    TD.RuntimeTransactionCompletionRequested(instance.Activity.GetType().ToString(), instance.Activity.DisplayName, instance.Id); 
                }
 
                return true; 
            }
 
            return false;
        }

        public void TerminateSpecialExecutionBlocks(ActivityInstance terminatedInstance, Exception terminationReason) 
        {
            if (this.runtimeTransaction != null && this.runtimeTransaction.IsolationScope == terminatedInstance) 
            { 
                Exception abortException = null;
 
                try
                {
                    this.runtimeTransaction.Rollback(terminationReason);
                } 
                catch (Exception e)
                { 
                    if (Fx.IsFatal(e)) 
                    {
                        throw; 
                    }

                    abortException = e;
                } 

                if (abortException != null) 
                { 
                    // It is okay for us to call AbortWorkflowInstance even if we are already
                    // aborting the instance since it is an async call (IE - we asking the host 
                    // to re-enter the instance to abandon it.
                    AbortWorkflowInstance(abortException);
                }
 
                SchedulePendingCancelation();
 
                ExitNoPersist(); 

                if (this.runtimeTransaction.TransactionHandle.AbortInstanceOnTransactionFailure) 
                {
                    AbortWorkflowInstance(terminationReason);
                }
 
                this.runtimeTransaction = null;
            } 
        } 

        // Returns true if we actually performed the abort and false if we had already been disposed 
        bool Abort(Exception terminationException, bool isTerminate)
        {
            if (!this.isDisposed)
            { 
                if (!this.rootInstance.IsCompleted)
                { 
                    this.rootInstance.Abort(this, this.bookmarkManager, terminationException, isTerminate); 

                    // the Abort walk won't catch host-registered properties 
                    if (this.rootPropertyManager != null)
                    {
                        if (isTerminate)
                        { 
                            HandleInitializationContext context = new HandleInitializationContext(this, null);
                            foreach (ExecutionPropertyManager.ExecutionProperty executionProperty in this.rootPropertyManager.Properties.Values) 
                            { 
                                Handle handle = executionProperty.Property as Handle;
                                if (handle != null) 
                                {
                                    handle.Uninitialize(context);
                                }
                            } 
                            context.Dispose();
                        } 
 
                        this.rootPropertyManager.UnregisterProperties(null, null, true);
                    } 
                }

                if (this.executingSecondaryRootInstances != null)
                { 
                    // We have to walk this list backwards because the abort
                    // path removes from this collection. 
                    for (int i = this.executingSecondaryRootInstances.Count - 1; i >= 0; i--) 
                    {
                        ActivityInstance secondaryRootInstance = this.executingSecondaryRootInstances[i]; 

                        Fx.Assert(!secondaryRootInstance.IsCompleted, "We should not have any complete instances in our list.");

                        secondaryRootInstance.Abort(this, this.bookmarkManager, terminationException, isTerminate); 

                        Fx.Assert(this.executingSecondaryRootInstances.Count == i, "We are always working from the back and we should have removed the item we just aborted."); 
                    } 
                }
 
                // This must happen after we abort each activity.  This allows us to utilize code paths
                // which schedule work items.
                this.scheduler.ClearAllWorkItems(this);
 
                if (isTerminate)
                { 
                    // Regardless of the previous state, a termination implies setting the 
                    // completion exception and completing in the Faulted state.
                    this.completionException = terminationException; 
                    this.executionState = ActivityInstanceState.Faulted;
                }

                this.Dispose(); 

                return true; 
            } 

            return false; 
        }

        // Returns true if tracing was transfered
        bool TryTraceResume(out Guid oldActivityId) 
        {
            // 
            if (FxTrace.Trace.ShouldTraceToTraceSource(TraceEventLevel.Informational)) 
            {
                oldActivityId = DiagnosticTrace.ActivityId; 
                FxTrace.Trace.SetAndTraceTransfer(this.WorkflowInstanceId, true);

                if (TD.WorkflowActivityResumeIsEnabled())
                { 
                    TD.WorkflowActivityResume(this.WorkflowInstanceId.ToString());
                } 
 
                return true;
            } 
            else
            {
                oldActivityId = Guid.Empty;
                return false; 
            }
        } 
 
        // Returns true if tracing was transfered
        bool TryTraceStart(out Guid oldActivityId) 
        {
            //
            if (FxTrace.Trace.ShouldTraceToTraceSource(TraceEventLevel.Informational))
            { 
                oldActivityId = DiagnosticTrace.ActivityId;
                FxTrace.Trace.SetAndTraceTransfer(this.WorkflowInstanceId, true); 
 
                if (TD.WorkflowActivityStartIsEnabled())
                { 
                    TD.WorkflowActivityStart(this.WorkflowInstanceId.ToString());
                }

                return true; 
            }
            else 
            { 
                oldActivityId = Guid.Empty;
                return false; 
            }
        }

        void TraceSuspend(bool hasBeenResumed, Guid oldActivityId) 
        {
            if (hasBeenResumed) 
            { 
                if (TD.WorkflowActivitySuspendIsEnabled())
                { 
                    TD.WorkflowActivitySuspend(this.WorkflowInstanceId.ToString());
                }

                DiagnosticTrace.ActivityId = oldActivityId; 
            }
        } 
 
        public bool Abort(Exception reason)
        { 
            Guid oldActivityId;
            bool hasTracedResume = TryTraceResume(out oldActivityId);

            bool abortResult = Abort(reason, false); 

            TraceSuspend(hasTracedResume, oldActivityId); 
 
            return abortResult;
        } 

        // It must be okay for the runtime to be processing other
        // work on a different thread when this is called.  See
        // the comments in the method for justifications. 
        public void AbortWorkflowInstance(Exception reason)
        { 
            Fx.Assert(!this.isDisposed, "We should not already be disposed."); 

            // 1) This flag is only ever set to true 
            this.isAbortPending = true;

            // 2) This causes a couple of fields to be set
            this.host.Abort(reason); 
            try
            { 
                // 3) The host expects this to come from an unknown thread 
                this.host.OnRequestAbort(reason);
            } 
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                { 
                    throw;
                } 
                throw FxTrace.Exception.AsError(new CallbackException(SR.CallbackExceptionFromHostAbort(this.WorkflowInstanceId), e)); 
            }
        } 

        public void ScheduleTerminate(Exception reason)
        {
            this.isTerminatePending = true; 
            this.terminationPendingException = reason;
        } 
 
        public void Terminate(Exception reason)
        { 
            Fx.Assert(!this.isDisposed, "We should not have been able to get here if we are disposed and Abort makes choices based on isDisposed");

            Guid oldActivityId;
            bool hasTracedResume = TryTraceResume(out oldActivityId); 

            Abort(reason, true); 
 
            TraceSuspend(hasTracedResume, oldActivityId);
        } 

        public void CancelRootActivity()
        {
            if (this.rootInstance.State == ActivityInstanceState.Executing) 
            {
                if (!this.rootInstance.IsCancellationRequested) 
                { 
                    Guid oldActivityId;
                    bool hasTracedResume = TryTraceResume(out oldActivityId); 

                    bool trackCancelRequested = true;

                    if (this.runtimeTransaction != null && this.runtimeTransaction.IsolationScope != null) 
                    {
                        if (this.runtimeTransaction.IsRootCancelPending) 
                        { 
                            trackCancelRequested = false;
                        } 

                        this.runtimeTransaction.IsRootCancelPending = true;
                    }
                    else 
                    {
                        this.rootInstance.IsCancellationRequested = true; 
 
                        if (this.rootInstance.HasNotExecuted)
                        { 
                            this.scheduler.PushWork(CreateEmptyWorkItem(this.rootInstance));
                        }
                        else
                        { 
                            this.scheduler.PushWork(new CancelActivityWorkItem(this.rootInstance));
                        } 
                    } 

                    if (this.ShouldTrackCancelRequestedRecords && trackCancelRequested) 
                    {
                        AddTrackingRecord(new CancelRequestedRecord(this.WorkflowInstanceId, null, this.rootInstance));
                    }
 
                    TraceSuspend(hasTracedResume, oldActivityId);
                } 
            } 
            else if (this.rootInstance.State != ActivityInstanceState.Closed)
            { 
                // We've been asked to cancel the instance and the root
                // completed in a canceled or faulted state.  By our rules
                // this means that the instance has been canceled.  A real
                // world example if the case of UnhandledExceptionAction.Cancel 
                // on a workflow whose root activity threw an exception. The
                // expected completion state is Canceled and NOT Faulted. 
                this.executionState = ActivityInstanceState.Canceled; 
                this.completionException = null;
            } 
        }

        public void CancelActivity(ActivityInstance activityInstance)
        { 
            Fx.Assert(activityInstance != null, "The instance must not be null.");
 
            // Cancel is a no-op if the activity is complete or cancel has already been requested 
            if (activityInstance.State != ActivityInstanceState.Executing || activityInstance.IsCancellationRequested)
            { 
                return;
            }

            // Set that we have requested cancel.  This is our only guard against scheduling 
            // ActivityInstance.Cancel multiple times.
            activityInstance.IsCancellationRequested = true; 
 
            if (activityInstance.HasNotExecuted)
            { 
                this.scheduler.PushWork(CreateEmptyWorkItem(activityInstance));
            }
            else
            { 
                this.scheduler.PushWork(new CancelActivityWorkItem(activityInstance));
            } 
 
            if (this.ShouldTrackCancelRequestedRecords)
            { 
                AddTrackingRecord(new CancelRequestedRecord(this.WorkflowInstanceId, activityInstance.Parent, activityInstance));
            }
        }
 
        void PropagateException(WorkItem workItem)
        { 
            ActivityInstance exceptionSource = workItem.ActivityInstance; 
            Exception exception = workItem.ExceptionToPropagate;
 
            ActivityInstance exceptionPropagator = exceptionSource;
            FaultBookmark targetBookmark = null;

            while (exceptionPropagator != null && targetBookmark == null) 
            {
                if (!exceptionPropagator.IsCompleted) 
                { 
                    if (this.runtimeTransaction != null && this.runtimeTransaction.IsolationScope == exceptionPropagator)
                    { 
                        // We are propagating the exception across the isolation scope
                        this.scheduler.PushWork(new AbortActivityWorkItem(exceptionPropagator, exception, CreateActivityInstanceReference(workItem.OriginalExceptionSource, exceptionPropagator)));

                        // Because we are aborting the transaction we reset the ShouldScheduleCompletion flag 
                        this.runtimeTransaction.ShouldScheduleCompletion = false;
                        workItem.ExceptionPropagated(); 
                        return; 
                    }
                } 

                if (exceptionPropagator.IsCancellationRequested)
                {
                    // Regardless of whether it is already completed or not we need 
                    // to honor the workflow abort
 
                    this.AbortWorkflowInstance(new InvalidOperationException(SR.CannotPropagateExceptionWhileCanceling(exceptionSource.Activity.DisplayName, exceptionSource.Id), exception)); 
                    workItem.ExceptionPropagated();
                    return; 
                }

                if (exceptionPropagator.FaultBookmark != null)
                { 
                    // This will cause us to break out of the loop
                    targetBookmark = exceptionPropagator.FaultBookmark; 
                } 
                else
                { 
                    exceptionPropagator = exceptionPropagator.Parent;
                }
            }
 
            if (targetBookmark != null)
            { 
                if (this.ShouldTrackFaultPropagationRecords) 
                {
                    AddTrackingRecord(new FaultPropagationRecord(this.WorkflowInstanceId, 
                                                                workItem.OriginalExceptionSource,
                                                                exceptionPropagator.Parent,
                                                                exceptionSource == workItem.OriginalExceptionSource,
                                                                exception)); 
                }
 
                this.scheduler.PushWork(targetBookmark.GenerateWorkItem(exception, exceptionPropagator, CreateActivityInstanceReference(workItem.OriginalExceptionSource, exceptionPropagator.Parent))); 
                workItem.ExceptionPropagated();
            } 
            else
            {
                if (this.ShouldTrackFaultPropagationRecords)
                { 
                    AddTrackingRecord(new FaultPropagationRecord(this.WorkflowInstanceId,
                                                                workItem.OriginalExceptionSource, 
                                                                null, 
                                                                exceptionSource == workItem.OriginalExceptionSource,
                                                                exception)); 
                }
            }
        }
 
        internal ActivityInstanceReference CreateActivityInstanceReference(ActivityInstance toReference, ActivityInstance referenceOwner)
        { 
            ActivityInstanceReference reference = new ActivityInstanceReference(toReference); 

            if (this.instanceMap != null) 
            {
                this.instanceMap.AddEntry(reference);
            }
 
            referenceOwner.AddActivityReference(reference);
 
            return reference; 
        }
 
        internal void RethrowException(ActivityInstance fromInstance, FaultContext context)
        {
            this.scheduler.PushWork(new RethrowExceptionWorkItem(fromInstance, context.Exception, context.Source));
        } 

        internal void OnDeserialized(Activity workflow, WorkflowInstance workflowInstance) 
        { 
            Fx.Assert(workflow != null, "The program must be non-null");
            Fx.Assert(workflowInstance != null, "The host must be non-null"); 

            this.rootElement = workflow;
            this.host = workflowInstance;
 
            if (!this.instanceIdSet)
            { 
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.EmptyGuidOnDeserializedInstance)); 
            }
            if (this.host.Id != this.instanceId) 
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.HostIdDoesNotMatchInstance(this.host.Id, this.instanceId)));
            }
 
            if (this.host.HasTrackingParticipant)
            { 
                this.host.TrackingProvider.OnDeserialized(this.nextTrackingRecordNumber); 
                this.host.OnDeserialized(this.hasTrackedStarted);
            } 

            // hookup our callback to the scheduler
            if (this.scheduler != null)
            { 
                this.scheduler.OnDeserialized(new Scheduler.Callbacks(this));
            } 
 
            if (this.rootInstance != null)
            { 
                Fx.Assert(this.instanceMap != null, "We always have an InstanceMap.");
                this.instanceMap.LoadActivityTree(workflow, this.rootInstance, this.executingSecondaryRootInstances, this);

                // We need to make sure that any "dangling" secondary root environments 
                // get OnDeserialized called.
                if (this.executingSecondaryRootInstances != null) 
                { 
                    Fx.Assert(this.executingSecondaryRootInstances.Count > 0, "We don't serialize out an empty list.");
 
                    for (int i = 0; i < this.executingSecondaryRootInstances.Count; i++)
                    {
                        ActivityInstance secondaryRoot = this.executingSecondaryRootInstances[i];
                        LocationEnvironment environment = secondaryRoot.Environment.Parent; 

                        if (environment != null) 
                        { 
                            environment.OnDeserialized(this, secondaryRoot);
                        } 
                    }
                }
            }
            else 
            {
                this.isDisposed = true; 
            } 
        }
 
        public T GetExtension()
            where T : class
        {
            T extension = null; 
            try
            { 
                extension = this.host.GetExtension(); 
            }
            catch (Exception e) 
            {
                if (Fx.IsFatal(e))
                {
                    throw; 
                }
                throw FxTrace.Exception.AsError(new CallbackException(SR.CallbackExceptionFromHostGetExtension(this.WorkflowInstanceId), e)); 
            } 

            return extension; 
        }

        // callback from scheduler to process a work item
        internal Scheduler.RequestedAction OnExecuteWorkItem(WorkItem workItem) 
        {
            workItem.Release(this); 
 
            // thunk out early if the work item is no longer valid (that is, we're not in the Executing state)
            if (!workItem.IsValid) 
            {
                return Scheduler.Continue;
            }
 
            if (!workItem.IsEmpty)
            { 
                Exception setupOrCleanupException = null; 
                ActivityInstance propertyManagerOwner = workItem.PropertyManagerOwner;
                try 
                {
                    if (propertyManagerOwner != null && propertyManagerOwner.PropertyManager != null)
                    {
                        try 
                        {
                            propertyManagerOwner.PropertyManager.SetupWorkflowThread(); 
                        } 
                        catch (Exception e)
                        { 
                            if (Fx.IsFatal(e))
                            {
                                throw;
                            } 

                            setupOrCleanupException = e; 
                        } 
                    }
 
                    if (setupOrCleanupException == null)
                    {
                        if (!workItem.Execute(this, this.bookmarkManager))
                        { 
                            return Scheduler.YieldSilently;
                        } 
                    } 
                }
                finally 
                {
                    // We might be multi-threaded when we execute code in
                    // this finally block.  The work item might have gone
                    // async and may already have called back into FinishWorkItem. 
                    if (propertyManagerOwner != null && propertyManagerOwner.PropertyManager != null)
                    { 
                        // This throws only fatal exceptions 
                        propertyManagerOwner.PropertyManager.CleanupWorkflowThread(ref setupOrCleanupException);
                    } 

                    if (setupOrCleanupException != null)
                    {
                        // This API must allow the runtime to be 
                        // multi-threaded when it is called.
                        AbortWorkflowInstance(new OperationCanceledException(SR.SetupOrCleanupWorkflowThreadThrew, setupOrCleanupException)); 
                    } 
                }
 
                if (setupOrCleanupException != null)
                {
                    // We already aborted the instance in the finally block so
                    // now we just need to return early. 
                    return Scheduler.Continue;
                } 
            } 

            if (workItem.WorkflowAbortException != null) 
            {
                AbortWorkflowInstance(new OperationCanceledException(SR.WorkItemAbortedInstance, workItem.WorkflowAbortException));
                return Scheduler.Continue;
            } 

            // We only check this in the [....] path because there are no ways of changing the keys collections from the work items that can 
            // go async.  There's an assert to this effect in FinishWorkItem. 
            if (this.bookmarkScopeManager != null && this.bookmarkScopeManager.HasKeysToUpdate)
            { 
                if (!workItem.FlushBookmarkScopeKeys(this))
                {
                    return Scheduler.YieldSilently;
                } 

                if (workItem.WorkflowAbortException != null) 
                { 
                    AbortWorkflowInstance(new OperationCanceledException(SR.WorkItemAbortedInstance, workItem.WorkflowAbortException));
                    return Scheduler.Continue; 
                }
            }

            workItem.PostProcess(this); 

            if (workItem.ExceptionToPropagate != null) 
            { 
                PropagateException(workItem);
            } 

            if (this.HasPendingTrackingRecords)
            {
                if (!workItem.FlushTracking(this)) 
                {
                    return Scheduler.YieldSilently; 
                } 

                if (workItem.WorkflowAbortException != null) 
                {
                    AbortWorkflowInstance(new OperationCanceledException(SR.TrackingRelatedWorkflowAbort, workItem.WorkflowAbortException));
                    return Scheduler.Continue;
                } 
            }
 
            ScheduleRuntimeWorkItems(); 

            if (workItem.ExceptionToPropagate != null) 
            {
                return Scheduler.CreateNotifyUnhandledExceptionAction(workItem.ExceptionToPropagate, workItem.OriginalExceptionSource);
            }
 
            return Scheduler.Continue;
        } 
 
        internal IAsyncResult BeginAssociateKeys(ICollection keysToAssociate, AsyncCallback callback, object state)
        { 
            return new AssociateKeysAsyncResult(this, keysToAssociate, callback, state);
        }

        internal void EndAssociateKeys(IAsyncResult result) 
        {
            AssociateKeysAsyncResult.End(result); 
        } 

        internal void DisassociateKeys(ICollection keysToDisassociate) 
        {
            this.host.OnDisassociateKeys(keysToDisassociate);
        }
 
        internal void FinishWorkItem(WorkItem workItem)
        { 
            Scheduler.RequestedAction resumptionAction = Scheduler.Continue; 

            try 
            {
                Fx.Assert(this.bookmarkScopeManager == null || !this.bookmarkScopeManager.HasKeysToUpdate,
                    "FinishWorkItem should be called after FlushBookmarkScopeKeys, or by a WorkItem that could not possibly generate keys.");
 
                if (workItem.WorkflowAbortException != null)
                { 
                    // We resume the scheduler even after abort to make sure that 
                    // the proper events are raised.
                    AbortWorkflowInstance(new OperationCanceledException(SR.WorkItemAbortedInstance, workItem.WorkflowAbortException)); 
                }
                else
                {
                    workItem.PostProcess(this); 

                    if (workItem.ExceptionToPropagate != null) 
                    { 
                        PropagateException(workItem);
                    } 

                    if (this.HasPendingTrackingRecords)
                    {
                        if (!workItem.FlushTracking(this)) 
                        {
                            // We exit early here and will come back in at 
                            // FinishWorkItemAfterTracking 
                            resumptionAction = Scheduler.YieldSilently;
                            return; 
                        }
                    }

                    if (workItem.WorkflowAbortException != null) 
                    {
                        // We resume the scheduler even after abort to make sure that 
                        // the proper events are raised. 
                        AbortWorkflowInstance(new OperationCanceledException(SR.TrackingRelatedWorkflowAbort, workItem.WorkflowAbortException));
                    } 
                    else
                    {
                        ScheduleRuntimeWorkItems();
 
                        if (workItem.ExceptionToPropagate != null)
                        { 
                            resumptionAction = Scheduler.CreateNotifyUnhandledExceptionAction(workItem.ExceptionToPropagate, workItem.OriginalExceptionSource); 
                        }
                    } 
                }
            }
            finally
            { 
                if (resumptionAction != Scheduler.YieldSilently)
                { 
                    workItem.Dispose(this); 
                }
            } 

            Fx.Assert(resumptionAction != Scheduler.YieldSilently, "should not reach this section if we've yielded earlier");
            this.scheduler.InternalResume(resumptionAction);
        } 

        internal void FinishWorkItemAfterTracking(WorkItem workItem) 
        { 
            Scheduler.RequestedAction resumptionAction = Scheduler.Continue;
 
            try
            {
                if (workItem.WorkflowAbortException != null)
                { 
                    // We resume the scheduler even after abort to make sure that
                    // the proper events are raised. 
                    AbortWorkflowInstance(new OperationCanceledException(SR.TrackingRelatedWorkflowAbort, workItem.WorkflowAbortException)); 
                }
                else 
                {
                    ScheduleRuntimeWorkItems();

                    if (workItem.ExceptionToPropagate != null) 
                    {
                        resumptionAction = Scheduler.CreateNotifyUnhandledExceptionAction(workItem.ExceptionToPropagate, workItem.OriginalExceptionSource); 
                    } 
                }
            } 
            finally
            {
                workItem.Dispose(this);
            } 

            this.scheduler.InternalResume(resumptionAction); 
        } 

        void ScheduleRuntimeWorkItems() 
        {
            if (this.runtimeTransaction != null && this.runtimeTransaction.ShouldScheduleCompletion)
            {
                this.scheduler.PushWork(new CompleteTransactionWorkItem(this.runtimeTransaction.IsolationScope)); 
                return;
            } 
 
            if (this.persistenceWaiters != null && this.persistenceWaiters.Count > 0 &&
                this.IsPersistable) 
            {
                PersistenceWaiter waiter = this.persistenceWaiters.Dequeue();

                while (waiter != null && waiter.WaitingInstance.IsCompleted) 
                {
                    // We just skip completed instance so we don't have to deal 
                    // with the housekeeping are arbitrary removal from our 
                    // queue
 
                    if (this.persistenceWaiters.Count == 0)
                    {
                        waiter = null;
                    } 
                    else
                    { 
                        waiter = this.persistenceWaiters.Dequeue(); 
                    }
                } 

                if (waiter != null)
                {
                    this.scheduler.PushWork(waiter.CreateWorkItem()); 
                    return;
                } 
            } 
        }
 
        internal void AbortActivityInstance(ActivityInstance instance, Exception reason)
        {
            instance.Abort(this, this.bookmarkManager, reason, true);
 
            if (instance.CompletionBookmark != null)
            { 
                instance.CompletionBookmark.CheckForCancelation(); 
            }
            else if (instance.Parent != null) 
            {
                instance.CompletionBookmark = new CompletionBookmark();
            }
 
            ScheduleCompletionBookmark(instance);
        } 
 
        internal Exception CompleteActivityInstance(ActivityInstance targetInstance)
        { 
            Exception exceptionToPropagate = null;

            // 1. Handle any root related work
            HandleRootCompletion(targetInstance); 

            // 2. Schedule the completion bookmark 
            // We MUST schedule the completion bookmark before 
            // we dispose the environment because we take this
            // opportunity to gather up any output values. 
            ScheduleCompletionBookmark(targetInstance);

            if (!targetInstance.HasNotExecuted)
            { 
                DebugActivityCompleted(targetInstance);
            } 
 
            // 3. Cleanup environmental resources (properties, handles, mapped locations)
            try 
            {
                if (targetInstance.PropertyManager != null)
                {
                    targetInstance.PropertyManager.UnregisterProperties(targetInstance, targetInstance.Activity.MemberOf); 
                }
 
                if (IsSecondaryRoot(targetInstance)) 
                {
                    // We need to appropriately remove references, dispose 
                    // environments, and remove instance map entries for
                    // all environments in this chain
                    LocationEnvironment environment = targetInstance.Environment;
 
                    if (targetInstance.IsEnvironmentOwner)
                    { 
                        environment.RemoveReference(true); 

                        if (environment.ShouldDispose) 
                        {
                            // Unintialize all handles declared in this environment.
                            environment.UninitializeHandles(targetInstance);
 
                            environment.Dispose();
                        } 
 
                        environment = environment.Parent;
                    } 

                    while (environment != null)
                    {
                        environment.RemoveReference(false); 

                        if (environment.ShouldDispose) 
                        { 
                             // Unintialize all handles declared in this environment.
                            environment.UninitializeHandles(targetInstance); 

                            environment.Dispose();

                            // This also implies that the owner is complete so we should 
                            // remove it from the map
                            if (this.instanceMap != null) 
                            { 
                                this.instanceMap.RemoveEntry(environment);
                            } 
                        }

                        environment = environment.Parent;
                    } 
                }
                else if (targetInstance.IsEnvironmentOwner) 
                { 
                    targetInstance.Environment.RemoveReference(true);
 
                    if (targetInstance.Environment.ShouldDispose)
                    {
                        // Unintialize all handles declared in this environment.
                        targetInstance.Environment.UninitializeHandles(targetInstance); 

                        targetInstance.Environment.Dispose(); 
                    } 
                    else if (this.instanceMap != null)
                    { 
                        // Someone else is referencing this environment
                        // Note that we don't use TryAdd since no-one else should have
                        // added it before.
                        this.instanceMap.AddEntry(targetInstance.Environment); 
                    }
                } 
            } 
            catch (Exception e)
            { 
                if (Fx.IsFatal(e))
                {
                    throw;
                } 

                exceptionToPropagate = e; 
            } 

            // 4. Cleanup remaining instance related resources (bookmarks, program mapping) 
            targetInstance.MarkAsComplete(this.bookmarkScopeManager, this.bookmarkManager);

            // 5. Track our final state
            targetInstance.FinalizeState(this, exceptionToPropagate != null); 

            return exceptionToPropagate; 
        } 

        internal bool TryGetPendingOperation(ActivityInstance instance, out AsyncOperationContext asyncContext) 
        {
            if (this.activeOperations != null)
            {
                return this.activeOperations.TryGetValue(instance, out asyncContext); 
            }
            else 
            { 
                asyncContext = null;
                return false; 
            }
        }

        internal void CancelPendingOperation(ActivityInstance instance) 
        {
            AsyncOperationContext asyncContext; 
            if (TryGetPendingOperation(instance, out asyncContext)) 
            {
                if (asyncContext.IsStillActive) 
                {
                    asyncContext.CancelOperation();
                }
            } 
        }
 
        internal void HandleRootCompletion(ActivityInstance completedInstance) 
        {
            if (completedInstance.Parent == null) 
            {
                if (completedInstance == this.rootInstance)
                {
                    this.shouldRaiseMainBodyComplete = true; 

                    Fx.Assert(this.executionState == ActivityInstanceState.Executing, "We shouldn't have a guess at our completion state yet."); 
 
                    // We start by assuming our completion state will match the root instance.
                    this.executionState = this.rootInstance.State; 
                    this.rootEnvironment = this.rootInstance.Environment;
                }
                else
                { 
                    Fx.Assert(this.executingSecondaryRootInstances.Contains(completedInstance), "An instance which is not the main root and doesn't have an execution parent must be an executing secondary root.");
                    this.executingSecondaryRootInstances.Remove(completedInstance); 
                } 

                // We just had a root complete, let's see if we're all the way done 
                // and should gather outputs from the root.  Note that we wait until
                // everything completes in case the root environment was detached.
                if (this.rootInstance.IsCompleted
                    && (this.executingSecondaryRootInstances == null || this.executingSecondaryRootInstances.Count == 0)) 
                {
                    GatherRootOutputs(); 
 
                    // uninitialize any host-provided handles
                    if (this.rootPropertyManager != null) 
                    {
                        // and uninitialize host-provided handles
                        HandleInitializationContext context = new HandleInitializationContext(this, null);
                        foreach (ExecutionPropertyManager.ExecutionProperty executionProperty in this.rootPropertyManager.Properties.Values) 
                        {
                            Handle handle = executionProperty.Property as Handle; 
                            if (handle != null) 
                            {
                                handle.Uninitialize(context); 
                            }
                        }
                        context.Dispose();
 
                        // unregister any properties that were registered
                        this.rootPropertyManager.UnregisterProperties(null, null); 
                    } 
                }
            } 
        }

        bool IsSecondaryRoot(ActivityInstance instance)
        { 
            return instance.Parent == null && instance != this.rootInstance;
        } 
 
        void GatherRootOutputs()
        { 
            Fx.Assert(this.workflowOutputs == null, "We should only get workflow outputs when we actually complete which should only happen once.");
            Fx.Assert(ActivityUtilities.IsCompletedState(this.rootInstance.State), "We should only gather outputs when in a completed state.");
            Fx.Assert(this.rootEnvironment != null, "We should have set the root environment");
 
            // We only gather outputs for Closed - not for canceled or faulted
            if (this.rootInstance.State == ActivityInstanceState.Closed) 
            { 
                // We use rootElement here instead of this.rootInstance.Activity
                // because we don't always reload the root instance (like if it 
                // was complete when we last persisted).
                IList rootArguments = this.rootElement.RuntimeArguments;

                for (int i = 0; i < rootArguments.Count; i++) 
                {
                    RuntimeArgument argument = rootArguments[i]; 
 
                    if (ArgumentDirectionHelper.IsOut(argument.Direction))
                    { 
                        if (this.workflowOutputs == null)
                        {
                            this.workflowOutputs = new Dictionary();
                        } 

                        Location location = this.rootEnvironment.GetSpecificLocation(argument.BoundArgument.Id); 
                        if (location == null) 
                        {
                            throw FxTrace.Exception.AsError(new InvalidOperationException(SR.NoOutputLocationWasFound(argument.Name))); 
                        }
                        this.workflowOutputs.Add(argument.Name, location.Value);
                    }
                } 
            }
 
            // GatherRootOutputs only ever gets called once so we can null it out the root environment now. 
            this.rootEnvironment = null;
        } 

        internal void NotifyUnhandledException(Exception exception, ActivityInstance source)
        {
            try 
            {
                this.host.NotifyUnhandledException(exception, source.Activity, source.Id); 
            } 
            catch (Exception e)
            { 
                if (Fx.IsFatal(e))
                {
                    throw;
                } 
                this.AbortWorkflowInstance(e);
            } 
        } 

        internal void OnSchedulerIdle() 
        {
            // If we're terminating we'll call terminate here and
            // then do the normal notification for the host.
            if (this.isTerminatePending) 
            {
                Fx.Assert(this.terminationPendingException != null, "Should have set terminationPendingException at the same time that we set isTerminatePending = true"); 
                this.Terminate(this.terminationPendingException); 
                this.isTerminatePending = false;
            } 

            if (this.IsIdle)
            {
                if (this.transactionContextWaiters != null && this.transactionContextWaiters.Count > 0) 
                {
                    if (this.IsPersistable || (this.transactionContextWaiters[0].IsRequires && this.noPersistCount == 1)) 
                    { 
                        TransactionContextWaiter waiter = this.transactionContextWaiters.Dequeue();
 
                        waiter.WaitingInstance.DecrementBusyCount();
                        waiter.WaitingInstance.WaitingForTransactionContext = false;

                        ScheduleItem(new TransactionContextWorkItem(waiter)); 

                        MarkSchedulerRunning(); 
                        ResumeScheduler(); 

                        return; 
                    }
                }

                if (this.shouldRaiseMainBodyComplete) 
                {
                    this.shouldRaiseMainBodyComplete = false; 
                    if (this.mainRootCompleteBookmark != null) 
                    {
                        BookmarkResumptionResult resumptionResult = this.TryResumeUserBookmark(this.mainRootCompleteBookmark, this.rootInstance.State, false); 
                        this.mainRootCompleteBookmark = null;
                        if (resumptionResult == BookmarkResumptionResult.Success)
                        {
                            this.MarkSchedulerRunning(); 
                            this.ResumeScheduler();
                            return; 
                        } 
                    }
 
                    if (this.executingSecondaryRootInstances == null || this.executingSecondaryRootInstances.Count == 0)
                    {
                        // if we got to this point we're completely done from the executor's point of view.
                        // outputs have been gathered, no more work is happening. Clear out some fields to shrink our 
                        // "completed instance" persistence size
                        Dispose(false); 
                    } 
                }
            } 

            if (this.shouldPauseOnCanPersist && this.IsPersistable)
            {
                this.shouldPauseOnCanPersist = false; 
            }
 
            try 
            {
                this.host.NotifyPaused(); 
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e)) 
                {
                    throw; 
                } 
                this.AbortWorkflowInstance(e);
            } 
        }

        public void Open(SynchronizationContext synchronizationContext)
        { 
            this.scheduler.Open(synchronizationContext);
        } 
 
        public void PauseScheduler()
        { 
            // Since we don't require calls to WorkflowInstanceControl.Pause to be synchronized
            // by the caller, we need to check for null here
            Scheduler localScheduler = this.scheduler;
 
            if (localScheduler != null)
            { 
                localScheduler.Pause(); 
            }
        } 

        public object PrepareForSerialization()
        {
            if (this.host.HasTrackingParticipant) 
            {
                this.nextTrackingRecordNumber = this.host.TrackingProvider.NextTrackingRecordNumber; 
                this.hasTrackedStarted = this.host.HasTrackedStarted; 
            }
            return this; 
        }

        public void RequestPersist(Bookmark onPersistBookmark, ActivityInstance requestingInstance)
        { 
            if (this.persistenceWaiters == null)
            { 
                this.persistenceWaiters = new Queue(); 
            }
 
            this.persistenceWaiters.Enqueue(new PersistenceWaiter(onPersistBookmark, requestingInstance));
        }

        void ScheduleCompletionBookmark(ActivityInstance completedInstance) 
        {
            if (completedInstance.CompletionBookmark != null) 
            { 
                this.scheduler.PushWork(completedInstance.CompletionBookmark.GenerateWorkItem(completedInstance, this));
            } 
            else if (completedInstance.Parent != null)
            {
                // Variable defaults and argument expressions always have a parent
                // and never have a CompletionBookmark 
                if (completedInstance.State != ActivityInstanceState.Closed && completedInstance.Parent.HasNotExecuted)
                { 
                    completedInstance.Parent.SetInitializationIncomplete(); 
                }
 
                this.scheduler.PushWork(CreateEmptyWorkItem(completedInstance.Parent));
            }
        }
 
        // This method is called by WorkflowInstance - these are bookmark resumptions
        // originated by the host 
        internal BookmarkResumptionResult TryResumeHostBookmark(Bookmark bookmark, object value) 
        {
            Guid oldActivityId; 
            bool hasTracedResume = TryTraceResume(out oldActivityId);

            BookmarkResumptionResult result = TryResumeUserBookmark(bookmark, value, true);
 
            TraceSuspend(hasTracedResume, oldActivityId);
 
            return result; 
        }
 
        internal BookmarkResumptionResult TryResumeUserBookmark(Bookmark bookmark, object value, bool isExternal)
        {
            if (this.isDisposed)
            { 
                return BookmarkResumptionResult.NotFound;
            } 
 
            ActivityInstance isolationInstance = null;
 
            if (this.runtimeTransaction != null)
            {
                isolationInstance = this.runtimeTransaction.IsolationScope;
            } 

            ActivityExecutionWorkItem resumeExecutionWorkItem; 
 
            BookmarkResumptionResult result = this.bookmarkManager.TryGenerateWorkItem(this, isExternal, ref bookmark, value, isolationInstance, out resumeExecutionWorkItem);
 
            if (result == BookmarkResumptionResult.Success)
            {
                this.scheduler.EnqueueWork(resumeExecutionWorkItem);
 
                if (this.ShouldTrackBookmarkResumptionRecords)
                { 
                    AddTrackingRecord(new BookmarkResumptionRecord(this.WorkflowInstanceId, bookmark, resumeExecutionWorkItem.ActivityInstance, value)); 
                }
            } 
            else if (result == BookmarkResumptionResult.NotReady)
            {
                // We had the bookmark but this is not an appropriate time to resume it
                // so we won't do anything here 
            }
            else if (bookmark == Bookmark.AsyncOperationCompletionBookmark) 
            { 
                Fx.Assert(result == BookmarkResumptionResult.NotFound, "This BookmarkNotFound is actually a well-known bookmark.");
 
                AsyncOperationContext.CompleteData data = (AsyncOperationContext.CompleteData)value;

                data.CompleteOperation();
 
                result = BookmarkResumptionResult.Success;
            } 
 
            return result;
        } 

        internal ReadOnlyCollection GetAllBookmarks()
        {
            List bookmarks = CollectExternalBookmarks(); 

            if (bookmarks != null) 
            { 
                return new ReadOnlyCollection(bookmarks);
            } 
            else
            {
                return EmptyBookmarkInfoCollection;
            } 
        }
 
        List CollectExternalBookmarks() 
        {
            List bookmarks = null; 

            if (this.bookmarkManager != null && this.bookmarkManager.HasBookmarks)
            {
                bookmarks = new List(); 

                this.bookmarkManager.PopulateBookmarkInfo(bookmarks); 
            } 

            if (this.bookmarkScopeManager != null) 
            {
                this.bookmarkScopeManager.PopulateBookmarkInfo(ref bookmarks);
            }
 
            if (bookmarks == null || bookmarks.Count == 0)
            { 
                return null; 
            }
            else 
            {
                return bookmarks;
            }
        } 

        internal ReadOnlyCollection GetBookmarks(BookmarkScope scope) 
        { 
            if (this.bookmarkScopeManager == null)
            { 
                return EmptyBookmarkInfoCollection;
            }
            else
            { 
                ReadOnlyCollection bookmarks = this.bookmarkScopeManager.GetBookmarks(scope);
 
                if (bookmarks == null) 
                {
                    return EmptyBookmarkInfoCollection; 
                }
                else
                {
                    return bookmarks; 
                }
            } 
        } 

        internal IAsyncResult BeginResumeBookmark(Bookmark bookmark, object value, TimeSpan timeout, AsyncCallback callback, object state) 
        {
            return this.host.OnBeginResumeBookmark(bookmark, value, timeout, callback, state);
        }
 
        internal BookmarkResumptionResult EndResumeBookmark(IAsyncResult result)
        { 
            return this.host.OnEndResumeBookmark(result); 
        }
 
        // This is only called by WorkflowInstance so it behaves like TryResumeUserBookmark with must
        // run work item set to true
        internal BookmarkResumptionResult TryResumeBookmark(Bookmark bookmark, object value, BookmarkScope scope)
        { 
            // We have to perform all of this work with tracing set up
            // since we might initialize a sub-instance while generating 
            // the work item. 
            Guid oldActivityId;
            bool hasTracedResume = TryTraceResume(out oldActivityId); 

            ActivityInstance isolationInstance = null;

            if (this.runtimeTransaction != null) 
            {
                isolationInstance = this.runtimeTransaction.IsolationScope; 
            } 

            bool hasOperations = this.activeOperations != null && this.activeOperations.Count > 0; 

            ActivityExecutionWorkItem resumeExecutionWorkItem;
            BookmarkResumptionResult result = this.BookmarkScopeManager.TryGenerateWorkItem(this, ref bookmark, scope, value, isolationInstance, hasOperations || this.bookmarkManager.HasBookmarks, out resumeExecutionWorkItem);
 
            if (result == BookmarkResumptionResult.Success)
            { 
                this.scheduler.EnqueueWork(resumeExecutionWorkItem); 

                if (this.ShouldTrackBookmarkResumptionRecords) 
                {
                    AddTrackingRecord(new BookmarkResumptionRecord(this.WorkflowInstanceId, bookmark, resumeExecutionWorkItem.ActivityInstance, value));
                }
            } 

            TraceSuspend(hasTracedResume, oldActivityId); 
 
            return result;
        } 

        public void MarkSchedulerRunning()
        {
            this.scheduler.MarkRunning(); 
        }
 
        public void Run() 
        {
            ResumeScheduler(); 
        }

        void ResumeScheduler()
        { 
            this.scheduler.Resume();
        } 
 
        internal void ScheduleItem(WorkItem workItem)
        { 
            this.scheduler.PushWork(workItem);
        }

        public void ScheduleRootActivity(Activity activity, IDictionary argumentValueOverrides, IList hostProperties) 
        {
            Fx.Assert(this.rootInstance == null, "ScheduleRootActivity should only be called once"); 
 
            if (hostProperties != null && hostProperties.Count > 0)
            { 
                Dictionary rootProperties = new Dictionary(hostProperties.Count);
                HandleInitializationContext context = new HandleInitializationContext(this, null);
                for (int i = 0; i < hostProperties.Count; i++)
                { 
                    Handle handle = hostProperties[i];
                    handle.Initialize(context); 
                    rootProperties.Add(handle.ExecutionPropertyName, new ExecutionPropertyManager.ExecutionProperty(handle.ExecutionPropertyName, handle, null)); 
                }
                context.Dispose(); 

                this.rootPropertyManager = new ExecutionPropertyManager(null, rootProperties);
            }
 
            Guid oldActivityId;
            bool hasTracedStart = TryTraceStart(out oldActivityId); 
 
            // Create and initialize the root instance
            this.rootInstance = new ActivityInstance(activity) 
            {
                PropertyManager = this.rootPropertyManager
            };
            this.rootElement = activity; 

            Fx.Assert(this.lastInstanceId == 0, "We should only hit this path once"); 
            this.lastInstanceId++; 

            bool requiresSymbolResolution = this.rootInstance.Initialize(null, this.instanceMap, null, this.lastInstanceId, this); 

            if (TD.ActivityScheduledIsEnabled())
            {
                TraceActivityScheduled(null, activity, this.rootInstance); 
            }
 
            // Add the work item for executing the root 
            this.scheduler.PushWork(new ExecuteRootWorkItem(this.rootInstance, requiresSymbolResolution, argumentValueOverrides));
 
            TraceSuspend(hasTracedStart, oldActivityId);
        }

        public void RegisterMainRootCompleteCallback(Bookmark bookmark) 
        {
            this.mainRootCompleteBookmark = bookmark; 
        } 

        public ActivityInstance ScheduleSecondaryRootActivity(Activity activity, LocationEnvironment environment) 
        {
            ActivityInstance secondaryRoot = ScheduleActivity(activity, null, null, null, environment);

            while (environment != null) 
            {
                environment.AddReference(); 
                environment = environment.Parent; 
            }
 
            if (this.executingSecondaryRootInstances == null)
            {
                this.executingSecondaryRootInstances = new List();
            } 

            this.executingSecondaryRootInstances.Add(secondaryRoot); 
 
            return secondaryRoot;
        } 

        public ActivityInstance ScheduleActivity(Activity activity, ActivityInstance parent,
            CompletionBookmark completionBookmark, FaultBookmark faultBookmark, LocationEnvironment parentEnvironment)
        { 
            return ScheduleActivity(activity, parent, completionBookmark, faultBookmark, parentEnvironment, null, null);
        } 
 
        public ActivityInstance ScheduleDelegate(ActivityDelegate activityDelegate, IDictionary inputParameters, ActivityInstance parent, LocationEnvironment executionEnvironment,
            CompletionBookmark completionBookmark, FaultBookmark faultBookmark) 
        {
            Fx.Assert(activityDelegate.Owner != null, "activityDelegate must have an owner");
            Fx.Assert(parent != null, "activityDelegate should have a parent activity instance");
 
            ActivityInstance handlerInstance;
 
            if (activityDelegate.Handler == null) 
            {
                handlerInstance = ActivityInstance.CreateCompletedInstance(new EmptyDelegateActivity()); 
                handlerInstance.CompletionBookmark = completionBookmark;
                ScheduleCompletionBookmark(handlerInstance);
            }
            else 
            {
                handlerInstance = CreateUninitalizedActivityInstance(activityDelegate.Handler, parent, completionBookmark, faultBookmark); 
                bool requiresSymbolResolution = handlerInstance.Initialize(parent, this.instanceMap, executionEnvironment, this.lastInstanceId, this, activityDelegate.RuntimeDelegateArguments.Count); 

                IList activityDelegateParameters = activityDelegate.RuntimeDelegateArguments; 
                for (int i = 0; i < activityDelegateParameters.Count; i++)
                {
                    RuntimeDelegateArgument runtimeArgument = activityDelegateParameters[i];
 
                    if (runtimeArgument.BoundArgument != null)
                    { 
                        string delegateParameterName = runtimeArgument.Name; 

                        // Populate argument location. Set it's value in the activity handler's 
                        // instance environment only if it is a DelegateInArgument.
                        Location newLocation = runtimeArgument.BoundArgument.CreateLocation();
                        handlerInstance.Environment.Declare(runtimeArgument.BoundArgument, newLocation, handlerInstance);
 
                        if (ArgumentDirectionHelper.IsIn(runtimeArgument.Direction))
                        { 
                            if (inputParameters != null && inputParameters.Count > 0) 
                            {
                                newLocation.Value = inputParameters[delegateParameterName]; 
                            }
                        }
                    }
                } 

                if (TD.ActivityScheduledIsEnabled()) 
                { 
                    TraceActivityScheduled(parent, activityDelegate.Handler, handlerInstance);
                } 

                if (this.ShouldTrackActivityScheduledRecords)
                {
                    AddTrackingRecord(new ActivityScheduledRecord(this.WorkflowInstanceId, parent, handlerInstance)); 
                }
 
                ScheduleBody(handlerInstance, requiresSymbolResolution, null, null); 
            }
 
            return handlerInstance;
        }

        void TraceActivityScheduled(ActivityInstance parent, Activity activity, ActivityInstance scheduledInstance) 
        {
            Fx.Assert(TD.ActivityScheduledIsEnabled(), "This should be checked before calling this helper."); 
 
            if (parent != null)
            { 
                TD.ActivityScheduled(parent.Activity.GetType().ToString(), parent.Activity.DisplayName, parent.Id, activity.GetType().ToString(), activity.DisplayName, scheduledInstance.Id);
            }
            else
            { 
                TD.ActivityScheduled(string.Empty, string.Empty, string.Empty, activity.GetType().ToString(), activity.DisplayName, scheduledInstance.Id);
            } 
        } 

        ActivityInstance CreateUninitalizedActivityInstance(Activity activity, ActivityInstance parent, CompletionBookmark completionBookmark, FaultBookmark faultBookmark) 
        {
            Fx.Assert(activity.IsMetadataCached, "Metadata must be cached for us to process this activity.");

            // 1. Create a new activity instance and setup bookmark callbacks 
            ActivityInstance activityInstance = new ActivityInstance(activity);
 
            if (parent != null) 
            {
                // add a bookmarks to complete at activity.Close/Fault time 
                activityInstance.CompletionBookmark = completionBookmark;
                activityInstance.FaultBookmark = faultBookmark;
                parent.AddChild(activityInstance);
            } 

            // 2. Setup parent and environment machinery, and add to instance's program mapping for persistence (if necessary) 
            if (this.lastInstanceId == long.MaxValue) 
            {
                throw FxTrace.Exception.AsError(new NotSupportedException(SR.OutOfInstanceIds)); 
            }
            this.lastInstanceId++;

            return activityInstance; 
        }
 
        ActivityInstance ScheduleActivity(Activity activity, ActivityInstance parent, 
            CompletionBookmark completionBookmark, FaultBookmark faultBookmark, LocationEnvironment parentEnvironment,
            IDictionary argumentValueOverrides, Location resultLocation) 
        {
            ActivityInstance activityInstance = CreateUninitalizedActivityInstance(activity, parent, completionBookmark, faultBookmark);
            bool requiresSymbolResolution = activityInstance.Initialize(parent, this.instanceMap, parentEnvironment, this.lastInstanceId, this);
 
            if (TD.ActivityScheduledIsEnabled())
            { 
                TraceActivityScheduled(parent, activity, activityInstance); 
            }
 
            if (this.ShouldTrackActivityScheduledRecords)
            {
                AddTrackingRecord(new ActivityScheduledRecord(this.WorkflowInstanceId, parent, activityInstance));
            } 

            ScheduleBody(activityInstance, requiresSymbolResolution, argumentValueOverrides, resultLocation); 
 
            return activityInstance;
        } 

        internal void ScheduleExpression(Activity activity, ActivityInstance parent, LocationEnvironment parentEnvironment, Location resultLocation)
        {
            Fx.Assert(resultLocation != null, "We should always schedule expressions with a result location."); 

            ScheduleActivity(activity, parent, null, null, parentEnvironment, null, resultLocation); 
        } 

        // Argument and variables resolution for root activity is defered to execution time 
        // invocation of this method means that we're ready to schedule Activity.Execute()
        internal void ScheduleBody(ActivityInstance activityInstance, bool requiresSymbolResolution,
            IDictionary argumentValueOverrides, Location resultLocation)
        { 
            if (resultLocation == null)
            { 
                ExecuteActivityWorkItem workItem = this.ExecuteActivityWorkItemPool.Acquire(); 
                workItem.Initialize(activityInstance, requiresSymbolResolution, argumentValueOverrides);
 
                this.scheduler.PushWork(workItem);
            }
            else
            { 
                this.scheduler.PushWork(new ExecuteExpressionWorkItem(activityInstance, requiresSymbolResolution, argumentValueOverrides, resultLocation));
            } 
        } 

        public NoPersistProperty CreateNoPersistProperty() 
        {
            return new NoPersistProperty(this);
        }
 
        public AsyncOperationContext SetupAsyncOperationBlock(ActivityInstance owningActivity)
        { 
            if (this.activeOperations != null && this.activeOperations.ContainsKey(owningActivity)) 
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.OnlyOneOperationPerActivity)); 
            }

            this.EnterNoPersist();
 
            AsyncOperationContext context = new AsyncOperationContext(this, owningActivity);
 
            if (this.activeOperations == null) 
            {
                this.activeOperations = new Dictionary(); 
            }

            this.activeOperations.Add(owningActivity, context);
 
            return context;
        } 
 
        // Must always be called from a workflow thread
        public void CompleteOperation(ActivityInstance owningInstance, BookmarkCallback callback, object state) 
        {
            Fx.Assert(callback != null, "Use the other overload if callback is null.");

            CompleteAsyncOperationWorkItem workItem = new CompleteAsyncOperationWorkItem( 
                new BookmarkCallbackWrapper(callback, owningInstance),
                this.bookmarkManager.GenerateTempBookmark(), 
                state); 
            CompleteOperation(workItem);
        } 

        // Must always be called from a workflow thread
        public void CompleteOperation(WorkItem asyncCompletionWorkItem)
        { 
            this.scheduler.EnqueueWork(asyncCompletionWorkItem);
            CompleteOperation(asyncCompletionWorkItem.ActivityInstance, false); 
        } 

        // Must always be called from a workflow thread 
        public void CompleteOperation(ActivityInstance owningInstance)
        {
            CompleteOperation(owningInstance, true);
        } 

        void CompleteOperation(ActivityInstance owningInstance, bool exitNoPersist) 
        { 
            Fx.Assert(owningInstance != null, "Cannot be called with a null instance.");
            Fx.Assert(this.activeOperations.ContainsKey(owningInstance), "The owning instance must be in the list if we've gotten here."); 

            this.activeOperations.Remove(owningInstance);

            owningInstance.DecrementBusyCount(); 

            if (exitNoPersist) 
            { 
                this.ExitNoPersist();
            } 
        }

        internal void AddHandle(Handle handleToAdd)
        { 
            if (this.handles == null)
            { 
                this.handles = new List(); 
            }
            this.handles.Add(handleToAdd); 
        }

        [DataContract]
        class PersistenceWaiter 
        {
            public PersistenceWaiter(Bookmark onPersist, ActivityInstance waitingInstance) 
            { 
                this.OnPersistBookmark = onPersist;
                this.WaitingInstance = waitingInstance; 
            }

            [DataMember]
            public Bookmark OnPersistBookmark 
            {
                get; 
                private set; 
            }
 
            [DataMember]
            public ActivityInstance WaitingInstance
            {
                get; 
                private set;
            } 
 
            public WorkItem CreateWorkItem()
            { 
                return new PersistWorkItem(this);
            }

            [DataContract] 
            class PersistWorkItem : WorkItem
            { 
                [DataMember] 
                PersistenceWaiter waiter;
 
                public PersistWorkItem(PersistenceWaiter waiter)
                    : base(waiter.WaitingInstance)
                {
                    this.waiter = waiter; 
                }
 
                public override bool IsValid 
                {
                    get 
                    {
                        return true;
                    }
                } 

                public override ActivityInstance PropertyManagerOwner 
                { 
                    get
                    { 
                        // Persist should not pick up user transaction / identity.
                        return null;
                    }
                } 

                public override void TraceCompleted() 
                { 
                    TraceRuntimeWorkItemCompleted();
                } 

                public override void TraceScheduled()
                {
                    TraceRuntimeWorkItemScheduled(); 
                }
 
                public override void TraceStarting() 
                {
                    TraceRuntimeWorkItemStarting(); 
                }

                public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
                { 
                    if (executor.TryResumeUserBookmark(this.waiter.OnPersistBookmark, null, false) != BookmarkResumptionResult.Success)
                    { 
                        Fx.Assert("This should always be resumable."); 
                    }
 
                    IAsyncResult result = null;

                    try
                    { 
                        result = executor.host.OnBeginPersist(Fx.ThunkCallback(new AsyncCallback(OnPersistComplete)), executor);
 
                        if (result.CompletedSynchronously) 
                        {
                            executor.host.OnEndPersist(result); 
                        }
                    }
                    catch (Exception e)
                    { 
                        if (Fx.IsFatal(e))
                        { 
                            throw; 
                        }
 
                        this.workflowAbortException = e;
                    }

                    return result == null || result.CompletedSynchronously; 
                }
 
                void OnPersistComplete(IAsyncResult result) 
                {
                    if (result.CompletedSynchronously) 
                    {
                        return;
                    }
 
                    ActivityExecutor executor = (ActivityExecutor)result.AsyncState;
 
                    try 
                    {
                        executor.host.OnEndPersist(result); 
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e)) 
                        {
                            throw; 
                        } 

                        this.workflowAbortException = e; 
                    }

                    executor.FinishWorkItem(this);
                } 

                public override void PostProcess(ActivityExecutor executor) 
                { 
                    if (this.ExceptionToPropagate != null)
                    { 
                        executor.AbortActivityInstance(this.waiter.WaitingInstance, this.ExceptionToPropagate);
                    }
                }
            } 
        }
 
        [DataContract] 
        class AbortActivityWorkItem : WorkItem
        { 
            [DataMember]
            Exception reason;
            [DataMember]
            ActivityInstanceReference originalSource; 

            public AbortActivityWorkItem(ActivityInstance activityInstance, Exception reason, ActivityInstanceReference originalSource) 
                : base(activityInstance) 
            {
                this.reason = reason; 
                this.originalSource = originalSource;

                this.IsEmpty = true;
            } 

            public override ActivityInstance OriginalExceptionSource 
            { 
                get
                { 
                    return this.originalSource.ActivityInstance;
                }
            }
 
            public override bool IsValid
            { 
                get 
                {
                    return this.ActivityInstance.State == ActivityInstanceState.Executing; 
                }
            }

            public override ActivityInstance PropertyManagerOwner 
            {
                get 
                { 
                    Fx.Assert("This is never called.");
 
                    return null;
                }
            }
 
            public override void TraceCompleted()
            { 
                TraceRuntimeWorkItemCompleted(); 
            }
 
            public override void TraceScheduled()
            {
                TraceRuntimeWorkItemScheduled();
            } 

            public override void TraceStarting() 
            { 
                TraceRuntimeWorkItemStarting();
            } 

            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
            {
                Fx.Assert("This is never called"); 

                return true; 
            } 

            public override void PostProcess(ActivityExecutor executor) 
            {
                executor.AbortActivityInstance(this.ActivityInstance, this.reason);

                // We always repropagate the exception from here 
                this.ExceptionToPropagate = this.reason;
            } 
        } 

        [DataContract] 
        class CompleteAsyncOperationWorkItem : BookmarkWorkItem
        {
            public CompleteAsyncOperationWorkItem(BookmarkCallbackWrapper wrapper, Bookmark bookmark, object value)
                : base(wrapper, bookmark, value) 
            {
                this.ExitNoPersistRequired = true; 
            } 
        }
 
        [DataContract]
        class CancelActivityWorkItem : ActivityExecutionWorkItem
        {
            public CancelActivityWorkItem(ActivityInstance activityInstance) 
                : base(activityInstance)
            { 
            } 

            public override void TraceCompleted() 
            {
                if (TD.CompleteCancelActivityWorkItemIsEnabled())
                {
                    TD.CompleteCancelActivityWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id); 
                }
            } 
 
            public override void TraceScheduled()
            { 
                if (TD.ScheduleCancelActivityWorkItemIsEnabled())
                {
                    TD.ScheduleCancelActivityWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id);
                } 
            }
 
            public override void TraceStarting() 
            {
                if (TD.StartCancelActivityWorkItemIsEnabled()) 
                {
                    TD.StartCancelActivityWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id);
                }
            } 

            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) 
            { 
                try
                { 
                    this.ActivityInstance.Cancel(executor, bookmarkManager);
                }
                catch (Exception e)
                { 
                    if (Fx.IsFatal(e))
                    { 
                        throw; 
                    }
 
                    this.ExceptionToPropagate = e;
                }

                return true; 
            }
        } 
 
        [DataContract]
        class ExecuteActivityWorkItem : ActivityExecutionWorkItem 
        {
            [DataMember(EmitDefaultValue = false)]
            bool requiresSymbolResolution;
            [DataMember(EmitDefaultValue = false)] 
            IDictionary argumentValueOverrides;
 
            // Called by the pool. 
            public ExecuteActivityWorkItem()
            { 
                this.IsPooled = true;
            }

            // Called by non-pool subclasses. 
            protected ExecuteActivityWorkItem(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary argumentValueOverrides)
                : base(activityInstance) 
            { 
                this.requiresSymbolResolution = requiresSymbolResolution;
                this.argumentValueOverrides = argumentValueOverrides; 
            }

            public void Initialize(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary argumentValueOverrides)
            { 
                base.Reinitialize(activityInstance);
                this.requiresSymbolResolution = requiresSymbolResolution; 
                this.argumentValueOverrides = argumentValueOverrides; 
            }
 
            protected override void ReleaseToPool(ActivityExecutor executor)
            {
                base.ClearForReuse();
                this.requiresSymbolResolution = false; 
                this.argumentValueOverrides = null;
 
                executor.ExecuteActivityWorkItemPool.Release(this); 
            }
 
            public override void TraceScheduled()
            {
                if (TD.ScheduleExecuteActivityWorkItemIsEnabled())
                { 
                    TD.ScheduleExecuteActivityWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id);
                } 
            } 

            public override void TraceStarting() 
            {
                if (TD.StartExecuteActivityWorkItemIsEnabled())
                {
                    TD.StartExecuteActivityWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id); 
                }
            } 
 
            public override void TraceCompleted()
            { 
                if (TD.CompleteExecuteActivityWorkItemIsEnabled())
                {
                    TD.CompleteExecuteActivityWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id);
                } 
            }
 
            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) 
            {
                return ExecuteBody(executor, bookmarkManager, null); 
            }

            protected bool ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)
            { 
                try
                { 
                    if (this.requiresSymbolResolution) 
                    {
                        if (!this.ActivityInstance.ResolveArguments(executor, this.argumentValueOverrides, resultLocation)) 
                        {
                            return true;
                        }
 
                        if (!this.ActivityInstance.ResolveVariables(executor))
                        { 
                            return true; 
                        }
                    } 
                    // We want to do this if there was no symbol resolution or if ResolveVariables completed
                    // synchronously.
                    this.ActivityInstance.SetInitializedSubstate(executor);
 
                    if (executor.IsDebugged())
                    { 
                        executor.debugController.ActivityStarted(this.ActivityInstance); 
                    }
 
                    this.ActivityInstance.Execute(executor, bookmarkManager);
                }
                catch (Exception e)
                { 
                    if (Fx.IsFatal(e))
                    { 
                        throw; 
                    }
 
                    this.ExceptionToPropagate = e;
                }

                return true; 
            }
        } 
 
        [DataContract]
        class ExecuteRootWorkItem : ExecuteActivityWorkItem 
        {
            public ExecuteRootWorkItem(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary argumentValueOverrides)
                : base(activityInstance, requiresSymbolResolution, argumentValueOverrides)
            { 
            }
 
            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) 
            {
                if (executor.ShouldTrackActivityScheduledRecords) 
                {
                    executor.AddTrackingRecord(
                        new ActivityScheduledRecord(
                            executor.WorkflowInstanceId, 
                            null,
                            this.ActivityInstance)); 
                } 

                return ExecuteBody(executor, bookmarkManager, null); 
            }
        }

        [DataContract] 
        class ExecuteExpressionWorkItem : ExecuteActivityWorkItem
        { 
            [DataMember] 
            Location resultLocation;
 
            public ExecuteExpressionWorkItem(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary argumentValueOverrides, Location resultLocation)
                : base(activityInstance, requiresSymbolResolution, argumentValueOverrides)
            {
                Fx.Assert(resultLocation != null, "We should only use this work item when we are resolving arguments/variables and therefore have a result location."); 
                this.resultLocation = resultLocation;
            } 
 
            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
            { 
                return ExecuteBody(executor, bookmarkManager, resultLocation);
            }
        }
 
        [DataContract]
        class RethrowExceptionWorkItem : WorkItem 
        { 
            [DataMember]
            Exception exception; 
            [DataMember]
            ActivityInstanceReference source;

            public RethrowExceptionWorkItem(ActivityInstance activityInstance, Exception exception, ActivityInstanceReference source) 
                : base(activityInstance)
            { 
                this.exception = exception; 
                this.source = source;
                this.IsEmpty = true; 
            }

            public override bool IsValid
            { 
                get
                { 
                    return this.ActivityInstance.State == ActivityInstanceState.Executing; 
                }
            } 

            public override ActivityInstance PropertyManagerOwner
            {
                get 
                {
                    Fx.Assert("This is never called."); 
 
                    return null;
                } 
            }

            public override ActivityInstance OriginalExceptionSource
            { 
                get
                { 
                    return this.source.ActivityInstance; 
                }
            } 

            public override void TraceCompleted()
            {
                TraceRuntimeWorkItemCompleted(); 
            }
 
            public override void TraceScheduled() 
            {
                TraceRuntimeWorkItemScheduled(); 
            }

            public override void TraceStarting()
            { 
                TraceRuntimeWorkItemStarting();
            } 
 
            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
            { 
                Fx.Assert("This shouldn't be called because we are IsEmpty = true.");

                return true;
            } 

            public override void PostProcess(ActivityExecutor executor) 
            { 
                executor.AbortActivityInstance(this.ActivityInstance, this.ExceptionToPropagate);
                this.ExceptionToPropagate = this.exception; 
            }
        }

        [DataContract] 
        class TransactionContextWaiter
        { 
            public TransactionContextWaiter(ActivityInstance instance, bool isRequires, RuntimeTransactionHandle handle, TransactionContextWaiterCallbackWrapper callbackWrapper, object state) 
            {
                Fx.Assert(instance != null, "Must have an instance."); 
                Fx.Assert(handle != null, "Must have a handle.");
                Fx.Assert(callbackWrapper != null, "Must have a callbackWrapper");

                this.WaitingInstance = instance; 
                this.IsRequires = isRequires;
                this.Handle = handle; 
                this.State = state; 
                this.CallbackWrapper = callbackWrapper;
            } 

            [DataMember]
            public ActivityInstance WaitingInstance
            { 
                get;
                private set; 
            } 

            [DataMember(EmitDefaultValue = false)] 
            public bool IsRequires
            {
                get;
                private set; 
            }
 
            [DataMember] 
            public RuntimeTransactionHandle Handle
            { 
                get;
                private set;
            }
 
            [DataMember(EmitDefaultValue = false)]
            public object State 
            { 
                get;
                private set; 
            }

            [DataMember]
            public TransactionContextWaiterCallbackWrapper CallbackWrapper 
            {
                get; 
                private set; 
            }
        } 

        [DataContract]
        class TransactionContextWaiterCallbackWrapper : CallbackWrapper
        { 
            static Type callbackType = typeof(Action);
            static Type[] transactionCallbackParameterTypes = new Type[] { typeof(NativeActivityTransactionContext), typeof(object) }; 
 
            public TransactionContextWaiterCallbackWrapper(Action action, ActivityInstance owningInstance)
                :base(action,owningInstance) 
            {
            }

            public void Invoke(NativeActivityTransactionContext context, object value) 
            {
                EnsureCallback(callbackType, transactionCallbackParameterTypes); 
                Action callback = (Action)this.Callback; 
                callback(context, value);
            } 
        }

        // This is not DataContract because this is always scheduled in a no-persist zone.
        // This work items exits the no persist zone when it is released. 
        class CompleteTransactionWorkItem : WorkItem
        { 
            static AsyncCallback persistCompleteCallback; 
            static AsyncCallback commitCompleteCallback;
            static Action outcomeDeterminedCallback; 

            RuntimeTransactionData runtimeTransaction;
            ActivityExecutor executor;
 
            public CompleteTransactionWorkItem(ActivityInstance instance)
                : base(instance) 
            { 
                this.ExitNoPersistRequired = true;
            } 

            static AsyncCallback PersistCompleteCallback
            {
                get 
                {
                    if (persistCompleteCallback == null) 
                    { 
                        persistCompleteCallback = Fx.ThunkCallback(new AsyncCallback(OnPersistComplete));
                    } 

                    return persistCompleteCallback;
                }
            } 

            static AsyncCallback CommitCompleteCallback 
            { 
                get
                { 
                    if (commitCompleteCallback == null)
                    {
                        commitCompleteCallback = Fx.ThunkCallback(new AsyncCallback(OnCommitComplete));
                    } 

                    return commitCompleteCallback; 
                } 
            }
 
            static Action OutcomeDeterminedCallback
            {
                get
                { 
                    if (outcomeDeterminedCallback == null)
                    { 
                        outcomeDeterminedCallback = new Action(OnOutcomeDetermined); 
                    }
 
                    return outcomeDeterminedCallback;
                }
            }
 
            public override bool IsValid
            { 
                get 
                {
                    return true; 
                }
            }

            public override ActivityInstance PropertyManagerOwner 
            {
                get 
                { 
                    return null;
                } 
            }

            public override void TraceCompleted()
            { 
                TraceRuntimeWorkItemCompleted();
            } 
 
            public override void TraceScheduled()
            { 
                TraceRuntimeWorkItemScheduled();
            }

            public override void TraceStarting() 
            {
                TraceRuntimeWorkItemStarting(); 
            } 

            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) 
            {
                this.runtimeTransaction = executor.runtimeTransaction;
                this.executor = executor;
 
                // We need to take care of any pending cancelation
                this.executor.SchedulePendingCancelation(); 
 
                bool completeSelf;
                try 
                {
                    // If the transaction is already rolled back, skip the persistence.  This allows us to avoid aborting the instance.
                    completeSelf = CheckTransactionAborted();
                    if (!completeSelf) 
                    {
                        IAsyncResult result = new TransactionalPersistAsyncResult(this.executor, PersistCompleteCallback, this); 
                        if (result.CompletedSynchronously) 
                        {
                            completeSelf = FinishPersist(result); 
                        }
                    }
                }
                catch (Exception e) 
                {
                    if (Fx.IsFatal(e)) 
                    { 
                        throw;
                    } 

                    HandleException(e);
                    completeSelf = true;
                } 

                if (completeSelf) 
                { 
                    this.executor.runtimeTransaction = null;
 
                    TraceTransactionOutcome();
                    return true;
                }
 
                return false;
            } 
 
            void TraceTransactionOutcome()
            { 
                if (TD.RuntimeTransactionCompleteIsEnabled())
                {
                    TD.RuntimeTransactionComplete(this.runtimeTransaction.TransactionStatus.ToString());
                } 
            }
 
            void HandleException(Exception exception) 
            {
                try 
                {
                    this.runtimeTransaction.OriginalTransaction.Rollback(exception);
                }
                catch (Exception e) 
                {
                    if (Fx.IsFatal(e)) 
                    { 
                        throw;
                    } 

                    this.workflowAbortException = e;
                }
 
                if (this.runtimeTransaction.TransactionHandle.AbortInstanceOnTransactionFailure)
                { 
                    // We might be overwriting a more recent exception from above, but it is 
                    // more important that we tell the user why they failed originally.
                    this.workflowAbortException = exception; 
                }
                else
                {
                    this.ExceptionToPropagate = exception; 
                }
            } 
 
            static void OnPersistComplete(IAsyncResult result)
            { 
                if (result.CompletedSynchronously)
                {
                    return;
                } 

                CompleteTransactionWorkItem thisPtr = (CompleteTransactionWorkItem)result.AsyncState; 
                bool completeSelf = true; 

                try 
                {
                    completeSelf = thisPtr.FinishPersist(result);
                }
                catch (Exception e) 
                {
                    if (Fx.IsFatal(e)) 
                    { 
                        throw;
                    } 

                    thisPtr.HandleException(e);
                    completeSelf = true;
                } 

                if (completeSelf) 
                { 
                    thisPtr.executor.runtimeTransaction = null;
 
                    thisPtr.TraceTransactionOutcome();

                    thisPtr.executor.FinishWorkItem(thisPtr);
                } 
            }
 
            bool FinishPersist(IAsyncResult result) 
            {
                TransactionalPersistAsyncResult.End(result); 

                return CompleteTransaction();
            }
 
            bool CompleteTransaction()
            { 
                PreparingEnlistment enlistment = null; 

                lock (this.runtimeTransaction) 
                {
                    if (this.runtimeTransaction.PendingPreparingEnlistment != null)
                    {
                        enlistment = this.runtimeTransaction.PendingPreparingEnlistment; 
                    }
 
                    this.runtimeTransaction.HasPrepared = true; 
                }
 
                if (enlistment != null)
                {
                    enlistment.Prepared();
                } 

                Transaction original = this.runtimeTransaction.OriginalTransaction; 
 
                DependentTransaction dependentTransaction = original as DependentTransaction;
                if (dependentTransaction != null) 
                {
                    dependentTransaction.Complete();
                    return CheckOutcome();
                } 
                else
                { 
                    CommittableTransaction committableTransaction = original as CommittableTransaction; 
                    if (committableTransaction != null)
                    { 
                        IAsyncResult result = committableTransaction.BeginCommit(CommitCompleteCallback, this);

                        if (result.CompletedSynchronously)
                        { 
                            return FinishCommit(result);
                        } 
                        else 
                        {
                            return false; 
                        }
                    }
                    else
                    { 
                        return CheckOutcome();
                    } 
                } 
            }
 
            static void OnCommitComplete(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                { 
                    return;
                } 
 
                CompleteTransactionWorkItem thisPtr = (CompleteTransactionWorkItem)result.AsyncState;
                bool completeSelf = true; 

                try
                {
                    completeSelf = thisPtr.FinishCommit(result); 
                }
                catch (Exception e) 
                { 
                    if (Fx.IsFatal(e))
                    { 
                        throw;
                    }

                    thisPtr.HandleException(e); 
                    completeSelf = true;
                } 
 
                if (completeSelf)
                { 
                    thisPtr.executor.runtimeTransaction = null;

                    thisPtr.TraceTransactionOutcome();
 
                    thisPtr.executor.FinishWorkItem(thisPtr);
                } 
            } 

            bool FinishCommit(IAsyncResult result) 
            {
                ((CommittableTransaction)this.runtimeTransaction.OriginalTransaction).EndCommit(result);

                return CheckOutcome(); 
            }
 
            bool CheckOutcome() 
            {
                AsyncWaitHandle completionEvent = null; 

                lock (this.runtimeTransaction)
                {
                    TransactionStatus status = this.runtimeTransaction.TransactionStatus; 

                    if (status == TransactionStatus.Active) 
                    { 
                        completionEvent = new AsyncWaitHandle();
                        this.runtimeTransaction.CompletionEvent = completionEvent; 
                    }
                }

                if (completionEvent != null) 
                {
                    if (!completionEvent.WaitAsync(OutcomeDeterminedCallback, this, ActivityDefaults.TransactionCompletionTimeout)) 
                    { 
                        return false;
                    } 
                }

                return FinishCheckOutcome();
            } 

            static void OnOutcomeDetermined(object state, TimeoutException asyncException) 
            { 
                CompleteTransactionWorkItem thisPtr = (CompleteTransactionWorkItem)state;
                bool completeSelf = true; 

                if (asyncException != null)
                {
                    thisPtr.HandleException(asyncException); 
                }
                else 
                { 
                    try
                    { 
                        completeSelf = thisPtr.FinishCheckOutcome();
                    }
                    catch (Exception e)
                    { 
                        if (Fx.IsFatal(e))
                        { 
                            throw; 
                        }
 
                        thisPtr.HandleException(e);
                        completeSelf = true;
                    }
                } 

                if (completeSelf) 
                { 
                    thisPtr.executor.runtimeTransaction = null;
 
                    thisPtr.TraceTransactionOutcome();

                    thisPtr.executor.FinishWorkItem(thisPtr);
                } 
            }
 
            bool FinishCheckOutcome() 
            {
                CheckTransactionAborted(); 
                return true;
            }

            bool CheckTransactionAborted() 
            {
                try 
                { 
                    Fx.ThrowIfTransactionAbortedOrInDoubt(this.runtimeTransaction.OriginalTransaction);
                    return false; 
                }
                catch (TransactionException exception)
                {
                    if (this.runtimeTransaction.TransactionHandle.AbortInstanceOnTransactionFailure) 
                    {
                        this.workflowAbortException = exception; 
                    } 
                    else
                    { 
                        this.ExceptionToPropagate = exception;
                    }
                    return true;
                } 
            }
 
            public override void PostProcess(ActivityExecutor executor) 
            {
            } 

            class TransactionalPersistAsyncResult : AsyncResult
            {
                CompleteTransactionWorkItem workItem; 
                static readonly AsyncCompletion onPersistComplete = new AsyncCompletion(OnPersistComplete);
                readonly ActivityExecutor executor; 
 
                public TransactionalPersistAsyncResult(ActivityExecutor executor, AsyncCallback callback, object state)
                    : base(callback, state) 
                {
                    this.executor = executor;
                    this.workItem = (CompleteTransactionWorkItem)state;
                    IAsyncResult result = null; 
                    using (PrepareTransactionalCall(this.executor.CurrentTransaction))
                    { 
                        try 
                        {
                            result = this.executor.host.OnBeginPersist(PrepareAsyncCompletion(TransactionalPersistAsyncResult.onPersistComplete), this); 
                        }
                        catch (Exception e)
                        {
                            if (Fx.IsFatal(e)) 
                            {
                                throw; 
                            } 
                            this.workItem.workflowAbortException = e;
                            throw; 
                        }
                    }
                    if (SyncContinue(result))
                    { 
                        Complete(true);
                    } 
                } 

                public static void End(IAsyncResult result) 
                {
                    AsyncResult.End(result);
                }
 
                static bool OnPersistComplete(IAsyncResult result)
                { 
                    TransactionalPersistAsyncResult thisPtr = (TransactionalPersistAsyncResult)result.AsyncState; 

                    try 
                    {
                        thisPtr.executor.host.OnEndPersist(result);
                    }
                    catch (Exception e) 
                    {
                        if (Fx.IsFatal(e)) 
                        { 
                            throw;
                        } 
                        thisPtr.workItem.workflowAbortException = e;
                        throw;
                    }
 
                    return true;
                } 
            } 
        }
 
        [DataContract]
        class TransactionContextWorkItem : ActivityExecutionWorkItem
        {
            [DataMember] 
            TransactionContextWaiter waiter;
 
            public TransactionContextWorkItem(TransactionContextWaiter waiter) 
                : base(waiter.WaitingInstance)
            { 
                this.waiter = waiter;

                if (this.waiter.IsRequires)
                { 
                    this.ExitNoPersistRequired = true;
                } 
            } 

            public override void TraceCompleted() 
            {
                if (TD.CompleteTransactionContextWorkItemIsEnabled())
                {
                    TD.CompleteTransactionContextWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id); 
                }
            } 
 
            public override void TraceScheduled()
            { 
                if (TD.ScheduleTransactionContextWorkItemIsEnabled())
                {
                    TD.ScheduleTransactionContextWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id);
                } 
            }
 
            public override void TraceStarting() 
            {
                if (TD.StartTransactionContextWorkItemIsEnabled()) 
                {
                    TD.StartTransactionContextWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id);
                }
            } 

            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) 
            { 
                NativeActivityTransactionContext transactionContext = null;
 
                try
                {
                    transactionContext = new NativeActivityTransactionContext(this.ActivityInstance, executor, bookmarkManager, this.waiter.Handle);
                    waiter.CallbackWrapper.Invoke(transactionContext, this.waiter.State); 
                }
                catch (Exception e) 
                { 
                    if (Fx.IsFatal(e))
                    { 
                        throw;
                    }

                    this.ExceptionToPropagate = e; 
                }
                finally 
                { 
                    if (transactionContext != null)
                    { 
                        transactionContext.Dispose();
                    }
                }
 
                return true;
            } 
        } 

        // This class is not DataContract since we only create instances of it while we 
        // are in no-persist zones
        class RuntimeTransactionData
        {
            public RuntimeTransactionData(RuntimeTransactionHandle handle, Transaction transaction, ActivityInstance isolationScope) 
            {
                this.TransactionHandle = handle; 
                this.OriginalTransaction = transaction; 
                this.ClonedTransaction = transaction.Clone();
                this.IsolationScope = isolationScope; 
                this.TransactionStatus = TransactionStatus.Active;
            }

            public AsyncWaitHandle CompletionEvent 
            {
                get; 
                set; 
            }
 
            public PreparingEnlistment PendingPreparingEnlistment
            {
                get;
                set; 
            }
 
            public bool HasPrepared 
            {
                get; 
                set;
            }

            public bool ShouldScheduleCompletion 
            {
                get; 
                set; 
            }
 
            public TransactionStatus TransactionStatus
            {
                get;
                set; 
            }
 
            public bool IsRootCancelPending 
            {
                get; 
                set;
            }

            public RuntimeTransactionHandle TransactionHandle 
            {
                get; 
                private set; 
            }
 
            public Transaction ClonedTransaction
            {
                get;
                private set; 
            }
 
            public Transaction OriginalTransaction 
            {
                get; 
                private set;
            }

            public ActivityInstance IsolationScope 
            {
                get; 
                private set; 
            }
 
            [Fx.Tag.Throws(typeof(Exception), "Doesn't handle any exceptions coming from Rollback.")]
            public void Rollback(Exception reason)
            {
                Fx.Assert(this.OriginalTransaction != null, "We always have an original transaction."); 

                this.OriginalTransaction.Rollback(reason); 
            } 
        }
 
        class AssociateKeysAsyncResult : AsyncResult
        {
            static readonly AsyncCompletion associatedCallback = new AsyncCompletion(OnAssociated);
 
            readonly ActivityExecutor executor;
 
            public AssociateKeysAsyncResult(ActivityExecutor executor, ICollection keysToAssociate, AsyncCallback callback, object state) 
                : base(callback, state)
            { 
                this.executor = executor;

                IAsyncResult result;
                using (PrepareTransactionalCall(this.executor.CurrentTransaction)) 
                {
                    result = this.executor.host.OnBeginAssociateKeys(keysToAssociate, PrepareAsyncCompletion(associatedCallback), this); 
                } 
                if (SyncContinue(result))
                { 
                    Complete(true);
                }
            }
 
            static bool OnAssociated(IAsyncResult result)
            { 
                AssociateKeysAsyncResult thisPtr = (AssociateKeysAsyncResult)result.AsyncState; 
                thisPtr.executor.host.OnEndAssociateKeys(result);
                return true; 
            }

            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result);
            } 
        } 

        class PoolOfEmptyWorkItems : Pool 
        {
            protected override EmptyWorkItem CreateNew()
            {
                return new EmptyWorkItem(); 
            }
        } 
 
        class PoolOfExecuteActivityWorkItems : Pool
        { 
            protected override ExecuteActivityWorkItem CreateNew()
            {
                return new ExecuteActivityWorkItem();
            } 
        }
 
        class PoolOfCompletionWorkItems : Pool 
        {
            protected override CompletionCallbackWrapper.CompletionWorkItem CreateNew() 
            {
                return new CompletionCallbackWrapper.CompletionWorkItem();
            }
        } 

        class PoolOfNativeActivityContexts : Pool 
        { 
            protected override NativeActivityContext CreateNew()
            { 
                return new NativeActivityContext();
            }
        }
 
        class PoolOfCodeActivityContexts : Pool
        { 
            protected override CodeActivityContext CreateNew() 
            {
                return new CodeActivityContext(); 
            }
        }

        class PoolOfResolveNextArgumentWorkItems : Pool 
        {
            protected override ResolveNextArgumentWorkItem CreateNew() 
            { 
                return new ResolveNextArgumentWorkItem();
            } 
        }

        //This is used in ScheduleDelegate when the handler is null. We use this dummy activity to
        //set as the 'Activity' of the completed ActivityInstance. 
        class EmptyDelegateActivity : NativeActivity
        { 
            internal EmptyDelegateActivity() 
            {
            } 

            protected override void Execute(NativeActivityContext context)
            {
                Fx.Assert(false, "This activity should never be executed. It is a dummy activity"); 
            }
        } 
    } 
}

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