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
{