Skip to content

Commit

Permalink
Enable option to use the Windows ThreadPool (#85373)
Browse files Browse the repository at this point in the history
When running on Windows, enable an option to switch between the Portable thread pool and the Windows thread pool.

This change targets NativeAOT, CoreCLR, and Mono.

Windows threadpool remains as the default for NativeAOT on Windows. For any other case the Portable thread pool remains the default.

Tests with the Windows thread pool enabled were added to the System.Threading.Threadpool solution.

Trimming is enabled to remove the unused thread pool.
---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Koundinya Veluri <kouvel@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 15, 2023
1 parent 226e3ec commit 0a0fa13
Show file tree
Hide file tree
Showing 53 changed files with 2,207 additions and 1,413 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@
<Compile Include="$(CommonPath)Interop\Windows\OleAut32\Interop.VariantClear.cs">
<Link>Common\Interop\Windows\OleAut32\Interop.VariantClear.cs</Link>
</Compile>
<Compile Include="$(BclSourcesRoot)\System\Threading\ThreadPool.CoreCLR.Windows.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureObjCMarshal)' == 'true'">
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ObjectiveCMarshal.CoreCLR.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,17 +275,17 @@ private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
#else // FEATURE_COMINTEROP_APARTMENT_SUPPORT
private static bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
{
if (state != ApartmentState.Unknown)
{
if (state != ApartmentState.Unknown)
{
if (throwOnError)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop);
}

return false;
}
}

return true;
return true;
}
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

/*=============================================================================
Expand All @@ -18,30 +18,6 @@

namespace System.Threading
{
internal sealed partial class CompleteWaitThreadPoolWorkItem : IThreadPoolWorkItem
{
void IThreadPoolWorkItem.Execute() => CompleteWait();

// Entry point from unmanaged code
private void CompleteWait()
{
PortableThreadPool.CompleteWait(_registeredWaitHandle, _timedOut);
}
}

internal sealed class UnmanagedThreadPoolWorkItem : IThreadPoolWorkItem
{
private readonly IntPtr _callback;
private readonly IntPtr _state;

public UnmanagedThreadPoolWorkItem(IntPtr callback, IntPtr state)
{
_callback = callback;
_state = state;
}

unsafe void IThreadPoolWorkItem.Execute() => ((delegate* unmanaged<IntPtr, int>)_callback)(_state);
}

public static partial class ThreadPool
{
Expand All @@ -52,12 +28,6 @@ internal static bool EnsureConfigInitialized()

private static readonly bool s_initialized = InitializeConfig();

// Indicates whether the thread pool should yield the thread from the dispatch loop to the runtime periodically so that
// the runtime may use the thread for processing other work
internal static bool YieldFromDispatchLoop => false;

private static readonly bool IsWorkerTrackingEnabledInConfig = GetEnableWorkerTracking();

private static unsafe bool InitializeConfig()
{
int configVariableIndex = 1;
Expand Down Expand Up @@ -100,116 +70,5 @@ private static extern unsafe int GetNextConfigUInt32Value(
out bool isBoolean,
out char* appContextConfigName);

private static bool GetEnableWorkerTracking() =>
AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.EnableWorkerTracking", false);

public static bool SetMaxThreads(int workerThreads, int completionPortThreads)
{
return PortableThreadPool.ThreadPoolInstance.SetMaxThreads(workerThreads, completionPortThreads);
}

public static void GetMaxThreads(out int workerThreads, out int completionPortThreads)
{
PortableThreadPool.ThreadPoolInstance.GetMaxThreads(out workerThreads, out completionPortThreads);
}

public static bool SetMinThreads(int workerThreads, int completionPortThreads)
{
return PortableThreadPool.ThreadPoolInstance.SetMinThreads(workerThreads, completionPortThreads);
}

public static void GetMinThreads(out int workerThreads, out int completionPortThreads)
{
PortableThreadPool.ThreadPoolInstance.GetMinThreads(out workerThreads, out completionPortThreads);
}

public static void GetAvailableThreads(out int workerThreads, out int completionPortThreads)
{
PortableThreadPool.ThreadPoolInstance.GetAvailableThreads(out workerThreads, out completionPortThreads);
}

/// <summary>
/// Gets the number of thread pool threads that currently exist.
/// </summary>
/// <remarks>
/// For a thread pool implementation that may have different types of threads, the count includes all types.
/// </remarks>
public static int ThreadCount
{
get
{
return PortableThreadPool.ThreadPoolInstance.ThreadCount;
}
}

/// <summary>
/// Gets the number of work items that have been processed so far.
/// </summary>
/// <remarks>
/// For a thread pool implementation that may have different types of work items, the count includes all types.
/// </remarks>
public static long CompletedWorkItemCount
{
get
{
return PortableThreadPool.ThreadPoolInstance.CompletedWorkItemCount;
}
}

private static RegisteredWaitHandle RegisterWaitForSingleObject(
WaitHandle waitObject,
WaitOrTimerCallback callBack,
object? state,
uint millisecondsTimeOutInterval,
bool executeOnlyOnce,
bool flowExecutionContext)
{
ArgumentNullException.ThrowIfNull(waitObject);
ArgumentNullException.ThrowIfNull(callBack);

RegisteredWaitHandle registeredWaitHandle = new RegisteredWaitHandle(
waitObject,
new _ThreadPoolWaitOrTimerCallback(callBack, state, flowExecutionContext),
(int)millisecondsTimeOutInterval,
!executeOnlyOnce);

PortableThreadPool.ThreadPoolInstance.RegisterWaitHandle(registeredWaitHandle);

return registeredWaitHandle;
}

internal static void RequestWorkerThread()
{
PortableThreadPool.ThreadPoolInstance.RequestWorker();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool NotifyWorkItemComplete(object? threadLocalCompletionCountObject, int currentTimeMs)
{
return
PortableThreadPool.ThreadPoolInstance.NotifyWorkItemComplete(
threadLocalCompletionCountObject,
currentTimeMs);
}

internal static void ReportThreadStatus(bool isWorking)
{
PortableThreadPool.ThreadPoolInstance.ReportThreadStatus(isWorking);
}

internal static void NotifyWorkItemProgress()
{
PortableThreadPool.ThreadPoolInstance.NotifyWorkItemProgress();
}

internal static bool NotifyThreadBlocked() => PortableThreadPool.ThreadPoolInstance.NotifyThreadBlocked();

internal static void NotifyThreadUnblocked()
{
PortableThreadPool.ThreadPoolInstance.NotifyThreadUnblocked();
}

internal static object? GetOrCreateThreadLocalCompletionCountObject() =>
PortableThreadPool.ThreadPoolInstance.GetOrCreateThreadLocalCompletionCountObject();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<UseSystemResourceKeys Condition="$(IlcDisableReflection) == 'true'">true</UseSystemResourceKeys>
<EventSourceSupport Condition="$(IlcDisableReflection) == 'true'">false</EventSourceSupport>
<EventSourceSupport Condition="$(EventSourceSupport) == ''">false</EventSourceSupport>
<UseWindowsThreadPool Condition="'$(UseWindowsThreadPool)' == '' and '$(_targetOS)' == 'win'">true</UseWindowsThreadPool>
<DynamicCodeSupport Condition="'$(DynamicCodeSupport)' == ''">false</DynamicCodeSupport>
</PropertyGroup>

Expand Down Expand Up @@ -272,6 +273,7 @@ The .NET Foundation licenses this file to you under the MIT license.

<!-- The managed debugging support in libraries is unused - trim it -->
<IlcArg Condition="'$(IlcKeepManagedDebuggerSupport)' != 'true'" Include="--feature:System.Diagnostics.Debugger.IsSupported=false" />
<IlcArg Condition="'$(UseWindowsThreadPool)' != '' and '$(_targetOS)' == 'win'" Include="--feature:System.Threading.ThreadPool.UseWindowsThreadPool=$(UseWindowsThreadPool)" />
</ItemGroup>

<MakeDir Directories="$(NativeIntermediateOutputPath)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@
</PropertyGroup>

<PropertyGroup>
<FeaturePortableThreadPool Condition="'$(FeaturePortableThreadPool)' == ''">false</FeaturePortableThreadPool>
<FeaturePortableThreadPool Condition="'$(TargetsUnix)' == 'true'">true</FeaturePortableThreadPool>
<FeaturePortableThreadPool>true</FeaturePortableThreadPool>
</PropertyGroup>
<PropertyGroup>
<FeaturePortableTimer Condition="'$(FeaturePortableTimer)' == ''">false</FeaturePortableTimer>
<FeaturePortableTimer Condition="'$(TargetsUnix)' == 'true'">true</FeaturePortableTimer>
<FeaturePortableTimer>true</FeaturePortableTimer>
</PropertyGroup>
<PropertyGroup>
<FeatureHardwareIntrinsics>true</FeatureHardwareIntrinsics>
Expand Down Expand Up @@ -233,7 +231,6 @@
<Compile Include="System\Threading\ObjectHeader.cs" />
<Compile Include="System\Threading\SyncTable.cs" />
<Compile Include="System\Threading\Thread.NativeAot.cs" />
<Compile Include="System\Threading\ThreadPool.NativeAot.cs" />
<Compile Include="System\Type.NativeAot.cs" />
<Compile Include="System\Type.Internal.cs" />
<Compile Include="System\TypedReference.cs" />
Expand All @@ -251,7 +248,6 @@
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)'=='true'">
<Compile Include="Microsoft\Win32\SafeHandles\SafeThreadPoolIOHandle.cs" />
<Compile Include="System\Runtime\InteropServices\NativeLibrary.NativeAot.Windows.cs" />
<Compile Include="System\Runtime\InteropServices\PInvokeMarshal.Windows.cs" />
<Compile Include="$(CommonPath)\System\Runtime\InteropServices\Variant.cs">
Expand Down Expand Up @@ -282,29 +278,13 @@
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.GetTickCount64.cs">
<Link>Interop\Windows\Kernel32\Interop.GetTickCount64.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.ThreadPool.cs">
<Link>Interop\Windows\Kernel32\Interop.ThreadPool.cs</Link>
</Compile>
<Compile Include="System\Threading\Timer.Windows.cs" Condition="'$(FeaturePortableTimer)' != 'true'" />
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.Timer.cs">
<Link>Interop\Windows\Kernel32\Interop.Timer.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.DynamicLoad.cs">
<Link>Interop\Windows\Kernel32\Interop.DynamicLoad.cs</Link>
</Compile>
<Compile Include="System\Threading\Thread.NativeAot.Windows.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.ThreadPoolIO.cs">
<Link>Interop\Windows\Kernel32\Interop.ThreadPoolIO.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)'=='true' and '$(FeaturePortableThreadPool)' != 'true'">
<Compile Include="System\Threading\ThreadPool.Windows.cs" />
<Compile Include="System\Threading\ThreadPoolCallbackWrapper.cs" />
<Compile Include="System\Threading\Win32ThreadPoolBoundHandle.cs" />
<Compile Include="System\Threading\Win32ThreadPoolNativeOverlapped.cs" />
<Compile Include="System\Threading\Win32ThreadPoolNativeOverlapped.ExecutionContextCallbackArgs.cs" />
<Compile Include="System\Threading\Win32ThreadPoolNativeOverlapped.OverlappedData.cs" />
<Compile Include="System\Threading\Win32ThreadPoolPreAllocatedOverlapped.cs" />
<ItemGroup Condition="'$(TargetsWindows)'=='true'">
<Compile Include="System\Threading\ThreadPoolCallbackWrapper.NativeAot.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)'=='true'">
<Compile Include="System\Environment.NativeAot.Unix.cs" />
Expand Down

This file was deleted.

Loading

0 comments on commit 0a0fa13

Please sign in to comment.