Exemplo n.º 1
0
        private static bool CanCompensationOrConfirmationHandlerReferenceAddedSymbols(InstanceList instanceList, DynamicUpdateMap rootUpdateMap, IdSpace rootIdSpace, List <ActivityInstance> secondaryRootInstances, ref Collection <ActivityBlockingUpdate> updateErrors)
        {
            for (int j = 0; j < instanceList.Count; j++)
            {
                ActivityInstance activityInstance = instanceList[j] as ActivityInstance;
                if (activityInstance == null || !IsNonDefaultSecondaryRoot(activityInstance, secondaryRootInstances))
                {
                    continue;
                }

                // here, find out if the given non-default secondary root references an environment to which a symbol is to be added via DU.
                // we start from a secondary root instead of starting from the enviroment with the already completed owner that was added symbols.
                // It is becuase for the case of adding symbols to noSymbols activities, the environment doesn't even exist from which we can start looking for referencing secondary root.

                int[] secondaryRootOriginalQID = new QualifiedId(instanceList.ActivityId).AsIDArray();

                Fx.Assert(secondaryRootOriginalQID != null && secondaryRootOriginalQID.Length > 1,
                          "CompensationParticipant is always an implementation child of a CompensableActivity, therefore it's IdSpace must be at least one level deep.");

                int[] parentOfSecondaryRootOriginalQID = new int[secondaryRootOriginalQID.Length - 1];
                Array.Copy(secondaryRootOriginalQID, parentOfSecondaryRootOriginalQID, secondaryRootOriginalQID.Length - 1);

                List <int> currentQIDBuilder = new List <int>();
                for (int i = 0; i < parentOfSecondaryRootOriginalQID.Length; i++)
                {
                    //
                    // for each iteration of this for-loop,
                    //  we are finding out if at every IdSpace level the map has any map entry whose activity has the CompensableActivity as an implementation decendant.
                    //  The map may not exist for every IdSpace between the root and the CompensableActivity.
                    //  If the matching map and the entry is found, then we find out if that matching entry's activity is a public decendant of any NoSymbols activity DU is to add variables or arguments to.
                    //
                    // This walk on the definition activity tree determines the hypothetical execution-time chain of instances and environments.
                    // The ultimate goal is to prevent adding variables or arguments to a NoSymbols activity which has already completed,
                    //  but its decendant CompensableActivity's compensation or confirmation handlers in the future may need to reference the added variables or arguments.

                    currentQIDBuilder.Add(parentOfSecondaryRootOriginalQID[i]);

                    DynamicUpdateMap.UpdatedActivity updatedActivity = rootUpdateMap.GetUpdatedActivity(new QualifiedId(currentQIDBuilder.ToArray()), rootIdSpace);
                    if (updatedActivity.MapEntry != null)
                    {
                        // the activity of this entry either has the CompensableActivity as an implementation decendant, or is the CompensableActivity itself.

                        // walk the same-IdSpace-parent chain of the entry,
                        // look for an entry whose EnvironmentUpdateMap.IsAdditionToNoSymbols is true.
                        DynamicUpdateMapEntry entry = updatedActivity.MapEntry;
                        do
                        {
                            if (!entry.IsRemoval && entry.HasEnvironmentUpdates && entry.EnvironmentUpdateMap.IsAdditionToNoSymbols)
                            {
                                int[] noSymbolAddActivityIDArray = currentQIDBuilder.ToArray();
                                noSymbolAddActivityIDArray[noSymbolAddActivityIDArray.Length - 1] = entry.OldActivityId;
                                QualifiedId noSymbolAddActivityQID = new QualifiedId(noSymbolAddActivityIDArray);
                                DynamicUpdateMap.UpdatedActivity noSymbolAddUpdatedActivity = rootUpdateMap.GetUpdatedActivity(noSymbolAddActivityQID, rootIdSpace);

                                AddBlockingActivity(ref updateErrors, noSymbolAddUpdatedActivity, noSymbolAddActivityQID, SR.VariableOrArgumentAdditionToReferencedEnvironmentNoDUSupported, null);
                                return(true);
                            }

                            entry = entry.Parent;
                        } while (entry != null);
                    }
                }
            }

            return(false);
        }
Exemplo n.º 2
0
        // this is called after all instances have been loaded and fixedup
        public void UpdateInstanceByActivityParticipation(ActivityExecutor activityExecutor, DynamicUpdateMap rootMap, ref Collection <ActivityBlockingUpdate> updateErrors)
        {
            foreach (InstanceListNeedingUpdate participant in this.updateList)
            {
                if (participant.NothingChanged || participant.ParentIdShiftOnly)
                {
                    Fx.Assert(participant.UpdateMap == null && participant.MapEntry == null, "UpdateMap and MapEntry must be null if we are here.");

                    // create a temporary NoChanges UpdateMap as well as a temporary no change MapEntry
                    // so that we can create a NativeActivityUpdateContext object in order to invoke UpdateInstance() on an activity which
                    // doesn't have a corresponding map and an map entry.
                    // The scenario enabled here is scheduling a newly added reference branch to a Parallel inside an activity's implementation.
                    participant.UpdateMap = DynamicUpdateMap.DummyMap;
                    participant.MapEntry  = DynamicUpdateMapEntry.DummyMapEntry;
                }

                // now let activities participate in update
                for (int i = 0; i < participant.InstanceList.Count; i++)
                {
                    ActivityInstance instance = participant.InstanceList[i] as ActivityInstance;
                    if (instance == null)
                    {
                        continue;
                    }

                    IInstanceUpdatable activity = instance.Activity as IInstanceUpdatable;
                    if (activity != null && instance.SubState == ActivityInstance.Substate.Executing)
                    {
                        NativeActivityUpdateContext updateContext = new NativeActivityUpdateContext(this, activityExecutor, instance, participant.UpdateMap, participant.MapEntry, rootMap);
                        try
                        {
                            activity.InternalUpdateInstance(updateContext);

                            if (updateContext.IsUpdateDisallowed)
                            {
                                ActivityBlockingUpdate.AddBlockingActivity(ref updateErrors, instance.Activity, new QualifiedId(participant.OriginalId).ToString(), updateContext.DisallowedReason, instance.Id);
                                continue;
                            }
                        }
                        catch (Exception e)
                        {
                            if (Fx.IsFatal(e))
                            {
                                throw;
                            }

                            throw FxTrace.Exception.AsError(new InstanceUpdateException(SR.NativeActivityUpdateInstanceThrewException(e.Message), e));
                        }
                        finally
                        {
                            updateContext.Dispose();
                        }
                    }
                }
            }

            // Schedule evaluation of newly added arguments and newly added variables.
            // This needs to happen after all the invokations of UpdateInstance above, so that newly
            // added arguments and newly added variables get evaluated before any newly added activities get executed.
            // We iterate the list in reverse so that parents are always scheduled after (and thus
            // execute before) their children, which may depend on the parents.
            for (int i = this.updateList.Count - 1; i >= 0; i--)
            {
                InstanceListNeedingUpdate participant = this.updateList[i];

                if (!participant.MapEntryExists)
                {
                    // if the given InstanceList has no map entry,
                    // then there is no new LocationReferences to resolve.
                    continue;
                }

                Fx.Assert(participant.MapEntry != null, "MapEntry must be non-null here.");
                if (!participant.MapEntry.HasEnvironmentUpdates)
                {
                    // if there is no environment updates for this MapEntry,
                    // then there is no new LocationReferences to resolve.
                    continue;
                }

                for (int j = 0; j < participant.InstanceList.Count; j++)
                {
                    ActivityInstance instance = participant.InstanceList[j] as ActivityInstance;
                    if (instance == null || instance.SubState != ActivityInstance.Substate.Executing)
                    {
                        // if the given ActivityInstance is not in Substate.Executing,
                        // then, do not try to resolve new LocationReferences
                        continue;
                    }

                    List <int> addedArgumentIndexes;
                    List <int> addedVariableIndexes;
                    List <int> addedPrivateVariableIndexes;

                    EnvironmentUpdateMap envMap = participant.MapEntry.EnvironmentUpdateMap;

                    if (envMap.HasVariableEntries && TryGatherSchedulableExpressions(envMap.VariableEntries, out addedVariableIndexes))
                    {
                        // schedule added variable default expressions
                        instance.ResolveNewVariableDefaultsDuringDynamicUpdate(activityExecutor, addedVariableIndexes, false);
                    }

                    if (envMap.HasPrivateVariableEntries && TryGatherSchedulableExpressions(envMap.PrivateVariableEntries, out addedPrivateVariableIndexes))
                    {
                        // schedule added private variable default expressions
                        // HasPrivateMemberChanged() check disallows addition of private variable default that offsets the private IdSpace,
                        // However, the added private variable default expression can be an imported activity, which has no affect on the private IdSpace.
                        // For such case, we want to be able to schedule the imported default expressions here.
                        instance.ResolveNewVariableDefaultsDuringDynamicUpdate(activityExecutor, addedPrivateVariableIndexes, true);
                    }

                    if (envMap.HasArgumentEntries && TryGatherSchedulableExpressions(envMap.ArgumentEntries, out addedArgumentIndexes))
                    {
                        // schedule added arguments
                        instance.ResolveNewArgumentsDuringDynamicUpdate(activityExecutor, addedArgumentIndexes);
                    }
                }
            }
        }
Exemplo n.º 3
0
        protected void Complete(bool completedSynchronously)
        {
            if (this.IsCompleted)
            {
                throw Fx.Exception.AsError(new InvalidOperationException(SR.AsyncResultCompletedTwice(this.GetType())));
            }

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

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

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

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

                    throw Fx.Exception.AsError(new CallbackException(SR.AsyncCallbackThrewException, e));
                }
#pragma warning restore 1634
            }
        }
Exemplo n.º 4
0
        public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
        {
            Fx.Assert("Empty work items should never been executed.");

            return(true);
        }
Exemplo n.º 5
0
 public void ThreadAcquired()
 {
     Fx.Assert(this.activityExecutor != null, "ActivityExecutor null in ThreadAcquired.");
     this.activityExecutor.OnSchedulerThreadAcquired();
 }
Exemplo n.º 6
0
 public void NotifyUnhandledException(Exception exception, ActivityInstance source)
 {
     Fx.Assert(this.activityExecutor != null, "ActivityExecutor null in NotifyUnhandledException.");
     this.activityExecutor.NotifyUnhandledException(exception, source);
 }
Exemplo n.º 7
0
        static void OnScheduledWork(object state)
        {
            Scheduler thisPtr = (Scheduler)state;

            // We snapshot these values here so that we can
            // use them after calling OnSchedulerIdle.
            bool isTracingEnabled   = FxTrace.Trace.ShouldTraceToTraceSource(TraceEventLevel.Informational);
            Guid oldActivityId      = Guid.Empty;
            Guid workflowInstanceId = Guid.Empty;

            if (isTracingEnabled)
            {
                oldActivityId      = DiagnosticTraceBase.ActivityId;
                workflowInstanceId = thisPtr.callbacks.WorkflowInstanceId;
                FxTrace.Trace.SetAndTraceTransfer(workflowInstanceId, true);

                if (thisPtr.resumeTraceRequired)
                {
                    if (TD.WorkflowActivityResumeIsEnabled())
                    {
                        TD.WorkflowActivityResume(workflowInstanceId);
                    }
                }
            }

            thisPtr.callbacks.ThreadAcquired();

            RequestedAction nextAction   = continueAction;
            bool            idleOrPaused = false;

            while (object.ReferenceEquals(nextAction, continueAction))
            {
                if (thisPtr.IsIdle || thisPtr.isPausing)
                {
                    idleOrPaused = true;
                    break;
                }

                // cycle through (queue->thisPtr.firstWorkItem->currentWorkItem)
                WorkItem currentWorkItem = thisPtr.firstWorkItem;

                // promote an item out of our work queue if necessary
                if (thisPtr.workItemQueue != null && thisPtr.workItemQueue.Count > 0)
                {
                    thisPtr.firstWorkItem = thisPtr.workItemQueue.Dequeue();
                }
                else
                {
                    thisPtr.firstWorkItem = null;
                }

                if (TD.ExecuteWorkItemStartIsEnabled())
                {
                    TD.ExecuteWorkItemStart();
                }

                nextAction = thisPtr.callbacks.ExecuteWorkItem(currentWorkItem);

                if (TD.ExecuteWorkItemStopIsEnabled())
                {
                    TD.ExecuteWorkItemStop();
                }
            }

            bool notifiedCompletion = false;
            bool isInstanceComplete = false;

            if (idleOrPaused || object.ReferenceEquals(nextAction, abortAction))
            {
                thisPtr.isPausing = false;
                thisPtr.isRunning = false;

                thisPtr.NotifyWorkCompletion();
                notifiedCompletion = true;

                if (isTracingEnabled)
                {
                    isInstanceComplete = thisPtr.callbacks.IsCompleted;
                }

                // After calling SchedulerIdle we no longer have the lock.  That means
                // that any subsequent processing in this method won't have the single
                // threaded guarantee.
                thisPtr.callbacks.SchedulerIdle();
            }
            else if (!object.ReferenceEquals(nextAction, yieldSilentlyAction))
            {
                Fx.Assert(nextAction is NotifyUnhandledExceptionAction, "This is the only other option");

                NotifyUnhandledExceptionAction notifyAction = (NotifyUnhandledExceptionAction)nextAction;

                // We only set isRunning back to false so that the host doesn't
                // have to treat this like a pause notification.  As an example,
                // a host could turn around and call run again in response to
                // UnhandledException without having to go through its operation
                // dispatch loop first (or request pause again).  If we reset
                // isPausing here then any outstanding operations wouldn't get
                // signaled with that type of host.
                thisPtr.isRunning = false;

                thisPtr.NotifyWorkCompletion();
                notifiedCompletion = true;

                if (isTracingEnabled)
                {
                    isInstanceComplete = thisPtr.callbacks.IsCompleted;
                }

                thisPtr.callbacks.NotifyUnhandledException(notifyAction.Exception, notifyAction.Source);
            }

            if (isTracingEnabled)
            {
                if (notifiedCompletion)
                {
                    if (isInstanceComplete)
                    {
                        if (TD.WorkflowActivityStopIsEnabled())
                        {
                            TD.WorkflowActivityStop(workflowInstanceId);
                        }
                    }
                    else
                    {
                        if (TD.WorkflowActivitySuspendIsEnabled())
                        {
                            TD.WorkflowActivitySuspend(workflowInstanceId);
                        }
                    }
                }

                DiagnosticTraceBase.ActivityId = oldActivityId;
            }
        }
Exemplo n.º 8
0
 public void SchedulerIdle()
 {
     Fx.Assert(this.activityExecutor != null, "ActivityExecutor null in SchedulerIdle.");
     this.activityExecutor.OnSchedulerIdle();
 }
Exemplo n.º 9
0
        // This method should only be called when we relinquished the thread but did not
        // complete the operation (silent yield is the current example)
        public void InternalResume(RequestedAction action)
        {
            Fx.Assert(this.isRunning, "We should still be processing work - we just don't have a thread");

            bool isTracingEnabled   = FxTrace.ShouldTraceInformation;
            bool notifiedCompletion = false;
            bool isInstanceComplete = false;

            if (this.callbacks.IsAbortPending)
            {
                this.isPausing = false;
                this.isRunning = false;

                this.NotifyWorkCompletion();
                notifiedCompletion = true;

                if (isTracingEnabled)
                {
                    isInstanceComplete = this.callbacks.IsCompleted;
                }

                // After calling SchedulerIdle we no longer have the lock.  That means
                // that any subsequent processing in this method won't have the single
                // threaded guarantee.
                this.callbacks.SchedulerIdle();
            }
            else if (object.ReferenceEquals(action, continueAction))
            {
                ScheduleWork(false);
            }
            else
            {
                Fx.Assert(action is NotifyUnhandledExceptionAction, "This is the only other choice because we should never have YieldSilently here");

                NotifyUnhandledExceptionAction notifyAction = (NotifyUnhandledExceptionAction)action;

                // We only set isRunning back to false so that the host doesn't
                // have to treat this like a pause notification.  As an example,
                // a host could turn around and call run again in response to
                // UnhandledException without having to go through its operation
                // dispatch loop first (or request pause again).  If we reset
                // isPausing here then any outstanding operations wouldn't get
                // signaled with that type of host.
                this.isRunning = false;

                this.NotifyWorkCompletion();
                notifiedCompletion = true;

                if (isTracingEnabled)
                {
                    isInstanceComplete = this.callbacks.IsCompleted;
                }

                this.callbacks.NotifyUnhandledException(notifyAction.Exception, notifyAction.Source);
            }

            if (isTracingEnabled)
            {
                if (notifiedCompletion)
                {
                    Guid oldActivityId = Guid.Empty;
                    bool resetId       = false;

                    if (isInstanceComplete)
                    {
                        if (TD.WorkflowActivityStopIsEnabled())
                        {
                            oldActivityId = DiagnosticTraceBase.ActivityId;
                            DiagnosticTraceBase.ActivityId = this.callbacks.WorkflowInstanceId;
                            resetId = true;

                            TD.WorkflowActivityStop(this.callbacks.WorkflowInstanceId);
                        }
                    }
                    else
                    {
                        if (TD.WorkflowActivitySuspendIsEnabled())
                        {
                            oldActivityId = DiagnosticTraceBase.ActivityId;
                            DiagnosticTraceBase.ActivityId = this.callbacks.WorkflowInstanceId;
                            resetId = true;

                            TD.WorkflowActivitySuspend(this.callbacks.WorkflowInstanceId);
                        }
                    }

                    if (resetId)
                    {
                        DiagnosticTraceBase.ActivityId = oldActivityId;
                    }
                }
            }
        }
Exemplo n.º 10
0
 internal void Open(Scheduler oldScheduler)
 {
     Fx.Assert(this.synchronizationContext == null, "can only open when in the created state");
     this.synchronizationContext = SynchronizationContextHelper.CloneSynchronizationContext(oldScheduler.synchronizationContext);
 }
Exemplo n.º 11
0
 public void OnDeserialized(Callbacks callbacks)
 {
     Initialize(callbacks);
     Fx.Assert(this.firstWorkItem != null || this.workItemQueue == null, "cannot have items in the queue unless we also have a firstWorkItem set");
 }
Exemplo n.º 12
0
        public BookmarkResumptionResult TryGenerateWorkItem(ActivityExecutor executor, ref Bookmark bookmark, BookmarkScope scope, object value, ActivityInstance isolationInstance, bool nonScopedBookmarksExist, out ActivityExecutionWorkItem workItem)
        {
            Fx.Assert(scope != null, "We should never have a null sub instance.");

            workItem = null;
            BookmarkScope lookupScope = scope;

            if (scope.IsDefault)
            {
                lookupScope = this.defaultScope;
            }

            // We don't really care about the return value since we'll
            // use null to know we should check uninitialized sub instances
            this.bookmarkManagers.TryGetValue(lookupScope, out BookmarkManager manager);

            if (manager == null)
            {
                Fx.Assert(lookupScope != null, "The sub instance should not be default if we are here.");

                BookmarkResumptionResult finalResult = BookmarkResumptionResult.NotFound;

                // Check the uninitialized sub instances for a matching bookmark
                if (this.uninitializedScopes != null)
                {
                    for (int i = 0; i < this.uninitializedScopes.Count; i++)
                    {
                        BookmarkScope uninitializedScope = this.uninitializedScopes[i];

                        Fx.Assert(this.bookmarkManagers.ContainsKey(uninitializedScope), "We must always have the uninitialized sub instances.");
                        BookmarkResumptionResult resumptionResult;
                        if (!this.bookmarkManagers[uninitializedScope].TryGetBookmarkFromInternalList(bookmark, out Bookmark internalBookmark, out BookmarkCallbackWrapper callbackWrapper))
                        {
                            resumptionResult = BookmarkResumptionResult.NotFound;
                        }
                        else if (IsExclusiveScopeUnstable(internalBookmark))
                        {
                            resumptionResult = BookmarkResumptionResult.NotReady;
                        }
                        else
                        {
                            resumptionResult = this.bookmarkManagers[uninitializedScope].TryGenerateWorkItem(executor, true, ref bookmark, value, isolationInstance, out workItem);
                        }

                        if (resumptionResult == BookmarkResumptionResult.Success)
                        {
                            // We are using InitializeBookmarkScopeWithoutKeyAssociation because we know this is a new uninitialized scope and
                            // the key we would associate is already associated. And if we did the association here, the subsequent call to
                            // FlushBookmarkScopeKeys would try to flush it out, but it won't have the transaction correct so will hang waiting for
                            // the transaction that has the PersistenceContext locked to complete. But it won't complete successfully until
                            // we finish processing here.
                            InitializeBookmarkScopeWithoutKeyAssociation(uninitializedScope, scope.Id);

                            // We've found what we were looking for
                            return(BookmarkResumptionResult.Success);
                        }
                        else if (resumptionResult == BookmarkResumptionResult.NotReady)
                        {
                            // This uninitialized sub-instance has a matching bookmark but
                            // it can't currently be resumed.  We won't return BookmarkNotFound
                            // because of this.
                            finalResult = BookmarkResumptionResult.NotReady;
                        }
                        else
                        {
                            if (finalResult == BookmarkResumptionResult.NotFound)
                            {
                                // If we still are planning on returning failure then
                                // we'll incur the cost of seeing if this scope is
                                // stable or not.

                                if (!IsStable(uninitializedScope, nonScopedBookmarksExist))
                                {
                                    // There exists an uninitialized scope which is unstable.
                                    // At the very least this means we'll return NotReady since
                                    // this uninitialized scope might eventually contain this
                                    // bookmark.
                                    finalResult = BookmarkResumptionResult.NotReady;
                                }
                            }
                        }
                    }
                }
Exemplo n.º 13
0
 internal void PurgeSingleBookmark(Bookmark bookmark)
 {
     Fx.Assert(this.bookmarks.ContainsKey(bookmark) && object.ReferenceEquals(bookmark, this.bookmarks[bookmark].Bookmark), "Something went wrong with our housekeeping - it must exist and must be our intenral reference");
     UpdateExclusiveHandleList(bookmark);
     this.bookmarks.Remove(bookmark);
 }
 public void CheckForCancelation()
 {
     Fx.Assert(this.callbackWrapper != null, "We must have a callback wrapper if we are calling this.");
     this.callbackWrapper.CheckForCancelation();
 }
Exemplo n.º 15
0
 public FatalException(string message, Exception innerException) : base(message, innerException)
 {
     // This can't throw something like ArgumentException because that would be worse than
     // throwing the fatal exception that was requested.
     Fx.Assert(innerException == null || !Fx.IsFatal(innerException), "FatalException can't be used to wrap fatal exceptions.");
 }