File: System\Activities\Runtime\ActivityExecutor.cs
Project: ndp\cdf\src\NetFx40\System.Activities\System.Activities.csproj (System.Activities)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.Activities.Runtime
{
    using System;
    using System.Activities.Debugger;
    using System.Activities.DynamicUpdate;
    using System.Activities.Hosting;
    using System.Activities.Tracking;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    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<BookmarkInfo> emptyBookmarkInfoCollection;
 
        BookmarkManager bookmarkManager;
 
        BookmarkScopeManager bookmarkScopeManager;
 
        DebugController debugController;
        bool hasRaisedWorkflowStarted;
 
        Guid instanceId;
        bool instanceIdSet;
 
        Activity rootElement;
        Dictionary<ActivityInstance, AsyncOperationContext> activeOperations;
        WorkflowInstance host;
 
        ActivityInstanceMap instanceMap;
        MappableObjectManager mappableObjectManager;
 
        bool hasTrackedStarted;
 
        long nextTrackingRecordNumber;
 
        ActivityInstance rootInstance;
        List<ActivityInstance> executingSecondaryRootInstances;
 
        Scheduler scheduler;
 
        Exception completionException;
 
        bool shouldRaiseMainBodyComplete;
 
        long lastInstanceId;
 
        LocationEnvironment rootEnvironment;
 
        IDictionary<string, object> workflowOutputs;
 
        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).
        ActivityInstanceState executionState;
 
        Queue<PersistenceWaiter> persistenceWaiters;
 
        Quack<TransactionContextWaiter> transactionContextWaiters;
        RuntimeTransactionData runtimeTransaction;
 
        bool isAbortPending;
        bool isDisposed;
        bool shouldPauseOnCanPersist;
 
        bool isTerminatePending;
        Exception terminationPendingException;
 
        int noPersistCount;
 
        SymbolResolver symbolResolver;
 
        bool throwDuringSerialization;
        
        CodeActivityContext cachedResolutionContext;
        Location ignorableResultLocation;
 
        // work item pools (for performance)
        Pool<EmptyWorkItem> emptyWorkItemPool;
        Pool<ExecuteActivityWorkItem> executeActivityWorkItemPool;
        Pool<ExecuteSynchronousExpressionWorkItem> executeSynchronousExpressionWorkItemPool;
        Pool<CompletionCallbackWrapper.CompletionWorkItem> completionWorkItemPool;
        Pool<ResolveNextArgumentWorkItem> resolveNextArgumentWorkItemPool;
 
        // context pools (for performance)
        Pool<CodeActivityContext> codeActivityContextPool;
        Pool<NativeActivityContext> nativeActivityContextPool;
 
        // root handles (for default Tx, Correlation, etc)
        ExecutionPropertyManager rootPropertyManager;
 
        // This list keeps track of handles that are created and initialized.
        List<Handle> handles;
 
        bool persistExceptions;
        bool havePersistExceptionsValue;
 
        public ActivityExecutor(WorkflowInstance host)
        {
            Fx.Assert(host != null, "There must be a host.");
 
            this.host = host;
            this.WorkflowIdentity = host.DefinitionIdentity;
 
            this.bookmarkManager = new BookmarkManager();
            this.scheduler = new Scheduler(new Scheduler.Callbacks(this));
        }
 
        public Pool<EmptyWorkItem> EmptyWorkItemPool
        {
            get
            {
                if (this.emptyWorkItemPool == null)
                {
                    this.emptyWorkItemPool = new PoolOfEmptyWorkItems();
                }
 
                return this.emptyWorkItemPool;
            }
        }
 
        Pool<ExecuteActivityWorkItem> ExecuteActivityWorkItemPool
        {
            get
            {
                if (this.executeActivityWorkItemPool == null)
                {
                    this.executeActivityWorkItemPool = new PoolOfExecuteActivityWorkItems();
                }
 
                return this.executeActivityWorkItemPool;
            }
        }
 
        public Pool<ExecuteSynchronousExpressionWorkItem> ExecuteSynchronousExpressionWorkItemPool
        {
            get
            {
                if (this.executeSynchronousExpressionWorkItemPool == null)
                {
                    this.executeSynchronousExpressionWorkItemPool = new PoolOfExecuteSynchronousExpressionWorkItems();
                }
 
                return this.executeSynchronousExpressionWorkItemPool;
            }
        }
 
        public Pool<CompletionCallbackWrapper.CompletionWorkItem> CompletionWorkItemPool
        {
            get
            {
                if (this.completionWorkItemPool == null)
                {
                    this.completionWorkItemPool = new PoolOfCompletionWorkItems();
                }
 
                return this.completionWorkItemPool;
            }
        }
 
        public Pool<CodeActivityContext> CodeActivityContextPool
        {
            get
            {
                if (this.codeActivityContextPool == null)
                {
                    this.codeActivityContextPool = new PoolOfCodeActivityContexts();
                }
 
                return this.codeActivityContextPool;
            }
        }
 
        public Pool<NativeActivityContext> NativeActivityContextPool
        {
            get
            {
                if (this.nativeActivityContextPool == null)
                {
                    this.nativeActivityContextPool = new PoolOfNativeActivityContexts();
                }
 
                return this.nativeActivityContextPool;
            }
        }
 
        public Pool<ResolveNextArgumentWorkItem> 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<SymbolResolver>();
                    }
                    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(EmitDefaultValue = false)]
        public WorkflowIdentity WorkflowIdentity
        {
            get;
            internal set;
        }
 
        [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;
            }
            // Internal visibility for partial trust serialization purposes only.
            internal 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<string, object> 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<BookmarkInfo> EmptyBookmarkInfoCollection
        {
            get
            {
                if (emptyBookmarkInfoCollection == null)
                {
                    emptyBookmarkInfoCollection = new ReadOnlyCollection<BookmarkInfo>(new List<BookmarkInfo>(0));
                }
 
                return emptyBookmarkInfoCollection;
            }
        }
 
        [DataMember(Name = XD.Executor.BookmarkManager, EmitDefaultValue = false)]
        internal BookmarkManager SerializedBookmarkManager
        {
            get { return this.bookmarkManager; }
            set { this.bookmarkManager = value; }
        }
 
        [DataMember(Name = XD.Executor.BookmarkScopeManager, EmitDefaultValue = false)]
        internal BookmarkScopeManager SerializedBookmarkScopeManager
        {
            get { return this.bookmarkScopeManager; }
            set { this.bookmarkScopeManager = value; }
        }
 
        [DataMember(EmitDefaultValue = false, Name = "hasTrackedStarted")]
        internal bool SerializedHasTrackedStarted
        {
            get { return this.hasTrackedStarted; }
            set { this.hasTrackedStarted = value; }
        }
 
        [DataMember(EmitDefaultValue = false, Name = "nextTrackingRecordNumber")]
        internal long SerializedNextTrackingRecordNumber
        {
            get { return this.nextTrackingRecordNumber; }
            set { this.nextTrackingRecordNumber = value; }
        }
 
        [DataMember(Name = XD.Executor.RootInstance, EmitDefaultValue = false)]
        internal ActivityInstance SerializedRootInstance
        {
            get { return this.rootInstance; }
            set { this.rootInstance = value; }
        }
 
        [DataMember(Name = XD.Executor.SchedulerMember, EmitDefaultValue = false)]
        internal Scheduler SerializedScheduler
        {
            get { return this.scheduler; }
            set { this.scheduler = value; }
        }
 
        [DataMember(Name = XD.Executor.ShouldRaiseMainBodyComplete, EmitDefaultValue = false)]
        internal bool SerializedShouldRaiseMainBodyComplete
        {
            get { return this.shouldRaiseMainBodyComplete; }
            set { this.shouldRaiseMainBodyComplete = value; }
        }
 
        [DataMember(Name = XD.Executor.LastInstanceId, EmitDefaultValue = false)]
        internal long SerializedLastInstanceId
        {
            get { return this.lastInstanceId; }
            set { this.lastInstanceId = value; }
        }
 
        [DataMember(Name = XD.Executor.RootEnvironment, EmitDefaultValue = false)]
        internal LocationEnvironment SerializedRootEnvironment
        {
            get { return this.rootEnvironment; }
            set { this.rootEnvironment = value; }
        }
 
        [DataMember(Name = XD.Executor.WorkflowOutputs, EmitDefaultValue = false)]
        internal IDictionary<string, object> SerializedWorkflowOutputs
        {
            get { return this.workflowOutputs; }
            set { this.workflowOutputs = value; }
        }
 
        [DataMember(Name = XD.Executor.MainRootCompleteBookmark, EmitDefaultValue = false)]
        internal Bookmark SerializedMainRootCompleteBookmark
        {
            get { return this.mainRootCompleteBookmark; }
            set { this.mainRootCompleteBookmark = value; }
        }
 
        [DataMember(Name = XD.Executor.ExecutionState, EmitDefaultValue = false)]
        internal ActivityInstanceState SerializedExecutionState
        {
            get { return this.executionState; }
            set { this.executionState = value; }
        }
 
        [DataMember(EmitDefaultValue = false, Name = "handles")]
        internal List<Handle> SerializedHandles
        {
            get { return this.handles; }
            set { this.handles = value; }
        }
 
        internal bool PersistExceptions
        {
            get
            {
                if (!havePersistExceptionsValue)
                {
                    // If we have an ExceptionPersistenceExtension, set our cached "persistExceptions" value to its
                    // PersistExceptions property. If we don't have the extension, set the cached value to true.
                    ExceptionPersistenceExtension extension = this.host.GetExtension<ExceptionPersistenceExtension>();
                    if (extension != null)
                    {
                        this.persistExceptions = extension.PersistExceptions;
                    }
                    else
                    {
                        this.persistExceptions = true;
                    }
 
                    this.havePersistExceptionsValue = true;
                }
                return this.persistExceptions;
            }
        }
 
        [DataMember(Name = XD.Executor.CompletionException, EmitDefaultValue = false)]
        internal Exception SerializedCompletionException
        {
            get
            {
                if (this.PersistExceptions)
                {
                    return this.completionException;
                }
                else
                {
                    return null;
                }
            }
            set
            {
                this.completionException = value;
            }
        }
 
        [DataMember(Name = XD.Executor.TransactionContextWaiters, EmitDefaultValue = false)]
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Used by serialization")]
        internal 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<TransactionContextWaiter>(value);
            }
        }
 
        [DataMember(Name = XD.Executor.PersistenceWaiters, EmitDefaultValue = false)]
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Used by serialization")]
        internal Queue<PersistenceWaiter> 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")]
        internal List<ActivityInstance> 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")]
        internal 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")]
        internal ActivityInstanceMap SerializedProgramMapping
        {
            get
            {
                ThrowIfNonSerializable();
 
                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")]
        internal 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);
            }
        }
 
        public void ThrowIfNonSerializable()
        {
            if (this.throwDuringSerialization)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.StateCannotBeSerialized(this.WorkflowInstanceId)));
            }
        }
 
        public void MakeNonSerializable()
        {
            this.throwDuringSerialization = true;
        }
 
        public IList<ActivityBlockingUpdate> GetActivitiesBlockingUpdate(DynamicUpdateMap updateMap)
        {
            Fx.Assert(updateMap != null, "UpdateMap must not be null.");
            Collection<ActivityBlockingUpdate> result = null;
            this.instanceMap.GetActivitiesBlockingUpdate(updateMap, this.executingSecondaryRootInstances, ref result);
            return result;
        }
 
        public void UpdateInstancePhase1(DynamicUpdateMap updateMap, Activity targetDefinition, ref Collection<ActivityBlockingUpdate> updateErrors)
        {
            Fx.Assert(updateMap != null, "UpdateMap must not be null.");
            this.instanceMap.UpdateRawInstance(updateMap, targetDefinition, this.executingSecondaryRootInstances, ref updateErrors);
        }
 
        public void UpdateInstancePhase2(DynamicUpdateMap updateMap, ref Collection<ActivityBlockingUpdate> updateErrors)
        {
            this.instanceMap.UpdateInstanceByActivityParticipation(this, updateMap, ref updateErrors);
        }
 
        internal List<Handle> Handles
        {
            get { return this.handles; }
        }
 
        // evaluate an argument/variable expression using fast-path optimizations
        public void ExecuteInResolutionContextUntyped(ActivityInstance parentInstance, ActivityWithResult expressionActivity, long instanceId, Location resultLocation)
        {
            if (this.cachedResolutionContext == null)
            {
                this.cachedResolutionContext = new CodeActivityContext(parentInstance, this);
            }
 
            this.cachedResolutionContext.Reinitialize(parentInstance, this, expressionActivity, instanceId);
            try
            {
                this.ignorableResultLocation = resultLocation;
                resultLocation.Value = expressionActivity.InternalExecuteInResolutionContextUntyped(this.cachedResolutionContext);
            }
            finally
            {
                if (!expressionActivity.UseOldFastPath)
                {
                    // The old fast path allows WorkflowDataContexts to escape up one level, because
                    // the resolution context uses the parent's ActivityInstance. We support that for
                    // back-compat, but don't allow it on new fast-path activities.
                    this.cachedResolutionContext.DisposeDataContext();
                }
 
                this.cachedResolutionContext.Dispose();
                this.ignorableResultLocation = null;
            }
        }
 
        // evaluate an argument/variable expression using fast-path optimizations
        public T ExecuteInResolutionContext<T>(ActivityInstance parentInstance, Activity<T> expressionActivity)
        {
            Fx.Assert(expressionActivity.UseOldFastPath, "New fast path should be scheduled via ExecuteSynchronousExpressionWorkItem, which calls the Untyped overload");
 
            if (this.cachedResolutionContext == null)
            {
                this.cachedResolutionContext = new CodeActivityContext(parentInstance, this);
            }
 
            this.cachedResolutionContext.Reinitialize(parentInstance, this, expressionActivity, parentInstance.InternalId);
            T result;
            try
            {
                result = expressionActivity.InternalExecuteInResolutionContext(this.cachedResolutionContext);
            }
            finally
            {
                this.cachedResolutionContext.Dispose();
            }
            return result;
        }
 
        internal void ExecuteSynchronousWorkItem(WorkItem workItem)
        {
            workItem.Release(this);
            try
            {
                bool result = workItem.Execute(this, bookmarkManager);
                Fx.AssertAndThrow(result, "Synchronous work item should not yield the scheduler");
            }
            finally
            {
                workItem.Dispose(this);
            }
        }
 
        internal void ExitNoPersistForExceptionPropagation()
        {
            if (!this.PersistExceptions)
            {
                ExitNoPersist();
            }
        }
 
        // This is called by RuntimeArgument.GetLocation (via ActivityContext.GetIgnorableResultLocation)
        // when the user tries to access the Result argument on an activity being run with SkipArgumentResolution.
        internal Location GetIgnorableResultLocation(RuntimeArgument resultArgument)
        {
            Fx.Assert(resultArgument.Owner == this.cachedResolutionContext.Activity, "GetIgnorableResultLocation should only be called for activity in resolution context");
            Fx.Assert(this.ignorableResultLocation != null, "ResultLocation should have been passed in to ExecuteInResolutionContext");
 
            return this.ignorableResultLocation;
        }
 
        // 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.BeginFlushTrackingRecordsInternal(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.EndFlushTrackingRecordsInternal(result);
        }
 
        internal IDictionary<string, LocationInfo> 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<NativeActivityTransactionContext, object> callback, object state)
        {
            if (isRequires)
            {
                EnterNoPersist();
            }
 
            if (this.transactionContextWaiters == null)
            {
                this.transactionContextWaiters = new Quack<TransactionContextWaiter>();
            }
 
            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 = DiagnosticTraceBase.ActivityId;
                FxTrace.Trace.SetAndTraceTransfer(this.WorkflowInstanceId, true);
 
                if (TD.WorkflowActivityResumeIsEnabled())
                {
                    TD.WorkflowActivityResume(this.WorkflowInstanceId);
                }
 
                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 = DiagnosticTraceBase.ActivityId;
                FxTrace.Trace.SetAndTraceTransfer(this.WorkflowInstanceId, true);
 
                if (TD.WorkflowActivityStartIsEnabled())
                {
                    TD.WorkflowActivityStart(this.WorkflowInstanceId);
                }
 
                return true;
            }
            else
            {
                oldActivityId = Guid.Empty;
                return false;
            }
        }
 
        void TraceSuspend(bool hasBeenResumed, Guid oldActivityId)
        {
            if (hasBeenResumed)
            {
                if (TD.WorkflowActivitySuspendIsEnabled())
                {
                    TD.WorkflowActivitySuspend(this.WorkflowInstanceId);
                }
 
                DiagnosticTraceBase.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)
        {
            // 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;
 
            // If we are not supposed to persist exceptions, call EnterNoPersist so that we don't persist while we are
            // propagating the exception.
            // We call ExitNoPersist when we abort an activit or when we call a fault callback. But we may end up
            // re-propagating and thus calling EnterNoPersist again.
            // We also do an exit if the workflow is aborted or the exception ends up being unhandled.
            if (!this.PersistExceptions)
            {
                EnterNoPersist();
            }
            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(this, 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
                    // If the TerminateOnUnhandledExceptionDuringCancel switch is true, terminate instead of abort.
                    if (System.Activities.LocalAppContextSwitches.TerminateOnUnhandledExceptionDuringCancel)
                    {
                        this.Terminate(new InvalidOperationException(SR.CannotPropagateExceptionWhileCanceling(exceptionSource.Activity.DisplayName, exceptionSource.Id), exception));
                    }
                    else
                    {
                        this.AbortWorkflowInstance(new InvalidOperationException(SR.CannotPropagateExceptionWhileCanceling(exceptionSource.Activity.DisplayName, exceptionSource.Id), exception));
                    }
 
                    workItem.ExceptionPropagated();
                    ExitNoPersistForExceptionPropagation();
                    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");
 
            if (!object.Equals(workflowInstance.DefinitionIdentity, this.WorkflowIdentity))
            {
                throw FxTrace.Exception.AsError(new VersionMismatchException(workflowInstance.DefinitionIdentity, this.WorkflowIdentity));
            }
 
            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<T>()
            where T : class
        {
            T extension = null;
            try
            {
                extension = this.host.GetExtension<T>();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }
                throw FxTrace.Exception.AsError(new CallbackException(SR.CallbackExceptionFromHostGetExtension(this.WorkflowInstanceId), e));
            }
 
            return extension;
        }
 
        internal Scheduler.RequestedAction TryExecuteNonEmptyWorkItem(WorkItem workItem)
        {
            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;
            }
            return null;
        }
 
        // 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)
            {
                // The try/catch/finally block used in executing a workItem prevents ryujit from performing
                // some optimizations. Moving the functionality back into this method may cause a performance
                // regression.
                var result = TryExecuteNonEmptyWorkItem(workItem);
                if (result != null)
                {
                    return result;
                }
            }
 
            if (workItem.WorkflowAbortException != null)
            {
                AbortWorkflowInstance(new OperationCanceledException(SR.WorkItemAbortedInstance, workItem.WorkflowAbortException));
                return Scheduler.Continue;
            }
 
            // We only check this in the sync 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)
            {
                ExitNoPersistForExceptionPropagation();
                return Scheduler.CreateNotifyUnhandledExceptionAction(workItem.ExceptionToPropagate, workItem.OriginalExceptionSource);
            }
 
            return Scheduler.Continue;
        }
 
        internal IAsyncResult BeginAssociateKeys(ICollection<InstanceKey> keysToAssociate, AsyncCallback callback, object state)
        {
            return new AssociateKeysAsyncResult(this, keysToAssociate, callback, state);
        }
 
        internal void EndAssociateKeys(IAsyncResult result)
        {
            AssociateKeysAsyncResult.End(result);
        }
 
        internal void DisassociateKeys(ICollection<InstanceKey> 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)
                        {
                            ExitNoPersistForExceptionPropagation();
                            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)
                    {
                        ExitNoPersistForExceptionPropagation();
                        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<RuntimeArgument> 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<string, object>();
                        }
 
                        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<PersistenceWaiter>();
            }
 
            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<BookmarkInfo> GetAllBookmarks()
        {
            List<BookmarkInfo> bookmarks = CollectExternalBookmarks();
 
            if (bookmarks != null)
            {
                return new ReadOnlyCollection<BookmarkInfo>(bookmarks);
            }
            else
            {
                return EmptyBookmarkInfoCollection;
            }
        }
 
        List<BookmarkInfo> CollectExternalBookmarks()
        {
            List<BookmarkInfo> bookmarks = null;
 
            if (this.bookmarkManager != null && this.bookmarkManager.HasBookmarks)
            {
                bookmarks = new List<BookmarkInfo>();
 
                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<BookmarkInfo> GetBookmarks(BookmarkScope scope)
        {
            if (this.bookmarkScopeManager == null)
            {
                return EmptyBookmarkInfoCollection;
            }
            else
            {
                ReadOnlyCollection<BookmarkInfo> 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<string, object> argumentValueOverrides, IList<Handle> hostProperties)
        {
            Fx.Assert(this.rootInstance == null, "ScheduleRootActivity should only be called once");
 
            if (hostProperties != null && hostProperties.Count > 0)
            {
                Dictionary<string, ExecutionPropertyManager.ExecutionProperty> rootProperties = new Dictionary<string, ExecutionPropertyManager.ExecutionProperty>(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.Id);
            }
 
            // 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<ActivityInstance>();
            }
 
            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<string, object> 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<RuntimeDelegateArgument> 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.Id);
                }
 
                if (this.ShouldTrackActivityScheduledRecords)
                {
                    AddTrackingRecord(new ActivityScheduledRecord(this.WorkflowInstanceId, parent, handlerInstance));
                }
 
                ScheduleBody(handlerInstance, requiresSymbolResolution, null, null);
            }
 
            return handlerInstance;
        }
 
        void TraceActivityScheduled(ActivityInstance parent, Activity activity, string scheduledInstanceId)
        {
            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, scheduledInstanceId);
            }
            else
            {
                TD.ActivityScheduled(string.Empty, string.Empty, string.Empty, activity.GetType().ToString(), activity.DisplayName, scheduledInstanceId);
            }
        }
 
        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)
            IncrementLastInstanceId();
 
            return activityInstance;
        }
 
        void IncrementLastInstanceId()
        {
            if (this.lastInstanceId == long.MaxValue)
            {
                throw FxTrace.Exception.AsError(new NotSupportedException(SR.OutOfInstanceIds));
            }
            this.lastInstanceId++;
        }
 
        ActivityInstance ScheduleActivity(Activity activity, ActivityInstance parent,
            CompletionBookmark completionBookmark, FaultBookmark faultBookmark, LocationEnvironment parentEnvironment,
            IDictionary<string, object> 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.Id);
            }
 
            if (this.ShouldTrackActivityScheduledRecords)
            {
                AddTrackingRecord(new ActivityScheduledRecord(this.WorkflowInstanceId, parent, activityInstance));
            }
 
            ScheduleBody(activityInstance, requiresSymbolResolution, argumentValueOverrides, resultLocation);
 
            return activityInstance;
        }
 
        internal void ScheduleExpression(ActivityWithResult activity, ActivityInstance parent, LocationEnvironment parentEnvironment, Location resultLocation, ResolveNextArgumentWorkItem nextArgumentWorkItem)
        {
            Fx.Assert(resultLocation != null, "We should always schedule expressions with a result location.");
 
            if (!activity.IsMetadataCached || activity.CacheId != parent.Activity.CacheId)
            {
                throw FxTrace.Exception.Argument("activity", SR.ActivityNotPartOfThisTree(activity.DisplayName, parent.Activity.DisplayName));
            }
 
            if (activity.SkipArgumentResolution)
            {
                // 
 
                Fx.Assert(!activity.UseOldFastPath || parent.SubState == ActivityInstance.Substate.Executing,
                    "OldFastPath activities should have been handled by the Populate methods, unless this is a dynamic update");
                
                IncrementLastInstanceId();
 
                ScheduleExpression(activity, parent, resultLocation, nextArgumentWorkItem, this.lastInstanceId);
            }
            else
            {
                if (nextArgumentWorkItem != null)
                {
                    ScheduleItem(nextArgumentWorkItem);
                }
                ScheduleActivity(activity, parent, null, null, parentEnvironment, null, resultLocation.CreateReference(true));
            }
        }
 
        void ScheduleExpression(ActivityWithResult activity, ActivityInstance parent, Location resultLocation, ResolveNextArgumentWorkItem nextArgumentWorkItem, long instanceId)
        {
            if (TD.ActivityScheduledIsEnabled())
            {
                TraceActivityScheduled(parent, activity, instanceId.ToString(CultureInfo.InvariantCulture));
            }
 
            if (this.ShouldTrackActivityScheduledRecords)
            {
                AddTrackingRecord(new ActivityScheduledRecord(this.WorkflowInstanceId, parent, new ActivityInfo(activity, instanceId)));
            }
 
            ExecuteSynchronousExpressionWorkItem workItem = this.ExecuteSynchronousExpressionWorkItemPool.Acquire();
            workItem.Initialize(parent, activity, this.lastInstanceId, resultLocation, nextArgumentWorkItem);
            if (this.instanceMap != null)
            {
                this.instanceMap.AddEntry(workItem);
            }
            ScheduleItem(workItem);
        }
 
        internal void ScheduleExpressionFaultPropagation(Activity activity, long instanceId, ActivityInstance parent, Exception exception)
        {
            ActivityInstance instance = new ActivityInstance(activity);
            instance.Initialize(parent, this.instanceMap, parent.Environment, instanceId, this);
 
            if (!parent.HasPendingWork)
            {
                // Force the parent to stay alive, and to attempt to execute its body if the fault is handled
                ScheduleItem(CreateEmptyWorkItem(parent));
            }
            PropagateExceptionWorkItem workItem = new PropagateExceptionWorkItem(exception, instance);
            ScheduleItem(workItem);
 
            parent.SetInitializationIncomplete();
        }
 
        // 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<string, object> 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<ActivityInstance, AsyncOperationContext>();
            }
 
            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<Handle>();
            }
            this.handles.Add(handleToAdd);
        }
 
        [DataContract]
        internal class PersistenceWaiter
        {
            Bookmark onPersistBookmark;
            ActivityInstance waitingInstance;
 
            public PersistenceWaiter(Bookmark onPersist, ActivityInstance waitingInstance)
            {
                this.OnPersistBookmark = onPersist;
                this.WaitingInstance = waitingInstance;
            }
            
            public Bookmark OnPersistBookmark
            {
                get
                {
                    return this.onPersistBookmark;
                }
                private set
                {
                    this.onPersistBookmark = value;
                }
            }
            
            public ActivityInstance WaitingInstance
            {
                get
                {
                    return this.waitingInstance;
                }
                private set
                {
                    this.waitingInstance = value;
                }
            }
 
            [DataMember(Name = "OnPersistBookmark")]
            internal Bookmark SerializedOnPersistBookmark
            {
                get { return this.OnPersistBookmark; }
                set { this.OnPersistBookmark = value; }
            }
 
            [DataMember(Name = "WaitingInstance")]
            internal ActivityInstance SerializedWaitingInstance
            {
                get { return this.WaitingInstance; }
                set { this.WaitingInstance = value; }
            }
 
            public WorkItem CreateWorkItem()
            {
                return new PersistWorkItem(this);
            }
 
            [DataContract]
            internal class PersistWorkItem : WorkItem
            {
                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;
                    }
                }
 
                [DataMember(Name = "waiter")]
                internal PersistenceWaiter SerializedWaiter
                {
                    get { return this.waiter; }
                    set { this.waiter = value; }
                }
 
                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]
        internal class AbortActivityWorkItem : WorkItem
        {
            Exception reason;
            ActivityInstanceReference originalSource;
 
            ActivityExecutor executor;
 
            public AbortActivityWorkItem(ActivityExecutor executor, ActivityInstance activityInstance, Exception reason, ActivityInstanceReference originalSource)
                : base(activityInstance)
            {
                this.reason = reason;
                this.originalSource = originalSource;
 
                this.IsEmpty = true;
                this.executor = executor;
            }
 
            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;
                }
            }
 
            [DataMember(Name = "reason")]
            internal Exception SerializedReason
            {
                get { return this.reason; }
                set { this.reason = value; }
            }
 
            [DataMember(Name = "originalSource")]
            internal ActivityInstanceReference SerializedOriginalSource
            {
                get { return this.originalSource; }
                set { this.originalSource = value; }
            }
 
            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;
 
                // Tell the executor to decrement its NoPersistCount, if necessary.
                executor.ExitNoPersistForExceptionPropagation();
            }
        }
 
        [DataContract]
        internal class CompleteAsyncOperationWorkItem : BookmarkWorkItem
        {
            public CompleteAsyncOperationWorkItem(BookmarkCallbackWrapper wrapper, Bookmark bookmark, object value)
                : base(wrapper, bookmark, value)
            {
                this.ExitNoPersistRequired = true;
            }
        }
 
        [DataContract]
        internal 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]
        internal class ExecuteActivityWorkItem : ActivityExecutionWorkItem
        {
            bool requiresSymbolResolution;
            IDictionary<string, object> argumentValueOverrides;
 
            // Called by the pool.
            public ExecuteActivityWorkItem()
            {
                this.IsPooled = true;
            }
 
            // Called by non-pool subclasses.
            protected ExecuteActivityWorkItem(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary<string, object> argumentValueOverrides)
                : base(activityInstance)
            {
                this.requiresSymbolResolution = requiresSymbolResolution;
                this.argumentValueOverrides = argumentValueOverrides;
            }
 
            [DataMember(EmitDefaultValue = false, Name = "requiresSymbolResolution")]
            internal bool SerializedRequiresSymbolResolution
            {
                get { return this.requiresSymbolResolution; }
                set { this.requiresSymbolResolution = value; }
            }
 
            [DataMember(EmitDefaultValue = false, Name = "argumentValueOverrides")]
            internal IDictionary<string, object> SerializedArgumentValueOverrides
            {
                get { return this.argumentValueOverrides; }
                set { this.argumentValueOverrides = value; }
            }            
 
            public void Initialize(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary<string, object> 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]
        internal class ExecuteRootWorkItem : ExecuteActivityWorkItem
        {
            public ExecuteRootWorkItem(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary<string, object> 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]
        internal class ExecuteExpressionWorkItem : ExecuteActivityWorkItem
        {
            Location resultLocation;
 
            public ExecuteExpressionWorkItem(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary<string, object> 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;
            }
 
            [DataMember(Name = "resultLocation")]
            internal Location SerializedResultLocation
            {
                get { return this.resultLocation; }
                set { this.resultLocation = value; }
            }
 
            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
            {
                return ExecuteBody(executor, bookmarkManager, resultLocation);
            }
        }
 
        [DataContract]
        internal class PropagateExceptionWorkItem : ActivityExecutionWorkItem
        {
            Exception exception;
 
            public PropagateExceptionWorkItem(Exception exception, ActivityInstance activityInstance)
                : base(activityInstance)
            {
                Fx.Assert(exception != null, "We must not have a null exception.");
 
                this.exception = exception;
                this.IsEmpty = true;
            }
 
            [DataMember(EmitDefaultValue = false, Name = "exception")]
            internal Exception SerializedException
            {
                get { return this.exception; }
                set { this.exception = value; }
            }
 
            public override void TraceScheduled()
            {
                TraceRuntimeWorkItemScheduled();
            }
 
            public override void TraceStarting()
            {
                TraceRuntimeWorkItemStarting();
            }
 
            public override void TraceCompleted()
            {
                TraceRuntimeWorkItemCompleted();
            }
 
            public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
            {
                Fx.Assert("This shouldn't be called because we are empty.");
 
                return false;
            }
 
            public override void PostProcess(ActivityExecutor executor)
            {
                ExceptionToPropagate = this.exception;
            }
        }
 
        [DataContract]
        internal class RethrowExceptionWorkItem : WorkItem
        {
            Exception exception;
            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;
                }
            }
 
            [DataMember(Name = "exception")]
            internal Exception SerializedException
            {
                get { return this.exception; }
                set { this.exception = value; }
            }
 
            [DataMember(Name = "source")]
            internal ActivityInstanceReference SerializedSource
            {
                get { return this.source; }
                set { this.source = value; }
            }
 
            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]
        internal 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;
            }
 
            ActivityInstance waitingInstance;
            public ActivityInstance WaitingInstance
            {
                get
                {
                    return this.waitingInstance;
                }
                private set
                {
                    this.waitingInstance = value;
                }
            }
 
            bool isRequires;
            public bool IsRequires
            {
                get
                {
                    return this.isRequires;
                }
                private set
                {
                    this.isRequires = value;
                }
            }
 
            RuntimeTransactionHandle handle;
            public RuntimeTransactionHandle Handle
            {
                get
                {
                    return this.handle;
                }
                private set
                {
                    this.handle = value;
                }
            }
 
            object state;
            public object State
            {
                get
                {
                    return this.state;
                }
                private set
                {
                    this.state = value;
                }
            }
 
            TransactionContextWaiterCallbackWrapper callbackWrapper;
            public TransactionContextWaiterCallbackWrapper CallbackWrapper
            {
                get
                {
                    return this.callbackWrapper;
                }
                private set
                {
                    this.callbackWrapper = value;
                }
            }
 
            [DataMember(Name = "WaitingInstance")]
            internal ActivityInstance SerializedWaitingInstance
            {
                get { return this.WaitingInstance; }
                set { this.WaitingInstance = value; }
            }
 
            [DataMember(EmitDefaultValue = false, Name = "IsRequires")]
            internal bool SerializedIsRequires
            {
                get { return this.IsRequires; }
                set { this.IsRequires = value; }
            }
 
            [DataMember(Name = "Handle")]
            internal RuntimeTransactionHandle SerializedHandle
            {
                get { return this.Handle; }
                set { this.Handle = value; }
            }
 
            [DataMember(EmitDefaultValue = false, Name = "State")]
            internal object SerializedState
            {
                get { return this.State; }
                set { this.State = value; }
            }
 
            [DataMember(Name = "CallbackWrapper")]
            internal TransactionContextWaiterCallbackWrapper SerializedCallbackWrapper
            {
                get { return this.CallbackWrapper; }
                set { this.CallbackWrapper = value; }
            }
        }
 
        [DataContract]
        internal class TransactionContextWaiterCallbackWrapper : CallbackWrapper
        {
            static readonly Type callbackType = typeof(Action<NativeActivityTransactionContext, object>);
            static readonly Type[] transactionCallbackParameterTypes = new Type[] { typeof(NativeActivityTransactionContext), typeof(object) };
 
            public TransactionContextWaiterCallbackWrapper(Action<NativeActivityTransactionContext, object> action, ActivityInstance owningInstance)
                : base(action, owningInstance)
            {
            }
 
            [Fx.Tag.SecurityNote(Critical = "Because we are calling EnsureCallback",
                Safe = "Safe because the method needs to be part of an Activity and we are casting to the callback type and it has a very specific signature. The author of the callback is buying into being invoked from PT.")]
            [SecuritySafeCritical]
            public void Invoke(NativeActivityTransactionContext context, object value)
            {
                EnsureCallback(callbackType, transactionCallbackParameterTypes);
                Action<NativeActivityTransactionContext, object> callback = (Action<NativeActivityTransactionContext, object>)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<object, TimeoutException> 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<object, TimeoutException> OutcomeDeterminedCallback
            {
                get
                {
                    if (outcomeDeterminedCallback == null)
                    {
                        outcomeDeterminedCallback = new Action<object, TimeoutException>(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
                {
                    TransactionHelper.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 : TransactedAsyncResult
            {
                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<TransactionalPersistAsyncResult>(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]
        internal class TransactionContextWorkItem : ActivityExecutionWorkItem
        {
            TransactionContextWaiter waiter;
 
            public TransactionContextWorkItem(TransactionContextWaiter waiter)
                : base(waiter.WaitingInstance)
            {
                this.waiter = waiter;
 
                if (this.waiter.IsRequires)
                {
                    this.ExitNoPersistRequired = true;
                }
            }
 
            [DataMember(Name = "waiter")]
            internal TransactionContextWaiter SerializedWaiter
            {
                get { return this.waiter; }
                set { this.waiter = value; }
            }
 
            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 : TransactedAsyncResult
        {
            static readonly AsyncCompletion associatedCallback = new AsyncCompletion(OnAssociated);
 
            readonly ActivityExecutor executor;
 
            public AssociateKeysAsyncResult(ActivityExecutor executor, ICollection<InstanceKey> 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<AssociateKeysAsyncResult>(result);
            }
        }
 
        class PoolOfEmptyWorkItems : Pool<EmptyWorkItem>
        {
            protected override EmptyWorkItem CreateNew()
            {
                return new EmptyWorkItem();
            }
        }
 
        class PoolOfExecuteActivityWorkItems : Pool<ExecuteActivityWorkItem>
        {
            protected override ExecuteActivityWorkItem CreateNew()
            {
                return new ExecuteActivityWorkItem();
            }
        }
 
        class PoolOfExecuteSynchronousExpressionWorkItems : Pool<ExecuteSynchronousExpressionWorkItem>
        {
            protected override ExecuteSynchronousExpressionWorkItem CreateNew()
            {
                return new ExecuteSynchronousExpressionWorkItem();
            }
        }
 
        class PoolOfCompletionWorkItems : Pool<CompletionCallbackWrapper.CompletionWorkItem>
        {
            protected override CompletionCallbackWrapper.CompletionWorkItem CreateNew()
            {
                return new CompletionCallbackWrapper.CompletionWorkItem();
            }
        }
 
        class PoolOfNativeActivityContexts : Pool<NativeActivityContext>
        {
            protected override NativeActivityContext CreateNew()
            {
                return new NativeActivityContext();
            }
        }
 
        class PoolOfCodeActivityContexts : Pool<CodeActivityContext>
        {
            protected override CodeActivityContext CreateNew()
            {
                return new CodeActivityContext();
            }
        }
 
        class PoolOfResolveNextArgumentWorkItems : Pool<ResolveNextArgumentWorkItem>
        {
            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");
            }
        }
    }
}