EventPipeConfiguration EventPipe::s_config;
EventPipeEventSource *EventPipe::s_pEventSource = nullptr;
VolatilePtr<EventPipeSession> EventPipe::s_pSessions[MaxNumberOfSessions];
+Volatile<uint64_t> EventPipe::s_allowWrite = 0;
#ifndef FEATURE_PAL
unsigned int * EventPipe::s_pProcGroupOffsets = nullptr;
#endif
return false;
}
s_pSessions[pSession->GetIndex()].Store(pSession);
+ s_allowWrite |= pSession->GetMask();
++s_numberOfSessions;
// Enable tracing.
// Disable pSession tracing.
s_config.Disable(*pSession, pEventPipeProviderCallbackDataQueue);
+ s_allowWrite &= ~(pSession->GetMask());
+
pSession->Disable(); // Suspend EventPipeBufferManager, and remove providers.
// Do rundown before fully stopping the session unless rundown wasn't requested
{
for (uint32_t i = 0; i < MaxNumberOfSessions; ++i)
{
- // This read is OK because we aren't derefencing the pointer and if we observe a value that
- // isn't up-to-date (whether null or non-null) that is just the natural race timing of trying to
- // write to a session while it is being concurrently enabled/disabled.
- if (s_pSessions[i].LoadWithoutBarrier() == nullptr)
+ if ((s_allowWrite & (1ui64 << i)) == 0)
continue;
// Now that we know this session is probably live we pay the perf cost of the memory barriers
{
EventPipeSession *const pSession = s_pSessions[i].Load();
- // The NULL check above may make this check below appear redundant but it is not. Disable is
- // allowed to set s_pSessions[i] = NULL at any time and that may have occured in between
+ // Disable is allowed to set s_pSessions[i] = NULL at any time and that may have occured in between
// the check and the load
if (pSession != nullptr)
pSession->WriteEventBuffered(
static Volatile<bool> s_tracingInitialized;
static EventPipeConfiguration s_config;
static VolatilePtr<EventPipeSession> s_pSessions[MaxNumberOfSessions];
+ static Volatile<uint64_t> s_allowWrite;
static EventPipeEventSource *s_pEventSource;
//! Bitmask tracking EventPipe active sessions.