Skip to content

Commit d07d2b8

Browse files
authored
[6.0] Check for pending IO in the portable thread pool's worker threads (#82248)
* [6.0] Check for pending IO in the portable thread pool's worker threads - Port of #82245 - When Resource Monitor is attached, some async IO operations are bound to the thread that issued it even though the IO handle is bound to an IOCP. If the thread exits, the async IO operation is aborted. This can lead to hangs or unexpected exceptions. - Added a check that was missing in the portable thread pool implementation to prevent exiting a worker thread when it has pending IO Port of fix for #82207 * Refactor Windows-specific code
1 parent 27d6b41 commit d07d2b8

File tree

5 files changed

+35
-6
lines changed

5 files changed

+35
-6
lines changed

src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,9 @@ internal enum ThreadPriority : int
7171

7272
[DllImport(Libraries.Kernel32)]
7373
internal static extern bool SetThreadPriority(SafeWaitHandle hThread, int nPriority);
74+
75+
[DllImport(Libraries.Kernel32, SetLastError = true)]
76+
[return: MarshalAs(UnmanagedType.Bool)]
77+
internal static extern bool GetThreadIOPendingFlag(nint hThread, out BOOL lpIOIsPending);
7478
}
7579
}

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,9 @@
16841684
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SystemTimeToFileTime.cs">
16851685
<Link>Common\Interop\Windows\Kernel32\Interop.SystemTimeToFileTime.cs</Link>
16861686
</Compile>
1687+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.Threading.cs">
1688+
<Link>Common\Interop\Windows\Kernel32\Interop.Threading.cs</Link>
1689+
</Compile>
16871690
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.TimeZone.cs">
16881691
<Link>Common\Interop\Windows\Kernel32\Interop.TimeZone.cs</Link>
16891692
</Compile>
@@ -2268,8 +2271,8 @@
22682271
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.WaitThread.cs" />
22692272
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.WorkerThread.cs" />
22702273
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.WorkerTracking.cs" />
2271-
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.CpuUtilizationReader.Unix.cs" Condition="'$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true'" />
2272-
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.CpuUtilizationReader.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
2274+
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.Unix.cs" Condition="'$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true'" />
2275+
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
22732276
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LowLevelLifoSemaphore.cs" />
22742277
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LowLevelLifoSemaphore.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
22752278
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\RegisteredWaitHandle.Portable.cs" />
@@ -2301,9 +2304,6 @@
23012304
<ItemGroup Condition="'$(FeatureCoreCLR)' != 'true' and '$(TargetsWindows)' == 'true'">
23022305
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Thread.Windows.cs" />
23032306
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitHandle.Windows.cs" />
2304-
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.Threading.cs">
2305-
<Link>Interop\Windows\Kernel32\Interop.Threading.cs</Link>
2306-
</Compile>
23072307
</ItemGroup>
23082308
<ItemGroup Condition="'$(FeatureGenericMath)' == 'true'">
23092309
<Compile Include="$(MSBuildThisFileDirectory)System\IAdditionOperators.cs" />
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ namespace System.Threading
55
{
66
internal sealed partial class PortableThreadPool
77
{
8+
private static partial class WorkerThread
9+
{
10+
private static bool IsIOPending => false;
11+
}
12+
813
private struct CpuUtilizationReader
914
{
1015
private Interop.Sys.ProcessCpuInformation _cpuInfo;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ namespace System.Threading
88
{
99
internal sealed partial class PortableThreadPool
1010
{
11+
private static partial class WorkerThread
12+
{
13+
private static bool IsIOPending
14+
{
15+
get
16+
{
17+
bool success =
18+
Interop.Kernel32.GetThreadIOPendingFlag(Interop.Kernel32.GetCurrentThread(), out Interop.BOOL isIOPending);
19+
Debug.Assert(success);
20+
return !success || isIOPending != Interop.BOOL.FALSE;
21+
}
22+
}
23+
}
24+
1125
private struct CpuUtilizationReader
1226
{
1327
public long _idleTime;

src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal sealed partial class PortableThreadPool
1010
/// <summary>
1111
/// The worker thread infastructure for the CLR thread pool.
1212
/// </summary>
13-
private static class WorkerThread
13+
private static partial class WorkerThread
1414
{
1515
// This value represents an assumption of how much uncommited stack space a worker thread may use in the future.
1616
// 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()
101101
}
102102
}
103103

104+
// The thread cannot exit if it has IO pending, otherwise the IO may be canceled
105+
if (IsIOPending)
106+
{
107+
continue;
108+
}
109+
104110
threadAdjustmentLock.Acquire();
105111
try
106112
{

0 commit comments

Comments
 (0)