diff --git a/src/libraries/System.Runtime/tests/System/Threading/PeriodicTimerTests.cs b/src/libraries/System.Runtime/tests/System/Threading/PeriodicTimerTests.cs index 099096ac4f540..518a36c6bf79b 100644 --- a/src/libraries/System.Runtime/tests/System/Threading/PeriodicTimerTests.cs +++ b/src/libraries/System.Runtime/tests/System/Threading/PeriodicTimerTests.cs @@ -112,20 +112,44 @@ public void PeriodicTimer_NoActiveOperations_TimerNotRooted() [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))] public async Task PeriodicTimer_ActiveOperations_TimerRooted() { - (WeakReference timer, ValueTask task) = Create(); + // Step 1: Verify that if we have an active wait the timer does not get collected. + WeakReference timer = await CreateAndVerifyRooted(); - WaitForTimerToBeCollected(timer, expected: false); + // Step 2: Verify that now the timer does get collected + WaitForTimerToBeCollected(timer, expected: true); - Assert.True(await task); + // It is important that we do these two thing sin NoInlining + // methods. We are only guaranteed that references inside these + // methods are not live anymore when the functions return. + [MethodImpl(MethodImplOptions.NoInlining)] + static async ValueTask> CreateAndVerifyRooted() + { + (WeakReference timer, ValueTask task) = CreateActive(); - WaitForTimerToBeCollected(timer, expected: true); + WaitForTimerToBeCollected(timer, expected: false); + + Assert.True(await task); + + return timer; + } [MethodImpl(MethodImplOptions.NoInlining)] - static (WeakReference, ValueTask) Create() + static (WeakReference, ValueTask) CreateActive() { - var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(1)); - ValueTask task = timer.WaitForNextTickAsync(); - return (new WeakReference(timer), task); + int waitMs = 1; + for (int i = 0; i < 10; i++) + { + var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(waitMs)); + ValueTask task = timer.WaitForNextTickAsync(); + if (!task.IsCompleted) + { + return (new WeakReference(timer), task); + } + + waitMs *= 2; + } + + throw new Exception("Expected to be able to create an active wait for a timer"); } }