Skip to content

Commit dd3b61d

Browse files
authored
Add support for Windows IO completions to the portable thread pool (#64834)
* Add support for Windows IO completions to the portable thread pool - Added an implementation for BindHandle - Polling for IO completions is done in batches on separate threads similarly to what is done on Unixes - Added a high-priority work item queue to have IO completion work items run at higher priority - Removed the time-sensitive work item queue, used the high-priority queue instead
1 parent 9a104b6 commit dd3b61d

File tree

85 files changed

+1255
-816
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1255
-816
lines changed

src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,6 @@
232232
<Compile Include="$(BclSourcesRoot)\System\String.CoreCLR.cs" />
233233
<Compile Include="$(BclSourcesRoot)\System\StubHelpers.cs" />
234234
<Compile Include="$(BclSourcesRoot)\System\Text\StringBuilder.CoreCLR.cs" />
235-
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.cs" />
236-
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandleOverlapped.cs" />
237-
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolPreAllocatedOverlapped.cs" />
238235
<Compile Include="$(BclSourcesRoot)\System\Threading\Interlocked.CoreCLR.cs" />
239236
<Compile Include="$(BclSourcesRoot)\System\Threading\Monitor.CoreCLR.cs" />
240237
<Compile Include="$(BclSourcesRoot)\System\Threading\Overlapped.cs" />
@@ -289,14 +286,13 @@
289286
</ItemGroup>
290287
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
291288
<Compile Include="$(BclSourcesRoot)\Interop\Unix\Interop.Libraries.cs" />
292-
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Unix.cs" />
293289
<Compile Include="$(BclSourcesRoot)\System\Threading\LowLevelLifoSemaphore.Unix.cs" />
294290
</ItemGroup>
295291
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
296292
<Compile Include="$(CommonPath)Interop\Windows\OleAut32\Interop.VariantClear.cs">
297293
<Link>Common\Interop\Windows\OleAut32\Interop.VariantClear.cs</Link>
298294
</Compile>
299-
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Windows.cs" />
295+
<Compile Include="$(BclSourcesRoot)\System\Threading\ThreadPool.CoreCLR.Windows.cs" />
300296
</ItemGroup>
301297
<ItemGroup Condition="'$(FeatureObjCMarshal)' == 'true'">
302298
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ObjectiveCMarshal.CoreCLR.cs" />

src/coreclr/System.Private.CoreLib/src/System/Threading/Overlapped.cs

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,8 @@ namespace System.Threading
2727
{
2828
#region class _IOCompletionCallback
2929

30-
internal unsafe class _IOCompletionCallback
30+
internal unsafe partial class _IOCompletionCallback
3131
{
32-
private readonly IOCompletionCallback _ioCompletionCallback;
33-
private readonly ExecutionContext _executionContext;
34-
private uint _errorCode; // Error code
35-
private uint _numBytes; // No. of bytes transferred
36-
private NativeOverlapped* _pNativeOverlapped;
37-
38-
internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback, ExecutionContext executionContext)
39-
{
40-
_ioCompletionCallback = ioCompletionCallback;
41-
_executionContext = executionContext;
42-
}
43-
// Context callback: same sig for SendOrPostCallback and ContextCallback
44-
internal static ContextCallback _ccb = new ContextCallback(IOCompletionCallback_Context);
45-
internal static void IOCompletionCallback_Context(object? state)
46-
{
47-
_IOCompletionCallback? helper = (_IOCompletionCallback?)state;
48-
Debug.Assert(helper != null, "_IOCompletionCallback cannot be null");
49-
helper._ioCompletionCallback(helper._errorCode, helper._numBytes, helper._pNativeOverlapped);
50-
}
51-
5232
// call back helper
5333
internal static void PerformIOCompletionCallback(uint errorCode, uint numBytes, NativeOverlapped* pNativeOverlapped)
5434
{
@@ -69,7 +49,7 @@ internal static void PerformIOCompletionCallback(uint errorCode, uint numBytes,
6949
helper._errorCode = errorCode;
7050
helper._numBytes = numBytes;
7151
helper._pNativeOverlapped = pNativeOverlapped;
72-
ExecutionContext.RunInternal(helper._executionContext, _ccb, helper);
52+
ExecutionContext.RunInternal(helper._executionContext, IOCompletionCallback_Context_Delegate, helper);
7353
}
7454

7555
// Quickly check the VM again, to see if a packet has arrived.
@@ -132,8 +112,6 @@ internal sealed unsafe class OverlappedData
132112
return AllocateNativeOverlapped();
133113
}
134114

135-
internal bool IsUserObject(byte[]? buffer) => ReferenceEquals(_userObject, buffer);
136-
137115
[MethodImpl(MethodImplOptions.InternalCall)]
138116
private extern NativeOverlapped* AllocateNativeOverlapped();
139117

@@ -254,8 +232,6 @@ public static unsafe void Free(NativeOverlapped* nativeOverlappedPtr!!)
254232
OverlappedData.GetOverlappedFromNative(nativeOverlappedPtr)._overlapped._overlappedData = null;
255233
OverlappedData.FreeNativeOverlapped(nativeOverlappedPtr);
256234
}
257-
258-
internal bool IsUserObject(byte[]? buffer) => _overlappedData!.IsUserObject(buffer);
259235
}
260236

261237
#endregion class Overlapped
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
using System.Runtime.Versioning;
7+
8+
namespace System.Threading
9+
{
10+
public static partial class ThreadPool
11+
{
12+
[CLSCompliant(false)]
13+
[SupportedOSPlatform("windows")]
14+
public static unsafe bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped)
15+
{
16+
if (overlapped == null)
17+
{
18+
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.overlapped);
19+
}
20+
21+
if (UsePortableThreadPoolForIO)
22+
{
23+
// OS doesn't signal handle, so do it here
24+
overlapped->InternalLow = IntPtr.Zero;
25+
26+
PortableThreadPool.ThreadPoolInstance.QueueNativeOverlapped(overlapped);
27+
return true;
28+
}
29+
30+
return PostQueuedCompletionStatus(overlapped);
31+
}
32+
33+
[MethodImpl(MethodImplOptions.InternalCall)]
34+
private static extern unsafe bool PostQueuedCompletionStatus(NativeOverlapped* overlapped);
35+
36+
[Obsolete("ThreadPool.BindHandle(IntPtr) has been deprecated. Use ThreadPool.BindHandle(SafeHandle) instead.")]
37+
[SupportedOSPlatform("windows")]
38+
public static bool BindHandle(IntPtr osHandle)
39+
{
40+
if (UsePortableThreadPoolForIO)
41+
{
42+
PortableThreadPool.ThreadPoolInstance.RegisterForIOCompletionNotifications(osHandle);
43+
return true;
44+
}
45+
46+
return BindIOCompletionCallbackNative(osHandle);
47+
}
48+
49+
[SupportedOSPlatform("windows")]
50+
public static bool BindHandle(SafeHandle osHandle!!)
51+
{
52+
bool mustReleaseSafeHandle = false;
53+
try
54+
{
55+
osHandle.DangerousAddRef(ref mustReleaseSafeHandle);
56+
57+
if (UsePortableThreadPoolForIO)
58+
{
59+
PortableThreadPool.ThreadPoolInstance.RegisterForIOCompletionNotifications(osHandle.DangerousGetHandle());
60+
return true;
61+
}
62+
63+
return BindIOCompletionCallbackNative(osHandle.DangerousGetHandle());
64+
}
65+
finally
66+
{
67+
if (mustReleaseSafeHandle)
68+
osHandle.DangerousRelease();
69+
}
70+
}
71+
72+
[MethodImpl(MethodImplOptions.InternalCall)]
73+
private static extern bool BindIOCompletionCallbackNative(IntPtr fileHandle);
74+
}
75+
}

0 commit comments

Comments
 (0)