Browse Source

Fix deadlock when a decompiler assertion fires during navigation

A Debug.Assert raised on a background decompile thread runs through
TraceInternal.Fail, which holds the global trace lock while invoking
the listener; the listener blocks on the UI thread to show the
assertion dialog. Meanwhile the UI thread, mid-navigation, runs a
layout pass whose virtualizing panel raises a binding error that
Avalonia logs via Trace.WriteLine -- which blocks acquiring that same
global trace lock. The two threads deadlock and the app freezes with
no dialog.

Mark the listener thread-safe and disable the global trace lock so
TraceInternal dispatches to it without serializing, removing the
contended lock between the asserting thread and the UI thread.

Assisted-by: Claude:claude-fable-5:Claude Code
pull/3776/head
Siegfried Pammer 4 weeks ago committed by Siegfried Pammer
parent
commit
80ca34b33c
  1. 13
      ILSpy/AppEnv/ILSpyTraceListener.cs

13
ILSpy/AppEnv/ILSpyTraceListener.cs

@ -36,8 +36,21 @@ namespace ILSpy.AppEnv @@ -36,8 +36,21 @@ namespace ILSpy.AppEnv
{
Trace.Listeners.Clear();
Trace.Listeners.Add(new ILSpyTraceListener());
// Don't serialize trace output through TraceInternal's global lock. A decompiler
// Debug.Assert runs Fail() under that lock, and Fail() blocks on the UI thread to
// show the dialog; meanwhile the UI thread emits its own trace output (Avalonia
// logs binding errors during a layout pass) and would block acquiring the same
// lock -> deadlock. With the global lock off and the listener declaring itself
// thread-safe, TraceInternal calls the listener directly, so the asserting thread
// and the UI thread no longer contend on it.
Trace.UseGlobalLock = false;
}
// Tells TraceInternal it may invoke this listener without taking the global lock; the
// dialog show is marshalled to the UI thread and guarded against re-entrancy, and the
// listener's own mutable state is lock-protected below.
public override bool IsThreadSafe => true;
ILSpyTraceListener()
{
AssertUiEnabled = false;

Loading…
Cancel
Save