Skip to content

Commit 00f1d43

Browse files
jkoritzinskyam11jkotas
authored
Port the Shared Mutex logic from CoreCLR PAL to work alongside the managed wait subsystem (#117635)
Co-authored-by: Adeel Mujahid <[email protected]> Co-authored-by: Jan Kotas <[email protected]>
1 parent 0e9ec23 commit 00f1d43

32 files changed

+2112
-92
lines changed

src/coreclr/nativeaot/Runtime/FinalizerHelpers.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,9 @@ FCIMPL0(OBJECTREF, RhpGetNextFinalizableObject)
262262
}
263263
}
264264
FCIMPLEND
265+
266+
FCIMPL0(FC_BOOL_RET, RhpCurrentThreadIsFinalizerThread)
267+
{
268+
FC_RETURN_BOOL(ThreadStore::GetCurrentThread() == g_pFinalizerThread);
269+
}
270+
FCIMPLEND

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,9 @@
303303
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Exit.cs">
304304
<Link>Interop\Unix\System.Native\Interop.Exit.cs</Link>
305305
</Compile>
306-
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.MMap.cs">
307-
<Link>Interop\Unix\System.Native\Interop.MMap.cs</Link>
308-
</Compile>
309306
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.MProtect.cs">
310307
<Link>Interop\Unix\System.Native\Interop.MProtect.cs</Link>
311308
</Compile>
312-
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.MUnmap.cs">
313-
<Link>Interop\Unix\System.Native\Interop.MUnmap.cs</Link>
314-
</Compile>
315309
</ItemGroup>
316310
<ItemGroup>
317311
<Compile Include="$(CompilerCommonPath)\System\Collections\Generic\ArrayBuilder.cs">

src/coreclr/vm/comsynchronizable.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,3 +899,11 @@ extern "C" void QCALLTYPE ThreadNative_ResetAbort()
899899
pThread->UnmarkThreadForAbort(EEPolicy::TA_Safe);
900900
}
901901
}
902+
903+
FCIMPL0(FC_BOOL_RET, ThreadNative::CurrentThreadIsFinalizerThread)
904+
{
905+
FCALL_CONTRACT;
906+
907+
FC_RETURN_BOOL(IsFinalizerThread());
908+
}
909+
FCIMPLEND

src/coreclr/vm/comsynchronizable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class ThreadNative
4242
static FCDECL0(INT32, GetOptimalMaxSpinWaitsPerSpinIteration);
4343
static FCDECL1(void, Finalize, ThreadBaseObject* pThis);
4444
static FCDECL0(FC_BOOL_RET, CatchAtSafePoint);
45+
static FCDECL0(FC_BOOL_RET, CurrentThreadIsFinalizerThread);
4546
};
4647

4748
extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, BOOL isThreadPool, PCWSTR pThreadName);

src/coreclr/vm/ecalllist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ FCFuncEnd()
248248
FCFuncStart(gThreadFuncs)
249249
FCFuncElement("InternalFinalize", ThreadNative::Finalize)
250250
FCFuncElement("CatchAtSafePoint", ThreadNative::CatchAtSafePoint)
251+
FCFuncElement("CurrentThreadIsFinalizerThread", ThreadNative::CurrentThreadIsFinalizerThread)
251252
FCFuncElement("get_OptimalMaxSpinWaitsPerSpinIteration", ThreadNative::GetOptimalMaxSpinWaitsPerSpinIteration)
252253
FCFuncEnd()
253254

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static unsafe partial class Sys
9+
{
10+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_Init", SetLastError = true)]
11+
internal static partial int LowLevelCrossProcessMutex_Init(void* mutex);
12+
13+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_Acquire", SetLastError = true)]
14+
internal static partial int LowLevelCrossProcessMutex_Acquire(void* mutex, int timeoutMilliseconds);
15+
16+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_Release", SetLastError = true)]
17+
internal static partial int LowLevelCrossProcessMutex_Release(void* mutex);
18+
19+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_Destroy", SetLastError = true)]
20+
internal static partial int LowLevelCrossProcessMutex_Destroy(void* mutex);
21+
22+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_Size")]
23+
[SuppressGCTransition]
24+
internal static partial int LowLevelCrossProcessMutex_Size();
25+
26+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_GetOwnerProcessAndThreadId", SetLastError = true)]
27+
[SuppressGCTransition]
28+
internal static partial void LowLevelCrossProcessMutex_GetOwnerProcessAndThreadId(void* mutex, out uint processId, out uint threadId);
29+
30+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_SetOwnerProcessAndThreadId", SetLastError = true)]
31+
[SuppressGCTransition]
32+
internal static partial void LowLevelCrossProcessMutex_SetOwnerProcessAndThreadId(void* mutex, uint processId, uint threadId);
33+
34+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_IsAbandoned", SetLastError = true)]
35+
[SuppressGCTransition]
36+
[return: MarshalAs(UnmanagedType.U1)]
37+
internal static partial bool LowLevelCrossProcessMutex_IsAbandoned(void* mutex);
38+
39+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelCrossProcessMutex_SetAbandoned", SetLastError = true)]
40+
[SuppressGCTransition]
41+
internal static partial void LowLevelCrossProcessMutex_SetAbandoned(void* mutex, [MarshalAs(UnmanagedType.U1)] bool abandoned);
42+
}
43+
}

src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public static partial class PlatformDetection
3535
public static bool IsNotMonoAOT => Environment.GetEnvironmentVariable("MONO_AOT_MODE") != "aot";
3636
public static bool IsNativeAot => IsNotMonoRuntime && !IsReflectionEmitSupported;
3737
public static bool IsNotNativeAot => !IsNativeAot;
38+
public static bool IsCoreCLR => IsNotMonoRuntime && IsNotNativeAot;
3839
public static bool IsFreeBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"));
3940
public static bool IsNetBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"));
4041
public static bool IsAndroid => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID"));

src/libraries/System.Private.CoreLib/src/Resources/Strings.resx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4387,5 +4387,34 @@
43874387
</data>
43884388
<data name="PlatformNotSupported_DynamicEntrypoint" xml:space="preserve">
43894389
<value>Dynamic entrypoint allocation is not supported in the current environment.</value>
4390+
</data> <data name="Arg_InvalidOperationException_CannotReleaseUnownedMutex" xml:space="preserve">
4391+
<value>Cannot release a lock that is not owned by the current thread.</value>
4392+
</data>
4393+
<data name="Arg_FailedToInitializePThreadMutex" xml:space="preserve">
4394+
<value>Failed to initialize pthread mutex</value>
4395+
</data>
4396+
<data name="IO_SharedMemory_InvalidHeader" xml:space="preserve">
4397+
<value>Cross-process shared memory file '{0}' has a header that is not supported by this version of the .NET runtime.</value>
4398+
</data>
4399+
<data name="IO_SharedMemory_FileNotOwnedByUid" xml:space="preserve">
4400+
<value>The file '{0}' is not owned by the current user with UID {1}.</value>
4401+
</data>
4402+
<data name="IO_SharedMemory_FilePermissionsIncorrect" xml:space="preserve">
4403+
<value>The file '{0}' does not have the expected permissions for user scope: {1}.</value>
4404+
</data>
4405+
<data name="IO_SharedMemory_PathExistsButNotDirectory" xml:space="preserve">
4406+
<value>The path '{0}' exists but is not a directory.</value>
4407+
</data>
4408+
<data name="IO_SharedMemory_DirectoryPermissionsIncorrect" xml:space="preserve">
4409+
<value>The directory '{0}' does not have the expected owner or permissions for system scope: {1}, {2}.</value>
4410+
</data>
4411+
<data name="IO_SharedMemory_DirectoryNotOwnedByUid" xml:space="preserve">
4412+
<value>The directory '{0}' is not owned by the current user with UID {1}.</value>
4413+
</data>
4414+
<data name="IO_SharedMemory_DirectoryPermissionsIncorrectUserScope" xml:space="preserve">
4415+
<value>The directory '{0}' does not have the expected permissions for user scope: {1}.</value>
4416+
</data>
4417+
<data name="IO_SharedMemory_DirectoryOwnerPermissionsIncorrect" xml:space="preserve">
4418+
<value>The directory '{0}' does not have the expected owner permissions: {1}.</value>
43904419
</data>
43914420
</root>

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<Is64Bit Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'x64' or '$(Platform)' == 's390x' or '$(Platform)' == 'loongarch64' or '$(Platform)' == 'ppc64le' or '$(Platform)' == 'riscv64'">true</Is64Bit>
2525
<UseMinimalGlobalizationData Condition="'$(TargetsBrowser)' == 'true' or '$(TargetsWasi)' == 'true'">true</UseMinimalGlobalizationData>
2626
<EnableLibraryImportGenerator>true</EnableLibraryImportGenerator>
27+
<FeatureCrossProcessMutex Condition="'$(IsMobileLike)' != 'true'">true</FeatureCrossProcessMutex>
2728
</PropertyGroup>
2829
<PropertyGroup>
2930
<DefineConstants Condition="'$(IsBigEndian)' == 'true'">$(DefineConstants);BIGENDIAN</DefineConstants>
@@ -49,6 +50,9 @@
4950
<DefineConstants Condition="'$(TargetsSolaris)' == 'true'">$(DefineConstants);TARGET_SOLARIS</DefineConstants>
5051
<DefineConstants Condition="'$(TargetsHaiku)' == 'true'">$(DefineConstants);TARGET_HAIKU</DefineConstants>
5152
</PropertyGroup>
53+
<PropertyGroup>
54+
<DefineConstants Condition="'$(FeatureCrossProcessMutex)' == 'true'">$(DefineConstants);FEATURE_CROSS_PROCESS_MUTEX</DefineConstants>
55+
</PropertyGroup>
5256
<ItemGroup>
5357
<ApiCompatSuppressionFile Include="$(MSBuildThisFileDirectory)CompatibilitySuppressions.xml" />
5458
</ItemGroup>
@@ -2463,6 +2467,12 @@
24632467
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.MksTemps.cs">
24642468
<Link>Common\Interop\Unix\System.Native\Interop.MksTemps.cs</Link>
24652469
</Compile>
2470+
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.MMap.cs">
2471+
<Link>Common\Interop\Unix\System.Native\Interop.MMap.cs</Link>
2472+
</Compile>
2473+
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.MUnmap.cs">
2474+
<Link>Common\Interop\Unix\System.Native\Interop.MUnmap.cs</Link>
2475+
</Compile>
24662476
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.MountPoints.cs">
24672477
<Link>Common\Interop\Unix\System.Native\Interop.MountPoints.cs</Link>
24682478
</Compile>
@@ -2622,6 +2632,9 @@
26222632
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetPid.cs">
26232633
<Link>Common\Interop\Unix\System.Native\Interop.GetPid.cs</Link>
26242634
</Compile>
2635+
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetSid.cs">
2636+
<Link>Common\Interop\Unix\System.Native\Interop.GetSid.cs</Link>
2637+
</Compile>
26252638
<Compile Include="$(CommonPath)Interop\FreeBSD\Interop.Process.GetProcInfo.cs" Condition="'$(TargetsFreeBSD)' == 'true'" Link="Common\Interop\FreeBSD\Interop.Process.GetProcInfo.cs" />
26262639
<Compile Include="$(CommonPath)Interop\BSD\System.Native\Interop.Sysctl.cs" Condition="'$(TargetsFreeBSD)' == 'true'" Link="Common\Interop\BSD\System.Native\Interop.Sysctl.cs" />
26272640
<Compile Include="$(CommonPath)Interop\Linux\procfs\Interop.ProcFsStat.TryReadStatusFile.cs" Condition="'$(TargetsLinux)' == 'true'" Link="Common\Interop\Linux\Interop.ProcFsStat.TryReadStatusFile.cs" />
@@ -2844,6 +2857,13 @@
28442857
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitSubsystem.Unix.cs" />
28452858
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitSubsystem.WaitableObject.Unix.cs" />
28462859
</ItemGroup>
2860+
<ItemGroup Condition="'$(FeatureCoreCLR)' != 'true' and '$(TargetsUnix)' == 'true' and '$(FeatureCrossProcessMutex)' == 'true'">
2861+
<Compile Include="$(MSBuildThisFileDirectory)System\IO\SharedMemoryManager.Unix.cs" />
2862+
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\NamedMutex.Unix.cs" />
2863+
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.LowLevelCrossProcessMutex.cs">
2864+
<Link>Common\Interop\Unix\System.Native\Interop.LowLevelCrossProcessMutex.cs</Link>
2865+
</Compile>
2866+
</ItemGroup>
28472867
<ItemGroup Condition="'$(FeatureCoreCLR)' != 'true' and '$(TargetsWindows)' == 'true'">
28482868
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitHandle.Windows.cs" />
28492869
</ItemGroup>

src/libraries/System.Private.CoreLib/src/System/IO/PersistedFiles.Unix.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ private static void EnsureUserDirectories()
5757

5858
// In initialization conditions, however, the "HOME" environment variable may
5959
// not yet be set. For such cases, consult with the password entry.
60+
return GetHomeDirectoryFromPasswd();
61+
}
62+
63+
internal static string GetHomeDirectoryFromPasswd()
64+
{
6065
unsafe
6166
{
6267
// First try with a buffer that should suffice for 99% of cases.
@@ -66,8 +71,8 @@ private static void EnsureUserDirectories()
6671
// what to do.
6772
const int BufLen = Interop.Sys.Passwd.InitialBufferSize;
6873
byte* stackBuf = stackalloc byte[BufLen];
69-
if (TryGetHomeDirectoryFromPasswd(stackBuf, BufLen, out userHomeDirectory))
70-
return userHomeDirectory;
74+
if (TryGetHomeDirectoryFromPasswd(stackBuf, BufLen, out string? userHomeDirectory))
75+
return userHomeDirectory!;
7176

7277
// Fallback to heap allocations if necessary, growing the buffer until
7378
// we succeed. TryGetHomeDirectory will throw if there's an unexpected error.
@@ -79,7 +84,7 @@ private static void EnsureUserDirectories()
7984
fixed (byte* buf = &heapBuf[0])
8085
{
8186
if (TryGetHomeDirectoryFromPasswd(buf, heapBuf.Length, out userHomeDirectory))
82-
return userHomeDirectory;
87+
return userHomeDirectory!;
8388
}
8489
}
8590
}

0 commit comments

Comments
 (0)