Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threadpool autorelease #47592

Merged
merged 23 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
aee6785
Add test for ThreadPool autorelease without enable.
jkoritzinsky Jan 26, 2021
a6b59df
Fix prototypes.
jkoritzinsky Feb 2, 2021
b0938eb
Always include Interop.AutoreleasePool.cs for build simplicity.
jkoritzinsky Feb 2, 2021
ed44c1e
PR Feedback.
jkoritzinsky Feb 2, 2021
d15f47b
Comment why Interop.AutoreleasePool.cs is included unconditionally an…
jkoritzinsky Feb 2, 2021
284a865
Update Interop.AutoreleasePool.cs
jkoritzinsky Feb 2, 2021
43bd530
Refactor out the AutoreleasePool impl to only exist on osx-like platf…
jkoritzinsky Feb 2, 2021
c4ab7e7
Disable -Wmissing-noreturn on Clang and GCC.
jkoritzinsky Feb 2, 2021
5671fa8
Make feature flag a property.
jkoritzinsky Feb 2, 2021
c7e2934
Fix typo
jkoritzinsky Feb 2, 2021
eb2e39d
Fix missing using
jkoritzinsky Feb 2, 2021
d6bab12
Reorganize to try to get WASM building.
jkoritzinsky Feb 3, 2021
9bd2af5
Use get-only property with initializer.
jkoritzinsky Feb 3, 2021
be9d6df
Add API to wasm threadpool impl.
jkoritzinsky Feb 3, 2021
1c85528
Use feature flag for all platforms, not just macos.
jkoritzinsky Feb 3, 2021
b6053fd
Merge branch 'master' of github.com:dotnet/runtime into threadpool-au…
jkoritzinsky Feb 5, 2021
c9eea84
Make EnableDispatchAutoreleasePool a property on all targets.
jkoritzinsky Feb 5, 2021
c803877
Use a preprocessor if instead of a runtime if with the OS APIs.
jkoritzinsky Feb 8, 2021
483db22
Merge branch 'master' of github.com:dotnet/runtime into threadpool-au…
jkoritzinsky Feb 8, 2021
f6c9313
Merge branch 'master' into threadpool-autorelease
jkoritzinsky Feb 9, 2021
bb19d85
Merge branch 'master' into threadpool-autorelease
jkoritzinsky Feb 12, 2021
a46dd70
Move EnableDispatchAutoreleasePool definition to be local to the Disp…
jkoritzinsky Feb 19, 2021
0fe7547
Merge branch 'threadpool-autorelease' of github.com:jkoritzinsky/runt…
jkoritzinsky Feb 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/workflow/trimming/feature-switches.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ configurations but their defaults might vary as any SDK can set the defaults dif
| UseSystemResourceKeys | System.Resources.UseSystemResourceKeys | Any localizable resources for system assemblies is trimmed when set to true |
| HttpActivityPropagationSupport | System.Net.Http.EnableActivityPropagation | Any dependency related to diagnostics support for System.Net.Http is trimmed when set to false |
| StartupHookSupport | System.StartupHookProvider.IsSupported | Startup hooks are disabled when set to false. Startup hook related functionality can be trimmed. |
| TBD | System.Threading.ThreadPool.EnableDispatchAutoreleasePool | When set to true, creates an NSAutoreleasePool around each thread pool work item on applicable platforms. |
| CustomResourceTypesSupport | System.Resources.ResourceManager.AllowCustomResourceTypes | Use of custom resource types is disabled when set to false. ResourceManager code paths that use reflection for custom types can be trimmed. |

Any feature-switch which defines property can be set in csproj file or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable enable
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_CreateAutoreleasePool")]
internal static extern IntPtr CreateAutoreleasePool();

[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_DrainAutoreleasePool")]
internal static extern void DrainAutoreleasePool(IntPtr ptr);
}
}
11 changes: 9 additions & 2 deletions src/libraries/Native/Unix/System.Native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,26 @@ set(NATIVE_SOURCES
pal_sysctl.c
)

if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
list (APPEND NATIVE_SOURCES pal_autoreleasepool.m)
set_source_files_properties(pal_autoreleasepool.m PROPERTIES COMPILE_FLAGS -fno-objc-arc)
else()
list (APPEND NATIVE_SOURCES pal_autoreleasepool.c)
endif()

if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
set(NATIVE_SOURCES ${NATIVE_SOURCES}
pal_log.m
pal_searchpath.m)
else ()
set(NATIVE_SOURCES ${NATIVE_SOURCES}
list (APPEND NATIVE_SOURCES
pal_searchpath.c
pal_console.c
pal_log.c)
endif ()

if (NOT CLR_CMAKE_TARGET_BROWSER)
set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_networkchange.c)
list (APPEND NATIVE_SOURCES pal_networkchange.c)
endif ()

include(${CMAKE_CURRENT_LIST_DIR}/extra_libs.cmake)
Expand Down
3 changes: 3 additions & 0 deletions src/libraries/Native/Unix/System.Native/entrypoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../../AnyOS/entrypoints.h"

// Include System.Native headers
#include "pal_autoreleasepool.h"
#include "pal_console.h"
#include "pal_datetime.h"
#include "pal_errno.h"
Expand Down Expand Up @@ -236,6 +237,8 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_GetGroupList)
DllImportEntry(SystemNative_GetUid)
DllImportEntry(SystemNative_LowLevelMonitor_Create)
DllImportEntry(SystemNative_CreateAutoreleasePool)
DllImportEntry(SystemNative_DrainAutoreleasePool)
};

EXTERN_C const void* SystemResolveDllImport(const char* name);
Expand Down
10 changes: 6 additions & 4 deletions src/libraries/Native/Unix/System.Native/extra_libs.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

macro(append_extra_system_libs NativeLibsExtra)
macro(append_extra_system_libs NativeLibsExtra)
if (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_ANDROID)
list(APPEND ${NativeLibsExtra} rt)
elseif (CLR_CMAKE_TARGET_FREEBSD)
Expand All @@ -9,9 +9,11 @@ macro(append_extra_system_libs NativeLibsExtra)
elseif (CLR_CMAKE_TARGET_SUNOS)
list(APPEND ${NativeLibsExtra} socket)
endif ()

if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
list(APPEND ${NativeLibsExtra} "-framework Foundation")

if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
include(CMakeFindFrameworks)
find_library(FOUNDATION Foundation REQUIRED)
list(APPEND ${NativeLibsExtra} ${FOUNDATION})
endif ()

if (CLR_CMAKE_TARGET_LINUX AND HAVE_GETADDRINFO_A)
Expand Down
26 changes: 26 additions & 0 deletions src/libraries/Native/Unix/System.Native/pal_autoreleasepool.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "pal_autoreleasepool.h"
#include <stdlib.h>
#include "pal_utilities.h"

#ifndef _MSC_VER
// Don't warning about not declaring a function with [[noreturn]] since it's only true in Debug mode.
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#endif

// These functions should not be used, but they need to be defined
// to satisfy the tooling we used to enable redirecting P/Invokes
// for the single file scenario.
void* SystemNative_CreateAutoreleasePool(void)
{
assert_err(false, "Autorelease pools not supported on this platform.", EINVAL);
return NULL;
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
}

void SystemNative_DrainAutoreleasePool(void* pool)
{
(void)pool;
assert_err(false, "Autorelease pools not supported on this platform.", EINVAL);
}
17 changes: 17 additions & 0 deletions src/libraries/Native/Unix/System.Native/pal_autoreleasepool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma once

#include "pal_compiler.h"
#include "pal_types.h"

/**
* Creates an pool to automatically release applicable ref-counted resources.
*/
PALEXPORT void* SystemNative_CreateAutoreleasePool(void);

/**
* Drains and releases a pool created by SystemNative_CreateAutoreleasePool.
*/
PALEXPORT void SystemNative_DrainAutoreleasePool(void* pool);
40 changes: 40 additions & 0 deletions src/libraries/Native/Unix/System.Native/pal_autoreleasepool.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "pal_autoreleasepool.h"
#include <Foundation/Foundation.h>

@interface PlaceholderObject : NSObject
- (void)noop:(id)_;
@end

@implementation PlaceholderObject : NSObject
- (void)noop:(id)_
{
[self release];
}
@end

void* SystemNative_CreateAutoreleasePool(void)
{
if (![NSThread isMultiThreaded])
{
// Start another no-op thread with the NSThread APIs to get NSThread into multithreaded mode.
// The NSAutoReleasePool APIs can't be used on secondary threads until NSThread is in multithreaded mode.
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
// See https://developer.apple.com/documentation/foundation/nsautoreleasepool for more information.
PlaceholderObject* placeholderObject = [[PlaceholderObject alloc] init];

// We need to use detachNewThreadSelector to put NSThread into multithreaded mode.
// We can't use detachNewThreadWithBlock since it doesn't change NSThread into multithreaded mode for some reason.
// See https://developer.apple.com/documentation/foundation/nswillbecomemultithreadednotification for more information.
[NSThread detachNewThreadSelector:@selector(noop:) toTarget:placeholderObject withObject:nil];
}
assert([NSThread isMultiThreaded]);

return [[NSAutoreleasePool alloc] init];
}

void SystemNative_DrainAutoreleasePool(void* pool)
{
[((NSAutoreleasePool*)pool) drain];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<linker>
<assembly fullname="System.Private.CoreLib">
<type fullname="System.Threading.ThreadPool" feature="System.Threading.ThreadPool.EnableDispatchAutoreleasePool" featurevalue="false">
<method signature="System.Boolean get_EnableDispatchAutoreleasePool()" body="stub" value="false" />
</type>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<ILLinkSubstitutionsXmls Include="$(ILLinkSharedDirectory)ILLink.Substitutions.64bit.xml" Condition="'$(Is64Bit)' == 'true'" />
<ILLinkSubstitutionsXmls Include="$(ILLinkSharedDirectory)ILLink.Substitutions.NoArmIntrinsics.xml" Condition="'$(SupportsArmIntrinsics)' != 'true'" />
<ILLinkSubstitutionsXmls Include="$(ILLinkSharedDirectory)ILLink.Substitutions.NoX86Intrinsics.xml" Condition="'$(SupportsX86Intrinsics)' != 'true'" />
<ILLinkSubstitutionsXmls Include="$(ILLinkSharedDirectory)ILLink.Substitutions.OSX.xml" Condition="'$(IsOSXLike)' == 'true'" />
<ILLinkLinkAttributesXmls Include="$(ILLinkSharedDirectory)ILLink.LinkAttributes.Shared.xml" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -1017,7 +1018,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadInt64PersistentCounter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadInterruptedException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadLocal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPoolWorkQueue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPriority.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadStart.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadStartException.cs" />
Expand Down Expand Up @@ -1877,6 +1878,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.OSX.cs" Condition="'$(IsOSXLike)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.OSVersion.Unix.cs" Condition="'$(IsOSXLike)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.SunOS.cs" Condition="'$(Targetsillumos)' == 'true' or '$(TargetsSolaris)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPoolWorkQueue.AutoreleasePool.OSX.cs" Condition="'$(IsOSXLike)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.GetDisplayName.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PersistedFiles.Unix.cs" />
Expand All @@ -1895,6 +1897,8 @@
<Compile Include="$(CommonPath)Interop\OSX\Interop.Libraries.cs">
<Link>Common\Interop\OSX\Interop.Libraries.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\OSX\System.Native\Interop.AutoreleasePool.cs"
Link="Common\Interop\OSX\System.Native\Interop.AutoreleasePool.cs" />
</ItemGroup>
<ItemGroup Condition="'$(SupportsX86Intrinsics)' == 'true'">
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\X86\Aes.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.Versioning;

namespace System.Threading
{
public static partial class ThreadPool
{
internal static bool EnableDispatchAutoreleasePool { get; } =
AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.EnableDispatchAutoreleasePool", false);
}

internal sealed partial class ThreadPoolWorkQueue
{
[MethodImpl(MethodImplOptions.NoInlining)]
private static void DispatchItemWithAutoreleasePool(object workItem, Thread currentThread)
{
IntPtr autoreleasePool = Interop.Sys.CreateAutoreleasePool();
try
{
#pragma warning disable CS0162 // Unreachable code detected. EnableWorkerTracking may be a constant in some runtimes.
if (ThreadPool.EnableWorkerTracking)
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
{
DispatchWorkItemWithWorkerTracking(workItem, currentThread);
}
else
{
DispatchWorkItem(workItem, currentThread);
}
#pragma warning restore CS0162
}
finally
{
Interop.Sys.DrainAutoreleasePool(autoreleasePool);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

namespace System.Threading
{
internal sealed class ThreadPoolWorkQueue
internal sealed partial class ThreadPoolWorkQueue
{
internal static class WorkStealingQueueList
{
Expand Down Expand Up @@ -691,23 +691,21 @@ internal static bool Dispatch()
//
// Execute the workitem outside of any finally blocks, so that it can be aborted if needed.
//
#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
if (ThreadPool.EnableDispatchAutoreleasePool)
{
DispatchItemWithAutoreleasePool(workItem, currentThread);
}
else
#endif
#pragma warning disable CS0162 // Unreachable code detected. EnableWorkerTracking may be a constant in some runtimes.
if (ThreadPool.EnableWorkerTracking)
{
DispatchWorkItemWithWorkerTracking(workItem, currentThread);
}
else if (workItem is Task task)
{
// Check for Task first as it's currently faster to type check
// for Task and then Unsafe.As for the interface, rather than
// vice versa, in particular when the object implements a bunch
// of interfaces.
task.ExecuteFromThreadPool(currentThread);
}
else
{
Debug.Assert(workItem is IThreadPoolWorkItem);
Unsafe.As<IThreadPoolWorkItem>(workItem).Execute();
DispatchWorkItem(workItem, currentThread);
}
#pragma warning restore CS0162

Expand Down Expand Up @@ -781,22 +779,28 @@ private static void DispatchWorkItemWithWorkerTracking(object workItem, Thread c
{
ThreadPool.ReportThreadStatus(isWorking: true);
reportedStatus = true;
if (workItem is Task task)
{
task.ExecuteFromThreadPool(currentThread);
}
else
{
Debug.Assert(workItem is IThreadPoolWorkItem);
Unsafe.As<IThreadPoolWorkItem>(workItem).Execute();
}
DispatchWorkItem(workItem, currentThread);
}
finally
{
if (reportedStatus)
ThreadPool.ReportThreadStatus(isWorking: false);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void DispatchWorkItem(object workItem, Thread currentThread)
{
if (workItem is Task task)
{
task.ExecuteFromThreadPool(currentThread);
}
else
{
Debug.Assert(workItem is IThreadPoolWorkItem);
Unsafe.As<IThreadPoolWorkItem>(workItem).Execute();
}
}
}

// Holds a WorkStealingQueue, and removes it from the list when this object is no longer referenced.
Expand Down
7 changes: 7 additions & 0 deletions src/tests/Common/Platform/platformdefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,14 @@ typedef HANDLE THREAD_ID;

typedef char16_t WCHAR;
typedef unsigned int DWORD;

#ifdef OBJC_TESTS
// The Objective-C headers define the BOOL type to be unsigned char or bool.
// As a result, we can't redefine it here. So instead, define WINBOOL to be int-sized.
typedef int WINBOOL;
#else
typedef int BOOL;
#endif
typedef WCHAR *LPWSTR, *PWSTR;
typedef const WCHAR *LPCWSTR, *PCWSTR;

Expand Down
4 changes: 4 additions & 0 deletions src/tests/Interop/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,7 @@ if(CLR_CMAKE_TARGET_WIN32)
add_subdirectory(IJW/NativeVarargs)
endif()
endif(CLR_CMAKE_TARGET_WIN32)

if(CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
add_subdirectory(ObjectiveC)
endif()
Loading