@@ -4222,18 +4222,33 @@ internal static void DisposeOnShutdown()
4222
4222
// If an EventListener calls Dispose without calling DisableEvents first we want to issue the Disable command now
4223
4223
private static void CallDisableEventsIfNecessary( EventDispatcher eventDispatcher , EventSource eventSource )
4224
4224
{
4225
- if ( eventDispatcher . m_EventEnabled == null )
4225
+ #if DEBUG
4226
+ // Disable validation of EventSource/EventListener connections in case a call to EventSource.AddListener
4227
+ // causes a recursive call into this method.
4228
+ bool previousValue = s_ConnectingEventSourcesAndListener;
4229
+ s_ConnectingEventSourcesAndListener = true;
4230
+ try
4226
4231
{
4227
- return ;
4228
- }
4232
+ #endif
4233
+ if ( eventDispatcher . m_EventEnabled == null )
4234
+ {
4235
+ return ;
4236
+ }
4229
4237
4230
- for ( int i = 0 ; i < eventDispatcher . m_EventEnabled . Length ; ++ i)
4231
- {
4232
- if ( eventDispatcher . m_EventEnabled [ i ] )
4238
+ for ( int i = 0 ; i < eventDispatcher . m_EventEnabled . Length ; ++ i)
4233
4239
{
4234
- eventDispatcher. m_Listener . DisableEvents ( eventSource ) ;
4240
+ if ( eventDispatcher . m_EventEnabled [ i ] )
4241
+ {
4242
+ eventDispatcher. m_Listener . DisableEvents ( eventSource ) ;
4243
+ }
4235
4244
}
4245
+ #if DEBUG
4246
+ }
4247
+ finally
4248
+ {
4249
+ s_ConnectingEventSourcesAndListener = previousValue;
4236
4250
}
4251
+ #endif
4237
4252
}
4238
4253
4239
4254
/// <summary>
@@ -4247,6 +4262,27 @@ private static void RemoveReferencesToListenerInEventSources(EventListener liste
4247
4262
Debug. Assert ( Monitor . IsEntered ( EventListener . EventListenersLock ) ) ;
4248
4263
// Foreach existing EventSource in the appdomain
4249
4264
Debug. Assert ( s_EventSources != null ) ;
4265
+
4266
+ // First pass to call DisableEvents
4267
+ foreach ( WeakReference < EventSource > eventSourceRef in s_EventSources)
4268
+ {
4269
+ if ( eventSourceRef . TryGetTarget ( out EventSource ? eventSource ) )
4270
+ {
4271
+ EventDispatcher ? cur = eventSource . m_Dispatchers ;
4272
+ while ( cur != null )
4273
+ {
4274
+ if ( cur . m_Listener == listenerToRemove )
4275
+ {
4276
+ CallDisableEventsIfNecessary ( cur ! , eventSource ) ;
4277
+ }
4278
+
4279
+ cur = cur . m_Next ;
4280
+ }
4281
+ }
4282
+ }
4283
+
4284
+ // DisableEvents can call back to user code and we have to start over since s_EventSources and
4285
+ // eventSource.m_Dispatchers could have mutated
4250
4286
foreach ( WeakReference < EventSource > eventSourceRef in s_EventSources)
4251
4287
{
4252
4288
if ( eventSourceRef . TryGetTarget ( out EventSource ? eventSource ) )
@@ -4255,7 +4291,6 @@ private static void RemoveReferencesToListenerInEventSources(EventListener liste
4255
4291
// Is the first output dispatcher the dispatcher we are removing?
4256
4292
if ( eventSource . m_Dispatchers . m_Listener == listenerToRemove )
4257
4293
{
4258
- CallDisableEventsIfNecessary( eventSource . m_Dispatchers ! , eventSource ) ;
4259
4294
eventSource. m_Dispatchers = eventSource . m_Dispatchers . m_Next ;
4260
4295
}
4261
4296
else
@@ -4272,7 +4307,6 @@ private static void RemoveReferencesToListenerInEventSources(EventListener liste
4272
4307
}
4273
4308
if ( cur . m_Listener == listenerToRemove )
4274
4309
{
4275
- CallDisableEventsIfNecessary( cur ! , eventSource ) ;
4276
4310
prev. m_Next = cur . m_Next ; // Remove entry.
4277
4311
break ;
4278
4312
}
@@ -4288,6 +4322,7 @@ private static void RemoveReferencesToListenerInEventSources(EventListener liste
4288
4322
#endif // FEATURE_PERFTRACING
4289
4323
}
4290
4324
4325
+
4291
4326
/// <summary>
4292
4327
/// Checks internal consistency of EventSources/Listeners.
4293
4328
/// </summary>
0 commit comments