From 0cefe59c4884cf9db45957097c798a0e924b4a22 Mon Sep 17 00:00:00 2001 From: Noah Falk Date: Thu, 9 Apr 2026 17:47:09 -0700 Subject: [PATCH] Early init for FrameworkEventSource ThreadPoolWorkQueue uses FrameworkEventSource during ThreadPool initialization. If that is the first time the FrameworkEventSource is being used, creating it on-demand will acquire the EventListener lock which can deadlock. We avoid that deadlock by creating the EventSource earlier on the startup path where nothing is waiting and holding the lock. We've seen several of these EventSource lock deadlocks over the years and it would be nice to make a more comprehensive fix, but unforetunately the only broad fix I know of would be make EventSource callbacks asynchronous relative to the underlying ETW callbacks. That isn't out of the question but it does carry a broader set of compatibility risks so we've generally favored these lower risk spot fixes instead. Fixes https://github.com/dotnet/runtime/issues/126591 --- .../src/System/Diagnostics/Tracing/EventSource.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 2761e0037e20a9..feabfae3e18835 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3896,10 +3896,14 @@ internal static void InitializeDefaultEventSources() return; } -// NOTE: this define is being used inconsistently. Most places mean just EventPipe support, but then a few places use -// it to mean other aspects of tracing such as these EventSources. + // NOTE: this define is being used inconsistently. Most places mean just EventPipe support, but then a few places use + // it to mean other aspects of tracing such as these EventSources. #if FEATURE_PERFTRACING _ = NativeRuntimeEventSource.Log; + // ThreadPoolWorkQueue uses FrameworkEventSource during ThreadPool initialization. If that is the first time + // the FrameworkEventSource is being used, creating it on-demand will acquire the EventListener lock which can deadlock. + // See https://github.com/dotnet/runtime/issues/126591. We avoid that by pre-creating the FrameworkEventSource here. + _ = FrameworkEventSource.Log; #if !TARGET_BROWSER _ = RuntimeEventSource.Log; #endif