Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 88876b3

Browse files
authored
Make sure RuntimeEventSource is passed to EventListener.OnEventSourceCreated (#19697)
1 parent 98a7f87 commit 88876b3

File tree

4 files changed

+106
-78
lines changed

4 files changed

+106
-78
lines changed

src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,14 @@ private static uint Rol30(uint input)
16491649

16501650
private static Guid GenerateGuidFromName(string name)
16511651
{
1652+
if (namespaceBytes == null)
1653+
{
1654+
namespaceBytes = new byte[] {
1655+
0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8,
1656+
0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
1657+
};
1658+
}
1659+
16521660
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(name);
16531661
var hash = new Sha1ForNonSecretPurposes();
16541662
hash.Start();
@@ -3734,11 +3742,12 @@ private bool SelfDescribingEvents
37343742
internal const string s_ActivityStartSuffix = "Start";
37353743
internal const string s_ActivityStopSuffix = "Stop";
37363744

3745+
// WARNING: Do not depend upon initialized statics during creation of EventSources, as it is possible for creation of an EventSource to trigger
3746+
// creation of yet another EventSource. When this happens, these statics may not yet be initialized.
3747+
// Rather than depending on initialized statics, use lazy initialization to ensure that the statics are initialized exactly when they are needed.
3748+
37373749
// used for generating GUID from eventsource name
3738-
private static readonly byte[] namespaceBytes = new byte[] {
3739-
0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8,
3740-
0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
3741-
};
3750+
private static byte[] namespaceBytes;
37423751

37433752
#endregion
37443753
}
@@ -3847,6 +3856,16 @@ public event EventHandler<EventSourceCreatedEventArgs> EventSourceCreated
38473856
/// </summary>
38483857
public event EventHandler<EventWrittenEventArgs> EventWritten;
38493858

3859+
static EventListener()
3860+
{
3861+
#if FEATURE_PERFTRACING
3862+
// Ensure that RuntimeEventSource is initialized so that EventListeners get an opportunity to subscribe to its events.
3863+
// This is required because RuntimeEventSource never emit events on its own, and thus will never be initialized
3864+
// in the normal way that EventSources are initialized.
3865+
GC.KeepAlive(RuntimeEventSource.Log);
3866+
#endif // FEATURE_PERFTRACING
3867+
}
3868+
38503869
/// <summary>
38513870
/// Create a new EventListener in which all events start off turned off (use EnableEvents to turn
38523871
/// them on).
@@ -4082,9 +4101,24 @@ internal static void AddEventSource(EventSource newEventSource)
40824101
}
40834102
newEventSource.m_id = newIndex;
40844103

4085-
// Add every existing dispatcher to the new EventSource
4086-
for (EventListener listener = s_Listeners; listener != null; listener = listener.m_Next)
4087-
newEventSource.AddListener(listener);
4104+
#if DEBUG
4105+
// Disable validation of EventSource/EventListener connections in case a call to EventSource.AddListener
4106+
// causes a recursive call into this method.
4107+
bool previousValue = s_ConnectingEventSourcesAndListener;
4108+
s_ConnectingEventSourcesAndListener = true;
4109+
try
4110+
{
4111+
#endif
4112+
// Add every existing dispatcher to the new EventSource
4113+
for (EventListener listener = s_Listeners; listener != null; listener = listener.m_Next)
4114+
newEventSource.AddListener(listener);
4115+
#if DEBUG
4116+
}
4117+
finally
4118+
{
4119+
s_ConnectingEventSourcesAndListener = previousValue;
4120+
}
4121+
#endif
40884122

40894123
Validate();
40904124
}
@@ -4165,6 +4199,14 @@ private static void RemoveReferencesToListenerInEventSources(EventListener liste
41654199
[Conditional("DEBUG")]
41664200
internal static void Validate()
41674201
{
4202+
#if DEBUG
4203+
// Don't run validation code if we're in the middle of modifying the connections between EventSources and EventListeners.
4204+
if (s_ConnectingEventSourcesAndListener)
4205+
{
4206+
return;
4207+
}
4208+
#endif
4209+
41684210
lock (EventListenersLock)
41694211
{
41704212
// Get all listeners
@@ -4254,18 +4296,30 @@ private void CallBackForExistingEventSources(bool addToListenersList, EventHandl
42544296
// is created.
42554297
WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray();
42564298

4257-
for (int i = 0; i < eventSourcesSnapshot.Length; i++)
4299+
#if DEBUG
4300+
bool previousValue = s_ConnectingEventSourcesAndListener;
4301+
s_ConnectingEventSourcesAndListener = true;
4302+
try
42584303
{
4259-
WeakReference eventSourceRef = eventSourcesSnapshot[i];
4260-
EventSource eventSource = eventSourceRef.Target as EventSource;
4261-
if (eventSource != null)
4304+
#endif
4305+
for (int i = 0; i < eventSourcesSnapshot.Length; i++)
42624306
{
4263-
EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
4264-
args.EventSource = eventSource;
4265-
callback(this, args);
4307+
WeakReference eventSourceRef = eventSourcesSnapshot[i];
4308+
EventSource eventSource = eventSourceRef.Target as EventSource;
4309+
if (eventSource != null)
4310+
{
4311+
EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
4312+
args.EventSource = eventSource;
4313+
callback(this, args);
4314+
}
42664315
}
4316+
#if DEBUG
42674317
}
4268-
4318+
finally
4319+
{
4320+
s_ConnectingEventSourcesAndListener = previousValue;
4321+
}
4322+
#endif
42694323
Validate();
42704324
}
42714325
finally
@@ -4299,6 +4353,16 @@ private void CallBackForExistingEventSources(bool addToListenersList, EventHandl
42994353
/// </summary>
43004354
private static bool s_CreatingListener = false;
43014355

4356+
#if DEBUG
4357+
/// <summary>
4358+
/// Used to disable validation of EventSource and EventListener connectivity.
4359+
/// This is needed when an EventListener is in the middle of being published to all EventSources
4360+
/// and another EventSource is created as part of the process.
4361+
/// </summary>
4362+
[ThreadStatic]
4363+
private static bool s_ConnectingEventSourcesAndListener = false;
4364+
#endif
4365+
43024366
/// <summary>
43034367
/// Used to register AD/Process shutdown callbacks.
43044368
/// </summary>
@@ -4637,7 +4701,7 @@ public DateTime TimeStamp
46374701
internal set;
46384702
}
46394703

4640-
#region private
4704+
#region private
46414705
internal EventWrittenEventArgs(EventSource eventSource)
46424706
{
46434707
m_eventSource = eventSource;

tests/src/tracing/common/RuntimeEventSource.cs

Lines changed: 0 additions & 52 deletions
This file was deleted.

tests/src/tracing/common/common.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
<Compile Include="Assert.cs" />
2929
<Compile Include="EtlFile.cs" />
3030
<Compile Include="NetPerfFile.cs" />
31-
<Compile Include="RuntimeEventSource.cs" />
3231
<Compile Include="TraceControl.cs" />
3332
<Compile Include="TraceConfiguration.cs" />
3433
</ItemGroup>

tests/src/tracing/runtimeeventsource/RuntimeEventSourceTest.cs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,16 @@ public sealed class RuntimeEventSourceTest
1717
{
1818
static int Main(string[] args)
1919
{
20-
// Get the RuntimeEventSource.
21-
EventSource eventSource = RuntimeEventSource.Log;
22-
20+
SimpleEventListener.EnableKeywords = (EventKeywords)0;
2321
using (SimpleEventListener noEventsListener = new SimpleEventListener("NoEvents"))
2422
{
25-
// Enable the provider, but not any keywords, so we should get no events as long as no rundown occurs.
26-
noEventsListener.EnableEvents(eventSource, EventLevel.Critical, (EventKeywords)(0));
27-
2823
// Create an EventListener.
24+
SimpleEventListener.EnableKeywords = (EventKeywords)0x4c14fccbd;
2925
using (SimpleEventListener listener = new SimpleEventListener("Simple"))
3026
{
3127
// Trigger the allocator task.
3228
System.Threading.Tasks.Task.Run(new Action(Allocator));
3329

34-
// Enable events.
35-
listener.EnableEvents(eventSource, EventLevel.Verbose, (EventKeywords)(0x4c14fccbd));
36-
3730
// Wait for events.
3831
Thread.Sleep(1000);
3932

@@ -73,13 +66,37 @@ internal sealed class SimpleEventListener : EventListener
7366
{
7467
private string m_name;
7568

69+
// Keep track of the set of keywords to be enabled.
70+
public static EventKeywords EnableKeywords
71+
{
72+
get;
73+
set;
74+
}
75+
7676
public SimpleEventListener(string name)
7777
{
7878
m_name = name;
7979
}
8080

8181
public int EventCount { get; private set; } = 0;
8282

83+
protected override void OnEventSourceCreated(EventSource eventSource)
84+
{
85+
if (eventSource.Name.Equals("Microsoft-Windows-DotNETRuntime"))
86+
{
87+
if (EnableKeywords != 0)
88+
{
89+
// Enable events.
90+
EnableEvents(eventSource, EventLevel.Verbose, EnableKeywords);
91+
}
92+
else
93+
{
94+
// Enable the provider, but not any keywords, so we should get no events as long as no rundown occurs.
95+
EnableEvents(eventSource, EventLevel.Critical, EnableKeywords);
96+
}
97+
}
98+
}
99+
83100
protected override void OnEventWritten(EventWrittenEventArgs eventData)
84101
{
85102
long osThreadId = -1;

0 commit comments

Comments
 (0)