From 6e8d60fb32f89f8925aa185a2ac15a329b60d59a Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Mon, 10 Jun 2019 14:24:55 -0700 Subject: [PATCH] Expose and test Timer.ActiveCount - Depends on https://github.com/dotnet/coreclr/pull/25061 - Fixes https://github.com/dotnet/corefx/issues/38422 Commit migrated from https://github.com/dotnet/corefx/commit/e2c3de82029f2187b3b0ad36a060e5f7e2ac0e93 --- .../ref/System.Threading.Timer.cs | 1 + .../src/ApiCompatBaseline.uapaot.txt | 2 + .../tests/System.Threading.Timer.Tests.csproj | 4 ++ .../tests/TimerMetricsTests.cs | 76 ++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 src/libraries/System.Threading.Timer/src/ApiCompatBaseline.uapaot.txt create mode 100644 src/libraries/System.Threading.Timer/tests/TimerMetricsTests.cs diff --git a/src/libraries/System.Threading.Timer/ref/System.Threading.Timer.cs b/src/libraries/System.Threading.Timer/ref/System.Threading.Timer.cs index ba2fa66..7f660bb 100644 --- a/src/libraries/System.Threading.Timer/ref/System.Threading.Timer.cs +++ b/src/libraries/System.Threading.Timer/ref/System.Threading.Timer.cs @@ -20,6 +20,7 @@ namespace System.Threading public bool Change(System.TimeSpan dueTime, System.TimeSpan period) { throw null; } [System.CLSCompliantAttribute(false)] public bool Change(uint dueTime, uint period) { throw null; } + public static long ActiveCount { get { throw null; } } public void Dispose() { } public bool Dispose(System.Threading.WaitHandle notifyObject) { throw null; } public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; } diff --git a/src/libraries/System.Threading.Timer/src/ApiCompatBaseline.uapaot.txt b/src/libraries/System.Threading.Timer/src/ApiCompatBaseline.uapaot.txt new file mode 100644 index 0000000..1acb8f0 --- /dev/null +++ b/src/libraries/System.Threading.Timer/src/ApiCompatBaseline.uapaot.txt @@ -0,0 +1,2 @@ +Compat issues with assembly System.Threading.Timer: +MembersMustExist : Member 'System.Threading.Timer.ActiveCount.get()' does not exist in the implementation but it does exist in the contract. diff --git a/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj b/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj index 5c8fae3b..4928271 100644 --- a/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj +++ b/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj @@ -10,5 +10,9 @@ + + + CommonTest\System\Threading\ThreadTestHelpers.cs + \ No newline at end of file diff --git a/src/libraries/System.Threading.Timer/tests/TimerMetricsTests.cs b/src/libraries/System.Threading.Timer/tests/TimerMetricsTests.cs new file mode 100644 index 0000000..cff37b6 --- /dev/null +++ b/src/libraries/System.Threading.Timer/tests/TimerMetricsTests.cs @@ -0,0 +1,76 @@ +// 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; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tests; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; + +public static partial class TimerMetricsTests +{ + [Fact] + public static void CountTest() + { + RemoteExecutor.Invoke(() => + { + const int TimersPerThread = 64; + int processorCount = Environment.ProcessorCount; + int totalTimerCount = processorCount * TimersPerThread; + + var timers = new List(totalTimerCount); + TimerCallback timerCallback = _ => { }; + var startCreateTimerThreads = new ManualResetEvent(false); + Action createTimerThreadStart = () => + { + startCreateTimerThreads.WaitOne(); + for (int i = 0; i < TimersPerThread; ++i) + { + lock (timers) + { + timers.Add( + new Timer( + timerCallback, + null, + ThreadTestHelpers.UnexpectedTimeoutMilliseconds, + ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); + Assert.True(Timer.ActiveCount >= timers.Count); + } + } + }; + var waitsForThread = new Action[processorCount]; + for (int i = 0; i < processorCount; ++i) + { + Thread t = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], createTimerThreadStart); + t.IsBackground = true; + t.Start(); + } + + startCreateTimerThreads.Set(); + foreach (Action waitForThread in waitsForThread) + { + waitForThread(); + } + + // To leave some room for unknown timers to be scheduled and removed, remove a large number of timers at a time and + // verify that the timer count has decreased + while (timers.Count > 0) + { + long timerCountBeforeRemove = Timer.ActiveCount; + int endIndex = timers.Count - processorCount * 8; + for (int i = timers.Count - 1; i >= Math.Max(0, endIndex); --i) + { + timers[i].Dispose(); + timers.RemoveAt(i); + } + + if (endIndex >= 0) + { + Assert.True(Timer.ActiveCount < timerCountBeforeRemove); + } + } + }).Dispose(); + } +} -- 2.7.4