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 d4919d725a52c..3eb2c7ccbf4d5 100644
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs
+++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs
@@ -71,5 +71,9 @@ internal enum ThreadPriority : int
[DllImport(Libraries.Kernel32)]
internal static extern bool SetThreadPriority(SafeWaitHandle hThread, int nPriority);
+
+ [DllImport(Libraries.Kernel32, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern 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 67870cf5aadf9..ec495cc7817c9 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
@@ -1684,6 +1684,9 @@
Common\Interop\Windows\Kernel32\Interop.SystemTimeToFileTime.cs
+
+ Common\Interop\Windows\Kernel32\Interop.Threading.cs
+
Common\Interop\Windows\Kernel32\Interop.TimeZone.cs
@@ -2268,8 +2271,8 @@
-
-
+
+
@@ -2301,9 +2304,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 79%
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 fe1eaa37d7577..7363e7034febc 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 d42dd58200b8b..886e774fd22fb 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
{
// This value represents an assumption of how much uncommited stack space a worker thread may use in the future.
// Used in calculations to estimate when to throttle the rate of thread injection to reduce the possibility of
@@ -101,6 +101,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
{