Skip to content

Commit 75a48e9

Browse files
authored
Fix Deadlock Inside Metrics Code (#105259)
1 parent ea9d53e commit 75a48e9

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections.Generic;
55
using System.ComponentModel;
6+
using System.Runtime.CompilerServices;
67

78
namespace System.Diagnostics.Metrics
89
{
@@ -88,6 +89,17 @@ protected void Publish()
8889
return;
8990
}
9091

92+
// MeterListener has a static constructor that creates runtime metrics instruments.
93+
// We need to ensure this static constructor is called before starting to publish the instrument.
94+
// This is necessary because creating runtime metrics instruments will cause re-entry to the Publish method,
95+
// potentially resulting in a deadlock due to the SyncObject lock.
96+
// Sequence of the deadlock:
97+
// 1. An application creates an early instrument (e.g., Counter) before the MeterListener static constructor is executed.
98+
// 2. Instrument.Publish is called and enters the SyncObject lock.
99+
// 3. Within the lock block, MeterListener is called, triggering its static constructor.
100+
// 4. The static constructor creates runtime metrics instruments, causing re-entry to Instrument.Publish and leading to a deadlock.
101+
RuntimeHelpers.RunClassConstructor(typeof(MeterListener).TypeHandle);
102+
91103
List<MeterListener>? allListeners = null;
92104
lock (Instrument.SyncObject)
93105
{

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MeterListener.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ public void Dispose()
293293
}
294294
}
295295

296-
// Publish is called from Instrument.Publish
296+
// GetAllListeners is called from Instrument.Publish inside Instrument.SyncObject lock.
297297
internal static List<MeterListener>? GetAllListeners() => s_allStartedListeners.Count == 0 ? null : new List<MeterListener>(s_allStartedListeners);
298298

299299
[MethodImpl(MethodImplOptions.AggressiveInlining)]

0 commit comments

Comments
 (0)