예제 #1
0
        private static void ChainStateMachinesBasedOnJointableTasks(DebuggerContext context, List <AsyncStateMachine> allStateMachines)
        {
            foreach (AsyncStateMachine?stateMachine in allStateMachines)
            {
                if (stateMachine.Previous is null)
                {
                    try
                    {
                        ClrObject joinableTask = stateMachine.StateMachine.TryGetObjectField("<>4__this");
                        ClrObject wrappedTask  = joinableTask.TryGetObjectField("wrappedTask");
                        if (!wrappedTask.IsNull)
                        {
                            AsyncStateMachine?previousStateMachine = allStateMachines
                                                                     .FirstOrDefault(s => s.Task.Address == wrappedTask.Address);
                            if (previousStateMachine is object && stateMachine != previousStateMachine)
                            {
                                stateMachine.Previous     = previousStateMachine;
                                previousStateMachine.Next = stateMachine;
                                previousStateMachine.DependentCount++;
                            }
                        }
                    }
#pragma warning disable CA1031 // Do not catch general exception types
                    catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                    {
                        context.Output.WriteLine($"Fail to fix continuation of state {stateMachine.StateMachine.Address:x} Error: {ex.Message}");
                    }
                }
            }
        }
예제 #2
0
        private static void ChainStateMachinesBasedOnTaskContinuations(DebuggerContext context, Dictionary <ulong, AsyncStateMachine> knownStateMachines)
        {
            foreach (AsyncStateMachine?stateMachine in knownStateMachines.Values)
            {
                ClrObject taskObject = stateMachine.Task;
                try
                {
                    while (!taskObject.IsNull)
                    {
                        // 3 cases in order to get the _target:
                        // 1. m_continuationObject.m_action._target
                        // 2. m_continuationObject._target
                        // 3. m_continuationObject.m_task.m_stateObject._target
                        ClrObject continuationObject = taskObject.TryGetObjectField("m_continuationObject");
                        if (continuationObject.IsNull)
                        {
                            break;
                        }

                        ChainStateMachineBasedOnTaskContinuations(knownStateMachines, stateMachine, continuationObject);

                        taskObject = continuationObject;
                    }
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    context.Output.WriteLine($"Fail to fix continuation of state {stateMachine.StateMachine.Address:x} Error: {ex.Message}");
                }
            }
        }
예제 #3
0
        private static void MarkThreadingBlockTasks(DebuggerContext context, List <AsyncStateMachine> allStateMachines)
        {
            foreach (var thread in context.Runtime.Threads)
            {
                var stackFrame = thread.EnumerateStackTrace().Take(50).FirstOrDefault(
                    f => f.Method is { } method &&
                    string.Equals(f.Method.Name, "CompleteOnCurrentThread", StringComparison.Ordinal) &&
                    string.Equals(f.Method.Type?.Name, "Microsoft.VisualStudio.Threading.JoinableTask", StringComparison.Ordinal));

                if (stackFrame is object)
                {
                    var visitedObjects = new HashSet <ulong>();
                    foreach (IClrStackRoot stackRoot in thread.EnumerateStackRoots())
                    {
                        ClrObject stackObject = stackRoot.Object;
                        if (string.Equals(stackObject.Type?.Name, "Microsoft.VisualStudio.Threading.JoinableTask", StringComparison.Ordinal) ||
                            string.Equals(stackObject.Type?.BaseType?.Name, "Microsoft.VisualStudio.Threading.JoinableTask", StringComparison.Ordinal))
                        {
                            if (visitedObjects.Add(stackObject.Address))
                            {
                                var joinableTaskObject = new ClrObject(stackObject.Address, stackObject.Type);
                                int state = joinableTaskObject.ReadField <int>("state");
                                if ((state & 0x10) == 0x10)
                                {
                                    // This flag indicates the JTF is blocking the thread
                                    var wrappedTask = joinableTaskObject.TryGetObjectField("wrappedTask");
                                    if (!wrappedTask.IsNull)
                                    {
                                        var blockingStateMachine = allStateMachines
                                                                   .FirstOrDefault(s => s.Task.Address == wrappedTask.Address);
                                        if (blockingStateMachine is object)
                                        {
                                            blockingStateMachine.BlockedThread       = thread.OSThreadId;
                                            blockingStateMachine.BlockedJoinableTask = joinableTaskObject;
                                        }
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #4
0
        private static void ChainStateMachineBasedOnTaskContinuations(Dictionary <ulong, AsyncStateMachine> knownStateMachines, AsyncStateMachine stateMachine, ClrObject continuationObject)
        {
            var continuationAction = continuationObject.TryGetObjectField("m_action");

            // case 1
            var continuationTarget = continuationAction.TryGetObjectField("_target");

            if (continuationTarget.IsNull)
            {
                // case 2
                continuationTarget = continuationObject.TryGetObjectField("_target");
                if (continuationTarget.IsNull)
                {
                    // case 3
                    continuationTarget = continuationObject.TryGetObjectField("m_task").TryGetObjectField("m_stateObject").TryGetObjectField("_target");
                }
            }

            while (!continuationTarget.IsNull)
            {
                // now get the continuation from the target
                var continuationTargetStateMachine = continuationTarget.TryGetObjectField("m_stateMachine");
                if (!continuationTargetStateMachine.IsNull)
                {
                    AsyncStateMachine targetAsyncState;
                    if (knownStateMachines.TryGetValue(continuationTargetStateMachine.Address, out targetAsyncState) && targetAsyncState != stateMachine)
                    {
                        stateMachine.Next = targetAsyncState;
                        stateMachine.DependentCount++;
                        targetAsyncState.Previous = stateMachine;
                    }

                    break;
                }
                else
                {
                    var nextContinuation = continuationTarget.TryGetObjectField("m_continuation");
                    continuationTarget = nextContinuation.TryGetObjectField("_target");
                }
            }

            var items = continuationObject.TryGetObjectField("_items");

            if (!items.IsNull && items.IsArray && items.ContainsPointers)
            {
                foreach (var promise in items.EnumerateReferences(true))
                {
                    if (!promise.IsNull)
                    {
                        var innerContinuationObject = promise.TryGetObjectField("m_continuationObject");
                        if (!innerContinuationObject.IsNull)
                        {
                            ChainStateMachineBasedOnTaskContinuations(knownStateMachines, stateMachine, innerContinuationObject);
                        }
                        else
                        {
                            ChainStateMachineBasedOnTaskContinuations(knownStateMachines, stateMachine, promise);
                        }
                    }
                }
            }
        }