Repository navigation
Fix Unix named mutex ownership recovery races - #136737
jkoritzinsky wants to merge 1 commit into
Conversation
Keep deferred pthread cleanup local and retire stale ownership before recording a new acquisition. Add native-thread regression coverage using shared interop declarations and runtime cleanup capability checks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 3 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @JulieLeeMSFT, @VSadov |
|
I think this will fix spurious "cannot release lock not owned by this thread" cases that I've seen locally with .NET 11 RC1 and .NET 11 RC2 sdks locally. Haven't been able to get a dump from those cases so it's difficult to figure out the exact race case that got hit. Copilot found these ones from source-inspection and they seem like reasonable candidates. |
|
honestly, I can't tell if this code is right. It's not obviously wrong, but it's not obviously right, either. |
| @@ -176,6 +176,9 @@ private static bool GetIsMultithreadingSupported() | |||
| public static bool IsWasmThreadingSupported => IsWasm && IsMultithreadingSupported; | |||
| public static bool IsNotWasmThreadingSupported => !IsWasmThreadingSupported; | |||
|
|
|||
| // Whether managed cleanup of externally created threads is deferred to the finalizer thread. | |||
| public static bool ManagedThreadCleanupOnFinalizerThread => IsCoreCLR || IsMonoRuntime; | |||
There was a problem hiding this comment.
This is a very corner-case condition. It may be better if it lives with the one test that uses it.
| private static bool IsRemoteExecutorAndPThreadNamedMutexSupported => | ||
| IsRemoteExecutorAndCrossProcessNamedMutexSupported && | ||
| PlatformDetection.ManagedThreadCleanupOnFinalizerThread && | ||
| RuntimeInformation.ProcessArchitecture is not (Architecture.Arm or Architecture.Arm64); |
There was a problem hiding this comment.
I am wondering whether it would be worth it to run the test everywhere and just suppress the validations that depend on implementation details as appropriate.
Summary
Native recovery of a Unix named mutex can happen before the runtime cleans up an externally created thread's managed ownership state. Deferred cleanup can then overwrite another process's ownership metadata, while stale local recursion state can misclassify a new acquisition or leak the dead owner's ownership reference.
[UnmanagedCallersOnly]callbacks. The finalizer-dependent scenarios require the newPlatformDetection.ManagedThreadCleanupOnFinalizerThreadcapability.Validation
Linux x64, using the existing checked baseline:
./build.sh clr.corelib+clr.nativecorelib+libs.pretest -rc checked -arch x64- passed..dotnet/dotnet build src/libraries/System.Threading/tests/System.Threading.Tests.csproj /t:Test /p:Outerloop=true /p:RuntimeConfiguration=Checked- passed: 775 passed, 17 existing platform skips, zero failures. All seven new cases ran without skips.Performance
Ad hoc BenchmarkDotNet measurements on WSL Ubuntu x64 with Release runtime/libraries, three launches, six warmups, and 15-30 measurement iterations per launch:
The recursive benchmark holds an initial acquisition outside the measured operation. Neither case allocates managed memory. The configured Mann-Whitney(3%) comparison reported
Samefor both, but distributions were noisy and multimodal; these observations are not evidence of a speedup or a precise bound on small overhead.Note
This pull request description was generated with GitHub Copilot.