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)