From: Stephen Toub Date: Fri, 7 Jun 2019 20:09:38 +0000 (-0400) Subject: Add debug data to help diagnose HTTP2 test failure (dotnet/corefx#38345) X-Git-Tag: submit/tizen/20210909.063632~11031^2~1357 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b585c84595ae6d385b98194fcb5dd55b9339c12d;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Add debug data to help diagnose HTTP2 test failure (dotnet/corefx#38345) The GoAwayFrame_AbortAllPendingStreams_StreamFailWithExpectedException test has been frequently hanging on some Linux distros. This adds some diagnostics to help track it down in CI: every minute, it'll dump out the fields of the async state machine, which if nothing else will let us see which await it's stuck on and what is the state of each of the tasks. Commit migrated from https://github.com/dotnet/corefx/commit/410a162f68eb319e8066ac7bf2d7bcd6e2ce47d0 --- diff --git a/src/libraries/Common/tests/System/Threading/Tasks/GetStateMachineData.cs b/src/libraries/Common/tests/System/Threading/Tasks/GetStateMachineData.cs new file mode 100644 index 00000000000..00ad9a8a10e --- /dev/null +++ b/src/libraries/Common/tests/System/Threading/Tasks/GetStateMachineData.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; + +/// +/// Fragile trick for getting a description of the current state of a .NET Core async method state machine. +/// To use, first await FetchAsync to get back an object: +/// object box = await GetStateMachineData.FetchAsync(); +/// and then when the description is desired, use: +/// string description = GetStateMachineData.Describe(box); +/// +namespace System.Threading.Tasks +{ + internal sealed class GetStateMachineData : ICriticalNotifyCompletion + { + private object _box; + + private GetStateMachineData() { } + public static GetStateMachineData FetchAsync() => new GetStateMachineData(); + + public GetStateMachineData GetAwaiter() => this; + public bool IsCompleted => false; + public void OnCompleted(Action continuation) => UnsafeOnCompleted(continuation); + public void UnsafeOnCompleted(Action continuation) + { + _box = continuation.Target; + Task.Run(continuation); + } + public object GetResult() => _box; + + public static string Describe(object box) + { + if (box is null) + { + return "(Couldn't get state machine box.)"; + } + + FieldInfo stateMachineField = box.GetType().GetField("StateMachine", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (stateMachineField is null) + { + return $"(Couldn't get state machine field from {box}."; + } + + IAsyncStateMachine stateMachine = stateMachineField.GetValue(box) as IAsyncStateMachine; + if (stateMachine is null) + { + return $"(Null state machine from {box}.)"; + } + + Type stateMachineType = stateMachine.GetType(); + FieldInfo[] fields = stateMachineType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + + var sb = new StringBuilder(); + sb.AppendLine(stateMachineType.FullName); + foreach (FieldInfo fi in fields) + { + sb.AppendLine($" {fi.Name}: {ToString(fi.GetValue(stateMachine))}"); + } + return sb.ToString(); + } + + private static string ToString(object value) + { + if (value is null) + { + return "(null)"; + } + + if (value is Task t) + { + return $"Status: {t.Status}, Exception: {t.Exception?.InnerException}"; + } + + return value.ToString(); + } + } +} diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs index e951d657a53..74176f3c6fd 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs @@ -798,6 +798,7 @@ namespace System.Net.Http.Functional.Tests [ConditionalFact(nameof(SupportsAlpn))] public async Task GoAwayFrame_AbortAllPendingStreams_StreamFailWithExpectedException() { + using (new Timer(s => Console.WriteLine(GetStateMachineData.Describe(s)), await GetStateMachineData.FetchAsync(), 60_000, 60_000)) using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer()) using (HttpClient client = CreateHttpClient()) { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index be3b84d94bd..51f84f45806 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -1,4 +1,4 @@ - + {C85CF035-7804-41FF-9557-48B7C948B58D} $(DefineConstants);TargetsWindows @@ -80,6 +80,9 @@ Common\System\Threading\TrackingSynchronizationContext.cs + + Common\System\Threading\Tasks\GetStateMachineData.cs + Common\System\Threading\Tasks\TaskTimeoutExtensions.cs