@@ -2328,6 +2328,13 @@ enum CallbackProviderIndex
2328
2328
DotNETRuntimePrivate = 3
2329
2329
};
2330
2330
2331
+ enum SessionChange
2332
+ {
2333
+ EventPipeSessionDisable = 0 ,
2334
+ EventPipeSessionEnable = 1 ,
2335
+ EtwSessionChangeUnknown = 2
2336
+ };
2337
+
2331
2338
#if !defined(HOST_UNIX)
2332
2339
// EventFilterType identifies the filter type used by the PEVENT_FILTER_DESCRIPTOR
2333
2340
enum EventFilterType
@@ -2394,13 +2401,15 @@ VOID ParseFilterDataClientSequenceNumber(
2394
2401
// Common handler for all ETW or EventPipe event notifications. Based on the provider that
2395
2402
// was enabled/disabled, this implementation forwards the event state change onto GCHeapUtilities
2396
2403
// which will inform the GC to update its local state about what events are enabled.
2404
+ // NOTE: When multiple ETW or EventPipe sessions are enabled, the ControlCode will be
2405
+ // EVENT_CONTROL_CODE_ENABLE_PROVIDER even if the session invoking this callback is being disabled.
2397
2406
VOID EtwCallbackCommon (
2398
2407
CallbackProviderIndex ProviderIndex,
2399
2408
ULONG ControlCode,
2400
2409
UCHAR Level,
2401
2410
ULONGLONG MatchAnyKeyword,
2402
2411
PVOID pFilterData,
2403
- BOOL isEventPipeCallback )
2412
+ SessionChange Change )
2404
2413
{
2405
2414
LIMITED_METHOD_CONTRACT;
2406
2415
@@ -2436,20 +2445,17 @@ VOID EtwCallbackCommon(
2436
2445
// This callback gets called on both ETW/EventPipe session enable/disable.
2437
2446
// We need toupdate the EventPipe provider context if we are in a callback
2438
2447
// from EventPipe, but not from ETW.
2439
- if (isEventPipeCallback )
2448
+ if (Change == EventPipeSessionEnable || Change == EventPipeSessionDisable )
2440
2449
{
2441
2450
ctxToUpdate->EventPipeProvider .Level = Level;
2442
2451
ctxToUpdate->EventPipeProvider .EnabledKeywordsBitmask = MatchAnyKeyword;
2443
2452
ctxToUpdate->EventPipeProvider .IsEnabled = ControlCode;
2444
2453
2445
2454
// For EventPipe, ControlCode can only be either 0 or 1.
2446
- _ASSERTE (ControlCode == 0 || ControlCode == 1 );
2455
+ _ASSERTE (ControlCode == EVENT_CONTROL_CODE_DISABLE_PROVIDER || ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER );
2447
2456
}
2448
2457
2449
- if (
2450
- #if !defined(HOST_UNIX)
2451
- (ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER || ControlCode == EVENT_CONTROL_CODE_DISABLE_PROVIDER) &&
2452
- #endif
2458
+ if ((ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER || ControlCode == EVENT_CONTROL_CODE_DISABLE_PROVIDER) &&
2453
2459
(ProviderIndex == DotNETRuntime || ProviderIndex == DotNETRuntimePrivate))
2454
2460
{
2455
2461
#if !defined(HOST_UNIX)
@@ -2466,10 +2472,23 @@ VOID EtwCallbackCommon(
2466
2472
GCHeapUtilities::RecordEventStateChange (bIsPublicTraceHandle, keywords, level);
2467
2473
}
2468
2474
2469
- // Special check for the runtime provider's ManagedHeapCollectKeyword. Profilers
2470
- // flick this to force a full GC.
2471
- if (g_fEEStarted && !g_fEEShutDown && bIsPublicTraceHandle &&
2472
- ((MatchAnyKeyword & CLR_MANAGEDHEAPCOLLECT_KEYWORD) != 0 ))
2475
+ // Special check for a profiler requested GC.
2476
+ // A full GC will be forced if:
2477
+ // 1. The runtime has started and is not shutting down.
2478
+ // 2. The public provider is requesting GC.
2479
+ // 3. The provider's ManagedHeapCollectKeyword is enabled.
2480
+ // 4. If it is an ETW provider, the control code is to enable or capture the state of the provider.
2481
+ // 5. If it is an EventPipe provider, the session is not being disabled.
2482
+ bool bValidGCRequest =
2483
+ g_fEEStarted && !g_fEEShutDown &&
2484
+ bIsPublicTraceHandle &&
2485
+ ((MatchAnyKeyword & CLR_MANAGEDHEAPCOLLECT_KEYWORD) != 0 ) &&
2486
+ ((ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER) ||
2487
+ (ControlCode == EVENT_CONTROL_CODE_CAPTURE_STATE)) &&
2488
+ ((Change == EtwSessionChangeUnknown) ||
2489
+ (Change == EventPipeSessionEnable));
2490
+
2491
+ if (bValidGCRequest)
2473
2492
{
2474
2493
// Profilers may (optionally) specify extra data in the filter parameter
2475
2494
// to log with the GCStart event.
@@ -2506,7 +2525,9 @@ VOID EventPipeEtwCallbackDotNETRuntimeStress(
2506
2525
{
2507
2526
LIMITED_METHOD_CONTRACT;
2508
2527
2509
- EtwCallbackCommon (DotNETRuntimeStress, ControlCode, Level, MatchAnyKeyword, FilterData, true );
2528
+ SessionChange change = SourceId == NULL ? EventPipeSessionDisable : EventPipeSessionEnable;
2529
+
2530
+ EtwCallbackCommon (DotNETRuntimeStress, ControlCode, Level, MatchAnyKeyword, FilterData, change);
2510
2531
}
2511
2532
2512
2533
VOID EventPipeEtwCallbackDotNETRuntime (
@@ -2520,7 +2541,9 @@ VOID EventPipeEtwCallbackDotNETRuntime(
2520
2541
{
2521
2542
LIMITED_METHOD_CONTRACT;
2522
2543
2523
- EtwCallbackCommon (DotNETRuntime, ControlCode, Level, MatchAnyKeyword, FilterData, true );
2544
+ SessionChange change = SourceId == NULL ? EventPipeSessionDisable : EventPipeSessionEnable;
2545
+
2546
+ EtwCallbackCommon (DotNETRuntime, ControlCode, Level, MatchAnyKeyword, FilterData, change);
2524
2547
}
2525
2548
2526
2549
VOID EventPipeEtwCallbackDotNETRuntimeRundown (
@@ -2534,7 +2557,9 @@ VOID EventPipeEtwCallbackDotNETRuntimeRundown(
2534
2557
{
2535
2558
LIMITED_METHOD_CONTRACT;
2536
2559
2537
- EtwCallbackCommon (DotNETRuntimeRundown, ControlCode, Level, MatchAnyKeyword, FilterData, true );
2560
+ SessionChange change = SourceId == NULL ? EventPipeSessionDisable : EventPipeSessionEnable;
2561
+
2562
+ EtwCallbackCommon (DotNETRuntimeRundown, ControlCode, Level, MatchAnyKeyword, FilterData, change);
2538
2563
}
2539
2564
2540
2565
VOID EventPipeEtwCallbackDotNETRuntimePrivate (
@@ -2548,7 +2573,9 @@ VOID EventPipeEtwCallbackDotNETRuntimePrivate(
2548
2573
{
2549
2574
WRAPPER_NO_CONTRACT;
2550
2575
2551
- EtwCallbackCommon (DotNETRuntimePrivate, ControlCode, Level, MatchAnyKeyword, FilterData, true );
2576
+ SessionChange change = SourceId == NULL ? EventPipeSessionDisable : EventPipeSessionEnable;
2577
+
2578
+ EtwCallbackCommon (DotNETRuntimePrivate, ControlCode, Level, MatchAnyKeyword, FilterData, change);
2552
2579
}
2553
2580
2554
2581
@@ -2704,7 +2731,7 @@ extern "C"
2704
2731
return ;
2705
2732
}
2706
2733
2707
- EtwCallbackCommon (providerIndex, ControlCode, Level, MatchAnyKeyword, FilterData, false );
2734
+ EtwCallbackCommon (providerIndex, ControlCode, Level, MatchAnyKeyword, FilterData, EtwSessionChangeUnknown );
2708
2735
2709
2736
// A manifest based provider can be enabled to multiple event tracing sessions
2710
2737
// As long as there is atleast 1 enabled session, IsEnabled will be TRUE
@@ -2762,10 +2789,7 @@ extern "C"
2762
2789
2763
2790
}
2764
2791
}
2765
- #endif // FEATURE_NATIVEAOT
2766
-
2767
- #endif // HOST_UNIX
2768
- #ifndef FEATURE_NATIVEAOT
2792
+ #endif // !defined(HOST_UNIX)
2769
2793
2770
2794
/* ***************************************************************************/
2771
2795
/* This is called by the runtime when an exception is thrown */
0 commit comments