Fix STA sync-context deadlock in Shutdown() and Dispose()#17
Merged
Fix STA sync-context deadlock in Shutdown() and Dispose()#17
Conversation
Add ConfigureAwait(false) to all await sites in the library to prevent deadlocks when sync wrappers (Shutdown, Dispose) are called from a single-threaded SynchronizationContext (Avalonia, WPF, WinForms). Add regression test using a minimal single-threaded SynchronizationContext that reproduces the deadlock without any UI framework dependency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces prerelease 10.0.0-preview.1.25080.5 with stable 10.0.3, fixing NU5104 warning about prerelease dependency in a stable package. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.
Summary
Add
ConfigureAwait(false)to allawaitsites in the library to fix a deadlock whenLogManager.Shutdown()orBufferedLogSink.Dispose()is called from a single-threadedSynchronizationContext(Avalonia, WPF, WinForms). Includes a regression test that reproduces the deadlock without any UI framework dependency.Reason for Change
LogManager.Shutdown()synchronously blocks via.GetAwaiter().GetResult(). The async dispose chain (ShutdownAsync→DisposeAllAsync→DisposeSinksAsync→BufferedLogSink.DisposeAsync) captures the caller'sSynchronizationContextat eachawait. On a single-threaded context (STA thread), the continuation tries to resume on the blocked thread — classic deadlock.Task.Run(() => LogManager.Shutdown())worked around it by moving off the STA thread, but that risks not completing before process exit.Impact
awaitsites insrc/Logsmith/now useConfigureAwait(false)(23 sites across 6 files)Shutdown(),Dispose(),Reset()) are now safe to call from anySynchronizationContextShutdown_Sync_OnSingleThreadedSyncContext_WithBufferedSink_Completesvalidates the fix using a minimal single-threadedSynchronizationContextMigration Steps
None — this is a bugfix with no API changes.
Performance Considerations
ConfigureAwait(false)avoids unnecessarySynchronizationContext.Postcalls, which is a marginal improvement in async throughput for the drain/dispose paths.Security Considerations
None.
Breaking Changes
SynchronizationContext. This is the correct behavior for a library.