[release/10.0] Release ThreadStore lock before blocking for shutdown - #133182
Merged
Conversation
## Summary Prevent a debugger shutdown hang by releasing the ThreadStore lock before a non-special thread is permanently parked for shutdown. Addresses #126096. ## Background Paired debugger and target dumps showed this wait chain: 1. A non-special runtime thread begins sending a debugger class-load event and acquires ThreadStore. 2. It attempts to acquire the debugger lock after shutdown mode has begun. 3. The shutdown-aware debugger lock releases its own lock and parks the thread permanently in `WaitForEndOfShutdown`. 4. The enclosing ThreadStore lock holder never unwinds, leaving ThreadStore permanently held. 5. The debugger helper cannot acquire ThreadStore to process `DB_IPCE_ASYNC_BREAK`, so `ICorDebugProcess::Stop` never receives SyncComplete. This is distinct from the previously fixed ReadyToRun/`PtrHashMap` deadlock paths. ## Fix `Debugger::DoNotCallDirectlyPrivateLock` knows when a shutdown-mode debugger lock will reject and permanently park a non-special thread. If that thread owns ThreadStore, release it immediately before entering the shutdown wait. Using `ThreadSuspend::UnlockThreadStore` preserves the ThreadStore ownership and cant-stop bookkeeping rather than releasing the underlying Crst directly. Finalizer, debugger-helper, shutdown, and GC threads retain ThreadStore because they are allowed to continue during shutdown. ## Testing - `.\build.cmd -subset clr` - Built and ran `foreground-shutdown` five times successfully. > [!NOTE] > This pull request description was drafted with GitHub Copilot. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
noahfalk
approved these changes
Sep 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of #133049 to release/10.0
/cc @steveisok
Customer Impact
Customers can experience an indefinite hang when using Stop Debugging or closing an application on .NET 10. This was reported in #126096 and confirmed internally with paired debugger and target process dumps. A non-special runtime class-load notification thread can retain the ThreadStore lock when parked during debugger shutdown, preventing debugger helper synchronization from completing.
Regression
This is a pre-existing race with no known regression point.
Testing
The CoreCLR build passed, and the foreground-shutdown test ran successfully five times. Targeted internal hosted-runtime A/B validation used identical inputs and layout except for the CoreCLR binaries: the unmodified release/10.0 parent build remained blocked until timeout, while the fixed build completed in approximately four seconds.
Risk
Low. The change is limited to debugger shutdown rejection, conditionally releases the ThreadStore lock through ThreadSuspend bookkeeping, and leaves special-thread behavior unchanged.
IMPORTANT: If this backport is for a servicing release, please verify that:
release/X.0-staging, notrelease/X.0.release/X.0(no-stagingsuffix).Package authoring no longer needed in .NET 9
IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.