public static ClrInstance[] TryResolveContinuations(ClrInstance continuation, CausalityContext context) { if (continuation.IsListOfObjects()) { var result = new List <ClrInstance>(); int size = (int)continuation["_size"].Instance.ValueOrDefault !; var items = continuation["_items"].Instance.Items; for (int i = 0; i < size; i++) { var continuationItem = TryResolveContinuationInstance(items[i], context); if (continuationItem != null) { result.Add(continuationItem); } return(result.ToArray()); } } var resolvedContinuation = TryResolveContinuationInstance(continuation, context); if (resolvedContinuation != null) { return(new[] { resolvedContinuation }); } return(Array.Empty <ClrInstance>()); }
protected CausalityNode(CausalityContext context, ClrInstance clrInstance, NodeKind kind) { Context = context; ClrInstance = clrInstance; Id = Contract.AssertNotNull(clrInstance.ValueOrDefault?.ToString(), "ValueOrDefault should not be null"); Kind = kind; }
public void AddInstance(ClrInstance instance) { _instances.Add(instance); if (instance.ObjectAddress != null) { _instancesByAddress[instance.ObjectAddress.Value] = instance; } }
public bool TryGetNodeFor(ClrInstance instance, [NotNullWhen(true)] out CausalityNode?result) { if (instance.ObjectAddress != null) { return(_nodesByAddress.TryGetValue(instance.ObjectAddress.Value, out result)); } result = null; return(false); }
public CausalityNode GetOrCreate(ClrInstance instance, NodeKind kind) { if (instance.ObjectAddress == null) { throw new InvalidOperationException($"instance.ObjectAddress should not be null. Instance: {instance}."); } //var node = _nodes.GetOrAdd(instance, task => new CausalityNode(this, task, kind: kind)); //_nodesByAddress.GetOrAdd(node.TaskInstance.ObjectAddress.Value, node); var node = _nodesByAddress.GetOrAdd(instance.ObjectAddress.Value, _ => CausalityNode.Create(this, instance, kind: kind)); return(node); }
public static CausalityNode Create(CausalityContext context, ClrInstance clrInstance, NodeKind kind) { return(kind switch { NodeKind.Task => new TaskNode(context, clrInstance), NodeKind.TaskCompletionSource => new TaskCompletionSourceNode(context, clrInstance), NodeKind.AsyncStateMachine => new AsyncStateMachineNode(context, clrInstance), NodeKind.AwaitTaskContinuation => new AwaitTaskContinuationNode(context, clrInstance), NodeKind.Thread => new ThreadNode(context, clrInstance), NodeKind.ManualResetEventSlim => new ManualResetEventSlimNode(context, clrInstance), NodeKind.SemaphoreSlim => new SemaphoreSlimNode(context, clrInstance), NodeKind.SynchronizationContext => new SynchronizationContextNode(context, clrInstance), _ => Return(() => new CausalityNode(context, clrInstance, kind)), });
public AsyncStateMachineNode(CausalityContext context, ClrInstance clrInstance) : base(context, clrInstance, NodeKind.AsyncStateMachine) { _status = StateMachineState switch { InitialState => StateMachineStatus.Created, CompletedState => StateMachineStatus.Completed, _ => StateMachineStatus.Awaiting, }; if (_status == StateMachineStatus.Awaiting) { _awaitedTask = GetAwaitedTask(); Contract.AssertNotNull(_awaitedTask, $"For state machine state '{StateMachineState}' an awaited task should be available"); } _resultingTask = GetResultingTask(clrInstance, Context.Registry); }
public override void Link() { if (TaskKind == TaskKind.WhenAll) { foreach (var item in WhenAllContinuations) { AddDependency(item); } } var parent = ClrInstance.TryGetFieldValue("m_parent")?.Instance; if (parent.IsNotNull()) { // m_parent is not null for Parallel.ForEach, for instance. AddDependent(parent); } // The continuation instance is a special (causality) node, then just adding the edge // without extra processing. if (Context.TryGetNodeFor(ContinuationObject, out var dependentNode)) { AddDependent(dependentNode); } else { var continuations = ContinuationResolver.TryResolveContinuations(ContinuationObject, Context); foreach (var c in continuations) { // TODO: need to add an adge name for visualization purposes! // Tasks created with 'ContinueWith' are different from other continuations. // In this case they're dependencies not dependents. if (Context.Registry.IsContinuationTaskFromTask(c)) { AddDependency(c); } else { AddDependent(c); } } } }
public static ClrInstance?TryResolveContinuationForAction(ClrInstance instance, CausalityContext context) { Contract.Requires(instance.IsOfType(typeof(Action), context), $"A given instance should be of type System.Action, but was '{instance.Type.TypeToString(context.Registry)}'"); var continuation = instance; var actionTarget = continuation["_target"].Instance; if (actionTarget.IsOfType(context.Registry.ContinuationWrapperType)) { // Do we need to look at the m_innerTask field as well here? return(actionTarget["m_continuation"].Instance); } // If the action points to a closure, it is possible that the closure // is responsible for setting the result of a task completion source. // There is no simple way to detect whether this is the case or not, so we will add the "edge" unconditionally. if (actionTarget.Type.IsClosure()) { foreach (var field in actionTarget.Fields) { if (field.Instance.IsTaskCompletionSource(context)) { return(field.Instance); } } } // m_stateMachine field is defined in AsyncMethodBuilderCore and in MoveNextRunner. var stateMachine = actionTarget.TryGetFieldValue("m_stateMachine")?.Instance; if (stateMachine.IsNull()) { return(null); } return(stateMachine); }
public static ClrInstance?TryResolveContinuationInstance(ClrInstance continuation, CausalityContext context) { if (continuation.IsOfType(context.Registry.StandardTaskContinuationType)) { return(continuation["m_task"].Instance); } if (continuation.IsTaskCompletionSource(context)) { return(continuation["m_task"].Instance); } if (continuation.IsCompletedTaskContinuation(context)) { // Continuation is a special sentinel instance that indicates that the task is completed. return(null); } if (continuation.IsOfType(typeof(Action), context)) { return(TryResolveContinuationForAction(continuation, context)); } if (continuation.IsOfType(context.Registry.AwaitTaskContinuationIndex) || continuation.IsOfType(context.Registry.TaskIndex)) { return(TryResolveContinuationForAction(continuation["m_action"].Instance, context)); } // Need to compare by name since GetTypeByName does not work for the generic type during initialization if (continuation.IsListOfObjects()) { Contract.Assert(false, "Please call 'TryResolveContinuations' for a list of continuations."); } return(null); }
public CausalityNode GetNode(ClrInstance instance) { Contract.AssertNotNull(instance.ObjectAddress); return(_nodesByAddress.GetOrAdd(instance.ObjectAddress.Value, task => CausalityNode.Create(this, instance, kind: NodeKind.Unknown))); }
public SynchronizationContextNode(CausalityContext context, ClrInstance clrInstance) : base(context, clrInstance, NodeKind.SynchronizationContext) { }
public AwaitTaskContinuationNode(CausalityContext context, ClrInstance clrInstance) : base(context, clrInstance, NodeKind.AwaitTaskContinuation) { }
public ManualResetEventSlimNode(CausalityContext context, ClrInstance clrInstance) : base(context, clrInstance, NodeKind.ManualResetEventSlim) { }
public bool TryGetInstanceAt(ulong address, out ClrInstance result) { return(_instancesByAddress.TryGetValue(address, out result)); }
public TaskInstance(ClrInstance instance) { _instance = instance; }
public SemaphoreSlimNode(CausalityContext context, ClrInstance clrInstance) : base(context, clrInstance, NodeKind.SemaphoreSlim) { _asyncWaiters = GetAsynchronousWaiters().ToList(); }
public TaskNode(CausalityContext context, ClrInstance clrInstance) : base(context, clrInstance, NodeKind.Task) { _taskInstance = new TaskInstance(clrInstance); }
public TaskCompletionSourceNode(CausalityContext context, ClrInstance clrInstance) : base(context, clrInstance, NodeKind.TaskCompletionSource) { }