// // Copyright (c) Microsoft Corporation. All rights reserved. // namespace System.Activities.Runtime { using System.Activities.Tracking; using System.Collections.Generic; using System.Runtime; using System.Runtime.Serialization; /// /// Evaluates a new-fast-path (SkipArgumentsResolution and Not UseOldFastPath) expression /// [DataContract] internal class ExecuteSynchronousExpressionWorkItem : ActivityExecutionWorkItem, ActivityInstanceMap.IActivityReference { private ActivityWithResult expressionActivity; private long instanceId; private ResolveNextArgumentWorkItem nextArgumentWorkItem; private Location resultLocation; /// /// Initializes a new instance of the ExecuteSynchronousExpressionWorkItem class. /// Called by the pool. /// public ExecuteSynchronousExpressionWorkItem() { this.IsPooled = true; } [DataMember(EmitDefaultValue = false, Name = "instanceId")] internal long SerializedInstanceId { get { return this.instanceId; } set { this.instanceId = value; } } [DataMember(EmitDefaultValue = false, Name = "nextArgumentWorkItem")] internal ResolveNextArgumentWorkItem SerializedNextArgumentWorkItem { get { return this.nextArgumentWorkItem; } set { this.nextArgumentWorkItem = value; } } [DataMember(EmitDefaultValue = false, Name = "resultLocation")] internal Location SerializedResultLocation { get { return this.resultLocation; } set { this.resultLocation = value; } } /// /// Gets the Activity reference to serialize at persistence /// Activity ActivityInstanceMap.IActivityReference.Activity { get { return this.expressionActivity; } } /// /// Called each time a work item is acquired from the pool /// /// The ActivityInstance containin the variable or argument that contains this expression /// The expression to evaluate /// The ActivityInstanceID to use for expressionActivity /// Location where the result of expressionActivity should be placed /// WorkItem to execute after this one public void Initialize(ActivityInstance parentInstance, ActivityWithResult expressionActivity, long instanceId, Location resultLocation, ResolveNextArgumentWorkItem nextArgumentWorkItem) { this.Reinitialize(parentInstance); Fx.Assert(resultLocation != null, "We should only use this work item when we are resolving arguments/variables and therefore have a result location."); Fx.Assert(expressionActivity.IsFastPath, "Should only use this work item for fast path expressions"); this.expressionActivity = expressionActivity; this.instanceId = instanceId; this.resultLocation = resultLocation; this.nextArgumentWorkItem = nextArgumentWorkItem; } /// /// Trace when we're scheduled /// public override void TraceScheduled() { TraceRuntimeWorkItemScheduled(); } /// /// Trace when we start /// public override void TraceStarting() { TraceRuntimeWorkItemStarting(); } /// /// Trace when we complete /// public override void TraceCompleted() { TraceRuntimeWorkItemCompleted(); } /// /// Execute the work item /// /// The executor /// The bookmark manager /// True to continue executing work items, false to yield the thread public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) { ActivityInfo activityInfo = null; this.TrackExecuting(executor, ref activityInfo); try { executor.ExecuteInResolutionContextUntyped(this.ActivityInstance, this.expressionActivity, this.instanceId, this.resultLocation); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.TrackFaulted(executor, ref activityInfo); if (this.nextArgumentWorkItem != null) { executor.ScheduleItem(this.nextArgumentWorkItem); } executor.ScheduleExpressionFaultPropagation(this.expressionActivity, this.instanceId, this.ActivityInstance, e); return true; } finally { if (this.ActivityInstance.InstanceMap != null) { this.ActivityInstance.InstanceMap.RemoveEntry(this); } } this.TrackClosed(executor, ref activityInfo); if (this.nextArgumentWorkItem != null) { this.EvaluateNextArgument(executor); } return true; } /// /// Fix up activity reference after persistence /// /// The persisted activity reference /// The map containing persisted activity references void ActivityInstanceMap.IActivityReference.Load(Activity activity, ActivityInstanceMap instanceMap) { ActivityWithResult activityWithResult = activity as ActivityWithResult; if (activityWithResult == null) { throw FxTrace.Exception.AsError( new ValidationException(SR.ActivityTypeMismatch(activity.DisplayName, typeof(ActivityWithResult).Name))); } this.expressionActivity = activityWithResult; } /// /// Release work item back to pool /// /// Executor that owns the work item. protected override void ReleaseToPool(ActivityExecutor executor) { this.ClearForReuse(); this.expressionActivity = null; this.instanceId = 0; this.resultLocation = null; this.nextArgumentWorkItem = null; executor.ExecuteSynchronousExpressionWorkItemPool.Release(this); } private void EvaluateNextArgument(ActivityExecutor executor) { if (executor.HasPendingTrackingRecords && this.nextArgumentWorkItem.CanExecuteUserCode()) { // Need to schedule a separate work item so we flush tracking before we continue. // This ensures consistent ordering of tracking output and user code. executor.ScheduleItem(this.nextArgumentWorkItem); } else { executor.ExecuteSynchronousWorkItem(this.nextArgumentWorkItem); } } private void EnsureActivityInfo(ref ActivityInfo activityInfo) { if (activityInfo == null) { activityInfo = new ActivityInfo(this.expressionActivity, this.instanceId); } } private void TrackClosed(ActivityExecutor executor, ref ActivityInfo activityInfo) { if (executor.ShouldTrackActivityStateRecordsClosedState) { this.TrackState(executor, ActivityInstanceState.Closed, ref activityInfo); } } private void TrackExecuting(ActivityExecutor executor, ref ActivityInfo activityInfo) { if (executor.ShouldTrackActivityStateRecordsExecutingState) { this.TrackState(executor, ActivityInstanceState.Executing, ref activityInfo); } } private void TrackFaulted(ActivityExecutor executor, ref ActivityInfo activityInfo) { if (executor.ShouldTrackActivityStateRecords) { this.TrackState(executor, ActivityInstanceState.Faulted, ref activityInfo); } } private void TrackState(ActivityExecutor executor, ActivityInstanceState state, ref ActivityInfo activityInfo) { if (executor.ShouldTrackActivity(this.expressionActivity.DisplayName)) { this.EnsureActivityInfo(ref activityInfo); executor.AddTrackingRecord(new ActivityStateRecord(executor.WorkflowInstanceId, activityInfo, state)); } } } }