Skip to content

Fix STA sync-context deadlock in Shutdown() and Dispose()#17

Merged
DJGosnell merged 2 commits intomasterfrom
fix/sta-sync-context-deadlock
Mar 5, 2026
Merged

Fix STA sync-context deadlock in Shutdown() and Dispose()#17
DJGosnell merged 2 commits intomasterfrom
fix/sta-sync-context-deadlock

Conversation

@DJGosnell
Copy link
Member

Summary

Add ConfigureAwait(false) to all await sites in the library to fix a deadlock when LogManager.Shutdown() or BufferedLogSink.Dispose() is called from a single-threaded SynchronizationContext (Avalonia, WPF, WinForms). Includes a regression test that reproduces the deadlock without any UI framework dependency.

  • Closes #

Reason for Change

LogManager.Shutdown() synchronously blocks via .GetAwaiter().GetResult(). The async dispose chain (ShutdownAsyncDisposeAllAsyncDisposeSinksAsyncBufferedLogSink.DisposeAsync) captures the caller's SynchronizationContext at each await. 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

  • All await sites in src/Logsmith/ now use ConfigureAwait(false) (23 sites across 6 files)
  • Sync wrappers (Shutdown(), Dispose(), Reset()) are now safe to call from any SynchronizationContext
  • New regression test Shutdown_Sync_OnSingleThreadedSyncContext_WithBufferedSink_Completes validates the fix using a minimal single-threaded SynchronizationContext

Migration Steps

None — this is a bugfix with no API changes.

Performance Considerations

ConfigureAwait(false) avoids unnecessary SynchronizationContext.Post calls, which is a marginal improvement in async throughput for the drain/dispose paths.

Security Considerations

None.

Breaking Changes

  • Consumer-facing: None
  • Internal: Async continuations in the library no longer flow the caller's SynchronizationContext. This is the correct behavior for a library.

DJGosnell and others added 2 commits March 5, 2026 15:29
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>
@DJGosnell DJGosnell merged commit fafe062 into master Mar 5, 2026
1 check passed
@DJGosnell DJGosnell deleted the fix/sta-sync-context-deadlock branch March 5, 2026 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant