|
// <copyright file="ExecuteSynchronousExpressionWorkItem.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.Runtime
{
using System.Activities.Tracking;
using System.Collections.Generic;
using System.Runtime;
using System.Runtime.Serialization;
/// <summary>
/// Evaluates a new-fast-path (SkipArgumentsResolution and Not UseOldFastPath) expression
/// </summary>
[DataContract]
internal class ExecuteSynchronousExpressionWorkItem : ActivityExecutionWorkItem, ActivityInstanceMap.IActivityReference
{
private ActivityWithResult expressionActivity;
private long instanceId;
private ResolveNextArgumentWorkItem nextArgumentWorkItem;
private Location resultLocation;
/// <summary>
/// Initializes a new instance of the ExecuteSynchronousExpressionWorkItem class.
/// Called by the pool.
/// </summary>
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; }
}
/// <summary>
/// Gets the Activity reference to serialize at persistence
/// </summary>
Activity ActivityInstanceMap.IActivityReference.Activity
{
get { return this.expressionActivity; }
}
/// <summary>
/// Called each time a work item is acquired from the pool
/// </summary>
/// <param name="parentInstance">The ActivityInstance containin the variable or argument that contains this expression</param>
/// <param name="expressionActivity">The expression to evaluate</param>
/// <param name="instanceId">The ActivityInstanceID to use for expressionActivity</param>
/// <param name="resultLocation">Location where the result of expressionActivity should be placed</param>
/// <param name="nextArgumentWorkItem">WorkItem to execute after this one</param>
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;
}
/// <summary>
/// Trace when we're scheduled
/// </summary>
public override void TraceScheduled()
{
TraceRuntimeWorkItemScheduled();
}
/// <summary>
/// Trace when we start
/// </summary>
public override void TraceStarting()
{
TraceRuntimeWorkItemStarting();
}
/// <summary>
/// Trace when we complete
/// </summary>
public override void TraceCompleted()
{
TraceRuntimeWorkItemCompleted();
}
/// <summary>
/// Execute the work item
/// </summary>
/// <param name="executor">The executor</param>
/// <param name="bookmarkManager">The bookmark manager</param>
/// <returns>True to continue executing work items, false to yield the thread</returns>
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;
}
/// <summary>
/// Fix up activity reference after persistence
/// </summary>
/// <param name="activity">The persisted activity reference</param>
/// <param name="instanceMap">The map containing persisted activity references</param>
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;
}
/// <summary>
/// Release work item back to pool
/// </summary>
/// <param name="executor">Executor that owns the work item.</param>
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));
}
}
}
}
|