diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs index f64a23f772234..9a53b48bec17c 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs @@ -70,5 +70,9 @@ internal enum ThreadPriority : int [LibraryImport(Libraries.Kernel32)] [return:MarshalAs(UnmanagedType.Bool)] internal static partial bool SetThreadPriority(SafeWaitHandle hThread, int nPriority); + + [LibraryImport(Libraries.Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool GetThreadIOPendingFlag(nint hThread, out BOOL lpIOIsPending); } } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index bbef0e98c7da7..b200e12ef36c5 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1854,6 +1854,9 @@ Common\Interop\Windows\Kernel32\Interop.SystemTimeToFileTime.cs + + Common\Interop\Windows\Kernel32\Interop.Threading.cs + Common\Interop\Windows\Kernel32\Interop.TimeZone.cs @@ -2502,8 +2505,8 @@ - - + + @@ -2537,9 +2540,6 @@ - - Interop\Windows\Kernel32\Interop.Threading.cs - diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.CpuUtilizationReader.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.Unix.cs similarity index 80% rename from src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.CpuUtilizationReader.Unix.cs rename to src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.Unix.cs index ea754f9185e9b..100ddf0c675d1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.CpuUtilizationReader.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.Unix.cs @@ -5,6 +5,11 @@ namespace System.Threading { internal sealed partial class PortableThreadPool { + private static partial class WorkerThread + { + private static bool IsIOPending => false; + } + private struct CpuUtilizationReader { private Interop.Sys.ProcessCpuInformation _cpuInfo; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.CpuUtilizationReader.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.Windows.cs similarity index 75% rename from src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.CpuUtilizationReader.Windows.cs rename to src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.Windows.cs index 4818512ba8183..6f5d7eff9d96c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.CpuUtilizationReader.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.Windows.cs @@ -8,6 +8,20 @@ namespace System.Threading { internal sealed partial class PortableThreadPool { + private static partial class WorkerThread + { + private static bool IsIOPending + { + get + { + bool success = + Interop.Kernel32.GetThreadIOPendingFlag(Interop.Kernel32.GetCurrentThread(), out Interop.BOOL isIOPending); + Debug.Assert(success); + return !success || isIOPending != Interop.BOOL.FALSE; + } + } + } + private struct CpuUtilizationReader { public long _idleTime; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs index 0e0323e3bc446..96578b9de6b8d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs @@ -10,7 +10,7 @@ internal sealed partial class PortableThreadPool /// /// The worker thread infastructure for the CLR thread pool. /// - private static class WorkerThread + private static partial class WorkerThread { private const int SemaphoreSpinCountDefaultBaseline = 70; #if !TARGET_ARM64 && !TARGET_ARM && !TARGET_LOONGARCH64 @@ -115,6 +115,12 @@ private static void WorkerThreadStart() } } + // The thread cannot exit if it has IO pending, otherwise the IO may be canceled + if (IsIOPending) + { + continue; + } + threadAdjustmentLock.Acquire(); try {