diff --git a/src/coreclr/tests/src/tracing/regress/GitHub_34839/GitHub_34839.cs b/src/coreclr/tests/src/tracing/regress/GitHub_34839/GitHub_34839.cs
new file mode 100644
index 00000000000000..7b0a978153739d
--- /dev/null
+++ b/src/coreclr/tests/src/tracing/regress/GitHub_34839/GitHub_34839.cs
@@ -0,0 +1,238 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Tracing;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+
+/*
+
+This test is a regression test for github.com/dotnet/runtime/issues/34839.
+
+We test whether it's possible to enable many sessions via reflection on EventPipe.Enable method, and whether they can be disabled by calling corresponding Disable() method.
+
+*/
+namespace EventPipe.Issue34839
+{
+ public enum EventPipeSerializationFormat
+ {
+ NetPerf,
+ NetTrace
+ }
+
+ public sealed class TraceConfiguration
+ {
+ private ConstructorInfo m_configurationCtor;
+ private MethodInfo m_enableProviderMethod;
+ private MethodInfo m_setProfilerSamplingRateMethod;
+
+ private object m_configurationObject;
+
+ public TraceConfiguration(
+ string outputFile,
+ uint circularBufferMB)
+ {
+ // Initialize reflection references.
+ if (!Initialize())
+ {
+ throw new InvalidOperationException("Reflection failed.");
+ }
+
+ m_configurationObject = m_configurationCtor.Invoke(
+ new object[]
+ {
+ outputFile,
+ EventPipeSerializationFormat.NetTrace,
+ circularBufferMB
+ });
+ }
+
+ public void EnableProvider(
+ string providerName,
+ UInt64 keywords,
+ uint level)
+ {
+ m_enableProviderMethod.Invoke(
+ m_configurationObject,
+ new object[]
+ {
+ providerName,
+ keywords,
+ level
+ });
+ }
+
+ internal object ConfigurationObject
+ {
+ get { return m_configurationObject; }
+ }
+
+ public void SetSamplingRate(TimeSpan minDelayBetweenSamples)
+ {
+ m_setProfilerSamplingRateMethod.Invoke(
+ m_configurationObject,
+ new object[]
+ {
+ minDelayBetweenSamples
+ });
+ }
+
+ private bool Initialize()
+ {
+ Assembly SPC = typeof(System.Diagnostics.Tracing.EventSource).Assembly;
+ if (SPC == null)
+ {
+ Console.WriteLine("System.Private.CoreLib assembly == null");
+ return false;
+ }
+
+ Type configurationType = SPC.GetType("System.Diagnostics.Tracing.EventPipeConfiguration");
+ if (configurationType == null)
+ {
+ Console.WriteLine("configurationType == null");
+ return false;
+ }
+ Type formatType = SPC.GetType("System.Diagnostics.Tracing.EventPipeSerializationFormat");
+ if (formatType == null)
+ {
+ Console.WriteLine("formatType == null");
+ return false;
+ }
+
+ m_configurationCtor = configurationType.GetConstructor(
+ BindingFlags.NonPublic | BindingFlags.Instance,
+ null,
+ new Type[] { typeof(string), formatType, typeof(uint) },
+ null);
+ if (m_configurationCtor == null)
+ {
+ Console.WriteLine("configurationCtor == null");
+ return false;
+ }
+
+ m_enableProviderMethod = configurationType.GetMethod(
+ "EnableProvider",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+ if (m_enableProviderMethod == null)
+ {
+ Console.WriteLine("enableProviderMethod == null");
+ return false;
+ }
+
+ m_setProfilerSamplingRateMethod = configurationType.GetMethod(
+ "SetProfilerSamplingRate",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+ if (m_setProfilerSamplingRateMethod == null)
+ {
+ Console.WriteLine("setProfilerSamplingRate == null");
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ class Program
+ {
+ private static MethodInfo m_enableMethod;
+ private static MethodInfo m_disableMethod;
+
+ public static void Enable(TraceConfiguration traceConfig)
+ {
+ m_enableMethod.Invoke(
+ null,
+ new object[]
+ {
+ traceConfig.ConfigurationObject
+ });
+ }
+
+ public static void Disable()
+ {
+ m_disableMethod.Invoke(
+ null,
+ null);
+ }
+
+ static int Main(string[] args)
+ {
+ TimeSpan profSampleDelay = TimeSpan.FromMilliseconds(1);
+
+ Assembly SPC = typeof(System.Diagnostics.Tracing.EventSource).Assembly;
+ Type eventPipeType = SPC.GetType("System.Diagnostics.Tracing.EventPipe");
+ m_enableMethod = eventPipeType.GetMethod("Enable", BindingFlags.NonPublic | BindingFlags.Static);
+ m_disableMethod = eventPipeType.GetMethod("Disable", BindingFlags.NonPublic | BindingFlags.Static);
+
+ // Setup the configuration values.
+ uint circularBufferMB = 1024; // 1 GB
+ uint level = 5; // Verbose
+
+ const uint configurationCnt = 5;
+
+ // Create 5 instances of EventPipeConfiguration.
+ TraceConfiguration[] configs = new TraceConfiguration[configurationCnt];
+
+ for (int i = 0; i < configurationCnt; i++)
+ {
+ string outputFile = $"default{i}.nettrace";
+ configs[i] = new TraceConfiguration(outputFile, circularBufferMB);
+
+ // Setup the provider values.
+ // Public provider.
+ string providerName = "Microsoft-Windows-DotNETRuntime";
+ UInt64 keywords = 0x4c14fccbd;
+
+ // Enable the provider.
+ configs[i].EnableProvider(providerName, keywords, level);
+
+ // Private provider.
+ providerName = "Microsoft-Windows-DotNETRuntimePrivate";
+ keywords = 0x4002000b;
+
+ // Enable the provider.
+ configs[i].EnableProvider(providerName, keywords, level);
+
+ // Sample profiler.
+ providerName = "Microsoft-DotNETCore-SampleProfiler";
+ keywords = 0x0;
+
+ // Enable the provider.
+ configs[i].EnableProvider(providerName, keywords, level);
+
+ // Set the sampling rate.
+ configs[i].SetSamplingRate(profSampleDelay);
+ }
+
+ // Enable tracing many times
+ for (int i = 0; i < configurationCnt; i++)
+ {
+ Enable(configs[i]);
+ }
+
+ // Sleep for 5 seconds to let some events to be written
+ Thread.Sleep(5000);
+
+ // Disable
+ for (int i = 0; i < configurationCnt; i++)
+ {
+ Disable();
+ }
+
+ // Assert that all trace files exist now.
+ for (int i = 0; i < configurationCnt; i++)
+ {
+ string outputFile = $"default{i}.nettrace";
+ if (!File.Exists(outputFile))
+ {
+ Console.WriteLine($"The expected output file {i} does not exist");
+ return 1;
+ }
+ }
+
+ return 100;
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/tracing/regress/GitHub_34839/GitHub_34839.csproj b/src/coreclr/tests/src/tracing/regress/GitHub_34839/GitHub_34839.csproj
new file mode 100644
index 00000000000000..c6c03714e2f0b0
--- /dev/null
+++ b/src/coreclr/tests/src/tracing/regress/GitHub_34839/GitHub_34839.csproj
@@ -0,0 +1,14 @@
+
+
+ Exe
+ BuildAndRun
+ true
+ 0
+
+ true
+ true
+
+
+
+
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipe.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipe.cs
index 308c19ada6281b..1abbf006e57b96 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipe.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipe.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
@@ -177,7 +178,7 @@ internal void SetProfilerSamplingRate(TimeSpan minTimeBetweenSamples)
internal static class EventPipe
{
- private static ulong s_sessionID = 0;
+ internal static ConcurrentQueue s_sessionIDs = new ConcurrentQueue();
internal static void Enable(EventPipeConfiguration configuration)
{
@@ -193,16 +194,19 @@ internal static void Enable(EventPipeConfiguration configuration)
EventPipeProviderConfiguration[] providers = configuration.Providers;
- s_sessionID = EventPipeInternal.Enable(
+ s_sessionIDs.Enqueue(EventPipeInternal.Enable(
configuration.OutputFile,
configuration.Format,
configuration.CircularBufferSizeInMB,
- providers);
+ providers));
}
internal static void Disable()
{
- EventPipeInternal.Disable(s_sessionID);
+ if (s_sessionIDs.TryDequeue(out ulong sessionID))
+ {
+ EventPipeInternal.Disable(sessionID);
+ }
}
}