diff --git a/src/System.Private.CoreLib/shared/System/Environment.cs b/src/System.Private.CoreLib/shared/System/Environment.cs index ea04f1000c7..1454f1d56e4 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.cs @@ -11,6 +11,16 @@ namespace System { public static partial class Environment { + public static int ProcessorCount { get; } = GetProcessorCount(); + + /// + /// Gets whether the current machine has only a single processor. + /// + internal static bool IsSingleProcessor => ProcessorCount == 1; + + // Unconditionally return false since .NET Core does not support object finalization during shutdown. + public static bool HasShutdownStarted => false; + public static string? GetEnvironmentVariable(string variable) { if (variable == null) diff --git a/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs b/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs index 1ed5c02be63..e90d7753767 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs @@ -726,7 +726,7 @@ private void ExecuteCallbackHandlers(bool throwOnFirstException) /// A power of 2 representing the number of partitions to use. private static int GetPartitionCount() { - int procs = PlatformHelper.ProcessorCount; + int procs = Environment.ProcessorCount; int count = procs > 8 ? 16 : // capped at 16 to limit memory usage on larger machines procs > 4 ? 8 : diff --git a/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs b/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs index a02dbd86807..4e812549e3c 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs @@ -88,7 +88,7 @@ public bool Wait(int timeoutMs) counts = countsBeforeUpdate; } - int processorCount = PlatformHelper.ProcessorCount; + int processorCount = Environment.ProcessorCount; int spinIndex = processorCount > 1 ? 0 : SpinSleep0Threshold; while (spinIndex < _spinCount) { diff --git a/src/System.Private.CoreLib/shared/System/Threading/ManualResetEventSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/ManualResetEventSlim.cs index e804d382450..f15e4efe0ea 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ManualResetEventSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ManualResetEventSlim.cs @@ -202,7 +202,7 @@ private void Initialize(bool initialState, int spinCount) Debug.Assert(DEFAULT_SPIN_SP >= 0, "Internal error - DEFAULT_SPIN_SP is outside the legal range."); Debug.Assert(DEFAULT_SPIN_SP <= SpinCountState_MaxValue, "Internal error - DEFAULT_SPIN_SP is outside the legal range."); - SpinCount = PlatformHelper.IsSingleProcessor ? DEFAULT_SPIN_SP : spinCount; + SpinCount = Environment.IsSingleProcessor ? DEFAULT_SPIN_SP : spinCount; } /// diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs index 3ea1c15b9b3..bad6e1faae1 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs @@ -68,7 +68,7 @@ private struct CacheLineSeparated private PortableThreadPool() { - _minThreads = s_forcedMinWorkerThreads > 0 ? s_forcedMinWorkerThreads : (short)ThreadPoolGlobals.processorCount; + _minThreads = s_forcedMinWorkerThreads > 0 ? s_forcedMinWorkerThreads : (short)Environment.ProcessorCount; if (_minThreads > MaxPossibleThreadCount) { _minThreads = MaxPossibleThreadCount; diff --git a/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs index 6267c67bb16..928f4c62c24 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs @@ -53,8 +53,6 @@ internal class ReaderWriterCount /// public class ReaderWriterLockSlim : IDisposable { - private static readonly int ProcessorCount = Environment.ProcessorCount; - // Specifying if the lock can be reacquired recursively. private readonly bool _fIsReentrant; @@ -1233,7 +1231,7 @@ private static void SpinWait(int spinCount) const int LockSpinCycles = 20; // Exponential back-off - if ((spinCount < 5) && (ProcessorCount > 1)) + if ((spinCount < 5) && (Environment.ProcessorCount > 1)) { Thread.SpinWait(LockSpinCycles * spinCount); } @@ -1563,7 +1561,7 @@ private void EnterSpin(EnterSpinLockReason reason) Interlocked.Add(ref _enterDeprioritizationState, deprioritizationStateChange); } - int processorCount = ProcessorCount; + int processorCount = Environment.ProcessorCount; for (int spinIndex = 0; ; spinIndex++) { if (spinIndex < LockSpinCount && processorCount > 1) diff --git a/src/System.Private.CoreLib/shared/System/Threading/SpinLock.cs b/src/System.Private.CoreLib/shared/System/Threading/SpinLock.cs index d2717e78f11..0a222dc1593 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/SpinLock.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/SpinLock.cs @@ -349,7 +349,7 @@ private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken) // *** Step 2, Spinning and Yielding var spinner = new SpinWait(); - if (turn > PlatformHelper.ProcessorCount) + if (turn > Environment.ProcessorCount) { spinner.Count = SpinWait.YieldThreshold; } diff --git a/src/System.Private.CoreLib/shared/System/Threading/SpinWait.cs b/src/System.Private.CoreLib/shared/System/Threading/SpinWait.cs index 56ee7c4df7f..1d1b68d1617 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/SpinWait.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/SpinWait.cs @@ -86,7 +86,7 @@ public struct SpinWait /// depends on the likelihood of the spin being successful and how long the wait would be but those are not accounted /// for here. /// - internal static readonly int SpinCountforSpinBeforeWait = PlatformHelper.IsSingleProcessor ? 1 : 35; + internal static readonly int SpinCountforSpinBeforeWait = Environment.IsSingleProcessor ? 1 : 35; // The number of times we've spun already. private int _count; @@ -114,7 +114,7 @@ internal set /// On a single-CPU machine, always yields the processor. On machines with /// multiple CPUs, may yield after an unspecified number of calls. /// - public bool NextSpinWillYield => _count >= YieldThreshold || PlatformHelper.IsSingleProcessor; + public bool NextSpinWillYield => _count >= YieldThreshold || Environment.IsSingleProcessor; /// /// Performs a single spin. @@ -175,7 +175,7 @@ private void SpinOnceCore(int sleep1Threshold) _count >= YieldThreshold && ((_count >= sleep1Threshold && sleep1Threshold >= 0) || (_count - YieldThreshold) % 2 == 0) ) || - PlatformHelper.IsSingleProcessor) + Environment.IsSingleProcessor) { // // We must yield. @@ -346,42 +346,4 @@ public static bool SpinUntil(Func condition, int millisecondsTimeout) } #endregion } - - /// - /// A helper class to get the number of processors, it updates the numbers of processors every sampling interval. - /// - internal static class PlatformHelper - { - private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 30000; // How often to refresh the count, in milliseconds. - private static volatile int s_processorCount; // The last count seen. - private static volatile int s_lastProcessorCountRefreshTicks; // The last time we refreshed. - - /// - /// Gets the number of available processors - /// - internal static int ProcessorCount - { - get - { - int now = Environment.TickCount; - int procCount = s_processorCount; - if (procCount == 0 || (now - s_lastProcessorCountRefreshTicks) >= PROCESSOR_COUNT_REFRESH_INTERVAL_MS) - { - s_processorCount = procCount = Environment.ProcessorCount; - s_lastProcessorCountRefreshTicks = now; - } - - Debug.Assert(procCount > 0, - "Processor count should be greater than 0."); - - return procCount; - } - } - - /// - /// Gets whether the current machine has only a single processor. - /// - /// This typically does not change on a machine, so it's checked only once. - internal static readonly bool IsSingleProcessor = ProcessorCount == 1; - } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs index f59785ac747..68cdc6ceecc 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @@ -25,8 +25,6 @@ namespace System.Threading { internal static class ThreadPoolGlobals { - public static readonly int processorCount = Environment.ProcessorCount; - public static volatile bool threadPoolInitialized; public static bool enableWorkerTracking; @@ -436,7 +434,7 @@ internal void EnsureThreadRequested() // by the VM by the time we reach this point. // int count = numOutstandingThreadRequests; - while (count < ThreadPoolGlobals.processorCount) + while (count < Environment.ProcessorCount) { int prev = Interlocked.CompareExchange(ref numOutstandingThreadRequests, count + 1, count); if (prev == count)