Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mason <davmason@microsoft.com>2021-06-15 21:54:02 +0300
committerGitHub <noreply@github.com>2021-06-15 21:54:02 +0300
commitab71c1f4031d449ed3d60ccaaecb629bb73b648a (patch)
tree891426baadbc67a3718edc12632887ef5cc83d00 /src/coreclr/vm
parent63c8ab2e7acedca0547bc9d59ba8b7d34faf3ddb (diff)
Add the concept of "notification profilers" to the runtime (#53122)
Diffstat (limited to 'src/coreclr/vm')
-rw-r--r--src/coreclr/vm/ClrEtwAll.man32
-rw-r--r--src/coreclr/vm/appdomain.cpp48
-rw-r--r--src/coreclr/vm/assembly.cpp24
-rw-r--r--src/coreclr/vm/ceeload.cpp50
-rw-r--r--src/coreclr/vm/ceemain.cpp11
-rw-r--r--src/coreclr/vm/class.cpp12
-rw-r--r--src/coreclr/vm/clsload.cpp8
-rw-r--r--src/coreclr/vm/comcallablewrapper.cpp12
-rw-r--r--src/coreclr/vm/comsynchronizable.cpp8
-rw-r--r--src/coreclr/vm/crossgencompile.cpp2
-rw-r--r--src/coreclr/vm/eetoprofinterfaceimpl.cpp529
-rw-r--r--src/coreclr/vm/eetoprofinterfaceimpl.h50
-rw-r--r--src/coreclr/vm/eetoprofinterfaceimpl.inl2
-rw-r--r--src/coreclr/vm/eetoprofinterfacewrapper.inl72
-rw-r--r--src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h10
-rw-r--r--src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h6
-rw-r--r--src/coreclr/vm/eventpipeadapter.h6
-rw-r--r--src/coreclr/vm/eventpipeinternal.cpp1
-rw-r--r--src/coreclr/vm/eventtrace.cpp12
-rw-r--r--src/coreclr/vm/gcenv.ee.cpp37
-rw-r--r--src/coreclr/vm/gchandleutilities.cpp12
-rw-r--r--src/coreclr/vm/genanalysis.cpp1
-rw-r--r--src/coreclr/vm/jitinterface.cpp24
-rw-r--r--src/coreclr/vm/prestub.cpp32
-rw-r--r--src/coreclr/vm/profdetach.cpp256
-rw-r--r--src/coreclr/vm/profdetach.h21
-rw-r--r--src/coreclr/vm/profilinghelper.cpp558
-rw-r--r--src/coreclr/vm/profilinghelper.h52
-rw-r--r--src/coreclr/vm/proftoeeinterfaceimpl.cpp302
-rw-r--r--src/coreclr/vm/proftoeeinterfaceimpl.h13
-rw-r--r--src/coreclr/vm/readytoruninfo.cpp12
-rw-r--r--src/coreclr/vm/rejit.cpp6
-rw-r--r--src/coreclr/vm/rejit.inl6
-rw-r--r--src/coreclr/vm/runtimehandles.cpp6
-rw-r--r--src/coreclr/vm/threads.cpp27
-rw-r--r--src/coreclr/vm/threads.h34
-rw-r--r--src/coreclr/vm/threadsuspend.cpp56
37 files changed, 1086 insertions, 1264 deletions
diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man
index 79e1f17b069..d8a275c6da6 100644
--- a/src/coreclr/vm/ClrEtwAll.man
+++ b/src/coreclr/vm/ClrEtwAll.man
@@ -87,6 +87,8 @@
message="$(string.RuntimePublisher.TypeDiagnosticKeywordMessage)" symbol="CLR_TYPEDIAGNOSTIC_KEYWORD" />
<keyword name="JitInstrumentationDataKeyword" mask="0x10000000000"
message="$(string.RuntimePublisher.JitInstrumentationDataKeywordMessage)" symbol="CLR_JITINSTRUMENTEDDATA_KEYWORD" />
+ <keyword name="ProfilerKeyword" mask="0x20000000000"
+ message="$(string.RuntimePublisher.ProfilerKeywordMessage)" symbol="CLR_PROFILER_KEYWORD" />
</keywords>
<!--Tasks-->
<tasks>
@@ -429,7 +431,14 @@
<opcode name="ExecutionCheckpoint" message="$(string.RuntimePublisher.ExecutionCheckpointOpcodeMessage)" symbol="CLR_EXECUTIONCHECKPOINT_OPCODE" value="11"> </opcode>
</opcodes>
</task>
- <!--Next available ID is 36-->
+ <task name="Profiler" symbol="CLR_PROFILER_TASK"
+ value="36" eventGUID="{68895E46-FD03-4528-89D2-5E1FBB1D3BCF}"
+ message="$(string.RuntimePublisher.ProfilerTaskMessage)">
+ <opcodes>
+ <opcode name="Profiler" message="$(string.RuntimePublisher.ProfilerOpcodeMessage)" symbol="CLR_PROFILER_OPCODE" value="11"/>
+ </opcodes>
+ </task>
+ <!--Next available ID is 37-->
</tasks>
<!--Maps-->
<maps>
@@ -2896,6 +2905,17 @@
</ExecutionCheckpoint>
</UserData>
</template>
+
+ <template tid="ProfilerMessage">
+ <data name="ClrInstanceID" inType="win:UInt16"/>
+ <data name="Message" inType="win:UnicodeString" />
+ <UserData>
+ <Settings xmlns="myNs">
+ <ClrInstanceID> %1 </ClrInstanceID>
+ <Message> %2 </Message>
+ </Settings>
+ </UserData>
+ </template>
</templates>
<events>
@@ -3921,6 +3941,11 @@
task="JitInstrumentationData"
symbol="JitInstrumentationDataVerbose" message="$(string.RuntimePublisher.JitInstrumentationDataEventMessage)"/>
+ <event value="299" version="0" level="win:Informational" template="ProfilerMessage"
+ keywords ="ProfilerKeyword" opcode="Profiler"
+ task="Profiler"
+ symbol="ProfilerMessage" message="$(string.RuntimePublisher.ProfilerEventMessage)"/>
+
<!-- Execution Checkpoint event 300 -->
<event value="300" version="0" level="win:Informational" template="ExecutionCheckpoint"
keywords ="PerfTrackKeyword" opcode="ExecutionCheckpoint" task="ExecutionCheckpoint" symbol="ExecutionCheckpoint"
@@ -7183,6 +7208,7 @@
<string id="RuntimePublisher.AssemblyLoadFromResolveHandlerInvokedEventMessage" value="ClrInstanceID=%1;%nAssemblyName=%2;%nIsTrackedLoad=%3;%nRequestingAssemblyPath=%4;%nComputedRequestedAssemblyPath=%5" />
<string id="RuntimePublisher.KnownPathProbedEventMessage" value="ClrInstanceID=%1;%nFilePath=%2;%nSource=%3;%nResult=%4" />
<string id="RuntimePublisher.JitInstrumentationDataEventMessage" value="%MethodId=%4" />
+ <string id="RuntimePublisher.ProfilerEventMessage" value="%Message=%2" />
<string id="RuntimePublisher.ResolutionAttemptedEventMessage" value="ClrInstanceID=%1;%nAssemblyName=%2;%nStage=%3;%nAssemblyLoadContext=%4;%nResult=%5;%nResultAssemblyName=%6;%nResultAssemblyPath=%7;%nErrorMessage=%8" />
<string id="RuntimePublisher.StackEventMessage" value="ClrInstanceID=%1;%nReserved1=%2;%nReserved2=%3;%nFrameCount=%4;%nStack=%5" />
<string id="RuntimePublisher.AppDomainMemAllocatedEventMessage" value="AppDomainID=%1;%nAllocated=%2;%nClrInstanceID=%3" />
@@ -7383,6 +7409,7 @@
<string id="RuntimePublisher.TypeLoadTaskMessage" value="TypeLoad" />
<string id="RuntimePublisher.JitInstrumentationDataTaskMessage" value="JitInstrumentationData" />
<string id="RuntimePublisher.ExecutionCheckpointTaskMessage" value="ExecutionCheckpoint" />
+ <string id="RuntimePublisher.ProfilerTaskMessage" value="Profiler" />
<string id="RundownPublisher.EEStartupTaskMessage" value="Runtime" />
<string id="RundownPublisher.MethodTaskMessage" value="Method" />
@@ -7712,6 +7739,7 @@
<string id="RuntimePublisher.MethodDiagnosticKeywordMessage" value="MethodDiagnostic" />
<string id="RuntimePublisher.TypeDiagnosticKeywordMessage" value="TypeDiagnostic" />
<string id="RuntimePublisher.JitInstrumentationDataKeywordMessage" value="JitInstrumentationData" />
+ <string id="RuntimePublisher.ProfilerKeywordMessage" value="Profiler" />
<string id="RuntimePublisher.GenAwareBeginEventMessage" value="NONE" />
<string id="RuntimePublisher.GenAwareEndEventMessage" value="NONE" />
<string id="RundownPublisher.LoaderKeywordMessage" value="Loader" />
@@ -7855,6 +7883,8 @@
<string id="RuntimePublisher.ExecutionCheckpointOpcodeMessage" value="ExecutionCheckpoint" />
+ <string id="RuntimePublisher.ProfilerOpcodeMessage" value="ProfilerMessage" />
+
<string id="RundownPublisher.MethodDCStartOpcodeMessage" value="DCStart" />
<string id="RundownPublisher.MethodDCEndOpcodeMessage" value="DCStop" />
<string id="RundownPublisher.MethodDCStartVerboseOpcodeMessage" value="DCStartVerbose" />
diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp
index 3f7c4deb6b0..f7bf57c5b52 100644
--- a/src/coreclr/vm/appdomain.cpp
+++ b/src/coreclr/vm/appdomain.cpp
@@ -2034,31 +2034,31 @@ void SystemDomain::NotifyProfilerStartup()
CONTRACTL_END;
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System());
- g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System());
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainCreationStarted((AppDomainID) System());
+ END_PROFILER_CALLBACK();
}
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System());
- g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainCreationFinished((AppDomainID) System(), S_OK);
+ END_PROFILER_CALLBACK();
}
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System()->DefaultDomain());
- g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
+ END_PROFILER_CALLBACK();
}
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System()->DefaultDomain());
- g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
+ END_PROFILER_CALLBACK();
}
}
@@ -2073,31 +2073,31 @@ HRESULT SystemDomain::NotifyProfilerShutdown()
CONTRACTL_END;
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System());
- g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System());
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainShutdownStarted((AppDomainID) System());
+ END_PROFILER_CALLBACK();
}
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System());
- g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
+ END_PROFILER_CALLBACK();
}
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System()->DefaultDomain());
- g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
+ END_PROFILER_CALLBACK();
}
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
_ASSERTE(System()->DefaultDomain());
- g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
+ END_PROFILER_CALLBACK();
}
return (S_OK);
}
diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp
index 6f45022d10b..9d4cd4ab7ce 100644
--- a/src/coreclr/vm/assembly.cpp
+++ b/src/coreclr/vm/assembly.cpp
@@ -270,10 +270,10 @@ void ProfilerCallAssemblyUnloadStarted(Assembly* assemblyUnloaded)
{
WRAPPER_NO_CONTRACT;
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
+ BEGIN_PROFILER_CALLBACK(CORProfilerPresent());
GCX_PREEMP();
- g_profControlBlock.pProfInterface->AssemblyUnloadStarted((AssemblyID)assemblyUnloaded);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AssemblyUnloadStarted((AssemblyID)assemblyUnloaded);
+ END_PROFILER_CALLBACK();
}
}
@@ -281,10 +281,10 @@ void ProfilerCallAssemblyUnloadFinished(Assembly* assemblyUnloaded)
{
WRAPPER_NO_CONTRACT;
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
+ BEGIN_PROFILER_CALLBACK(CORProfilerPresent());
GCX_PREEMP();
- g_profControlBlock.pProfInterface->AssemblyUnloadFinished((AssemblyID) assemblyUnloaded, S_OK);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AssemblyUnloadFinished((AssemblyID) assemblyUnloaded, S_OK);
+ END_PROFILER_CALLBACK();
}
}
#endif
@@ -347,10 +347,10 @@ Assembly * Assembly::Create(
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAssemblyLoads());
GCX_COOP();
- g_profControlBlock.pProfInterface->AssemblyLoadStarted((AssemblyID)(Assembly *) pAssembly);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->AssemblyLoadStarted((AssemblyID)(Assembly *) pAssembly);
+ END_PROFILER_CALLBACK();
}
// Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback
@@ -363,11 +363,11 @@ Assembly * Assembly::Create(
EX_HOOK
{
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAssemblyLoads());
GCX_COOP();
- g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID)(Assembly *) pAssembly,
+ (&g_profControlBlock)->AssemblyLoadFinished((AssemblyID)(Assembly *) pAssembly,
GET_EXCEPTION()->GetHR());
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
EX_END_HOOK;
diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp
index 1dff1e92480..a41ed4c81a5 100644
--- a/src/coreclr/vm/ceeload.cpp
+++ b/src/coreclr/vm/ceeload.cpp
@@ -163,10 +163,10 @@ void Module::DoInit(AllocMemTracker *pamTracker, LPCWSTR szName)
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads());
GCX_COOP();
- g_profControlBlock.pProfInterface->ModuleLoadStarted((ModuleID) this);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->ModuleLoadStarted((ModuleID) this);
+ END_PROFILER_CALLBACK();
}
// Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback
EX_TRY
@@ -180,9 +180,9 @@ void Module::DoInit(AllocMemTracker *pamTracker, LPCWSTR szName)
EX_HOOK
{
{
- BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
- g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, GET_EXCEPTION()->GetHR());
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads());
+ (&g_profControlBlock)->ModuleLoadFinished((ModuleID) this, GET_EXCEPTION()->GetHR());
+ END_PROFILER_CALLBACK();
}
}
EX_END_HOOK;
@@ -291,20 +291,20 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr)
BOOL profilerCallbackHappened = FALSE;
// Notify the profiler, this may cause metadata to be updated
{
- BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads());
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, hr);
+ (&g_profControlBlock)->ModuleLoadFinished((ModuleID) this, hr);
if (SUCCEEDED(hr))
{
- g_profControlBlock.pProfInterface->ModuleAttachedToAssembly((ModuleID) this,
+ (&g_profControlBlock)->ModuleAttachedToAssembly((ModuleID) this,
(AssemblyID)m_pAssembly);
}
profilerCallbackHappened = TRUE;
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
// If there are more types than before, add these new types to the
@@ -315,13 +315,13 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr)
}
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAssemblyLoads());
if (IsManifest())
{
GCX_COOP();
- g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID) m_pAssembly, hr);
+ (&g_profControlBlock)->AssemblyLoadFinished((AssemblyID) m_pAssembly, hr);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
}
@@ -1219,7 +1219,7 @@ void Module::Destruct()
LOG((LF_EEMEM, INFO3, "Deleting module %x\n", this));
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads());
if (!IsBeingUnloaded())
{
// Profiler is causing some peripheral class loads. Probably this just needs
@@ -1227,14 +1227,14 @@ void Module::Destruct()
EX_TRY
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
+ (&g_profControlBlock)->ModuleUnloadStarted((ModuleID) this);
}
EX_CATCH
{
}
EX_END_CATCH(SwallowAllExceptions);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -1277,19 +1277,19 @@ void Module::Destruct()
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads());
// Profiler is causing some peripheral class loads. Probably this just needs
// to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
EX_TRY
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ModuleUnloadFinished((ModuleID) this, S_OK);
+ (&g_profControlBlock)->ModuleUnloadFinished((ModuleID) this, S_OK);
}
EX_CATCH
{
}
EX_END_CATCH(SwallowAllExceptions);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
if (m_pValidatedEmitter.Load() != NULL)
@@ -3129,7 +3129,7 @@ void Module::StartUnload()
WRAPPER_NO_CONTRACT;
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads());
if (!IsBeingUnloaded())
{
// Profiler is causing some peripheral class loads. Probably this just needs
@@ -3137,14 +3137,14 @@ void Module::StartUnload()
EX_TRY
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
+ (&g_profControlBlock)->ModuleUnloadStarted((ModuleID) this);
}
EX_CATCH
{
}
EX_END_CATCH(SwallowAllExceptions);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -3607,11 +3607,11 @@ void Module::SetSymbolBytes(LPCBYTE pbSyms, DWORD cbSyms)
IfFailThrow(HRESULT_FROM_WIN32(dwError));
#if PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
- BEGIN_PIN_PROFILER(CORProfilerInMemorySymbolsUpdatesEnabled());
+ BEGIN_PROFILER_CALLBACK(CORProfilerInMemorySymbolsUpdatesEnabled());
{
- g_profControlBlock.pProfInterface->ModuleInMemorySymbolsUpdated((ModuleID) this);
+ (&g_profControlBlock)->ModuleInMemorySymbolsUpdated((ModuleID) this);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
#endif //PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
ETW::CodeSymbolLog::EmitCodeSymbols(this);
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index 14e9dd9da8a..cdc5925234a 100644
--- a/src/coreclr/vm/ceemain.cpp
+++ b/src/coreclr/vm/ceemain.cpp
@@ -703,11 +703,6 @@ void EEStartupHelper()
}
#endif
-#ifdef PROFILING_SUPPORTED
- // The diagnostics server might register a profiler for delayed startup, indicate here that
- // it is not currently set. This will be set to TRUE if a profiler is registered.
- g_profControlBlock.fIsStoredProfilerRegistered = FALSE;
-#endif // PROFILING_SUPPORTED
#ifdef FEATURE_PERFTRACING
DiagnosticServerAdapter::Initialize();
DiagnosticServerAdapter::PauseForDiagnosticsMonitor();
@@ -1404,10 +1399,10 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
// Don't call back in to the profiler if we are being torn down, it might be unloaded
if (!fIsDllUnloading)
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
+ BEGIN_PROFILER_CALLBACK(CORProfilerPresent());
GCX_PREEMP();
- g_profControlBlock.pProfInterface->Shutdown();
- END_PIN_PROFILER();
+ (&g_profControlBlock)->Shutdown();
+ END_PROFILER_CALLBACK();
}
g_fEEShutDown |= ShutDown_Profiler;
diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp
index 17417e0b760..6f2da9db3c2 100644
--- a/src/coreclr/vm/class.cpp
+++ b/src/coreclr/vm/class.cpp
@@ -94,7 +94,7 @@ void EEClass::Destruct(MethodTable * pOwningMT)
#ifdef PROFILING_SUPPORTED
// If profiling, then notify the class is getting unloaded.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackClasses());
{
// Calls to the profiler callback may throw, or otherwise fail, if
// the profiler AVs/throws an unhandled exception/etc. We don't want
@@ -115,7 +115,7 @@ void EEClass::Destruct(MethodTable * pOwningMT)
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ClassUnloadStarted((ClassID) pOwningMT);
+ (&g_profControlBlock)->ClassUnloadStarted((ClassID) pOwningMT);
}
EX_CATCH
{
@@ -125,7 +125,7 @@ void EEClass::Destruct(MethodTable * pOwningMT)
}
EX_END_CATCH(RethrowTerminalExceptions);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -178,7 +178,7 @@ void EEClass::Destruct(MethodTable * pOwningMT)
#ifdef PROFILING_SUPPORTED
// If profiling, then notify the class is getting unloaded.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackClasses());
{
// See comments in the call to ClassUnloadStarted for details on this
// FAULT_NOT_FATAL marker and exception swallowing.
@@ -186,14 +186,14 @@ void EEClass::Destruct(MethodTable * pOwningMT)
EX_TRY
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ClassUnloadFinished((ClassID) pOwningMT, S_OK);
+ (&g_profControlBlock)->ClassUnloadFinished((ClassID) pOwningMT, S_OK);
}
EX_CATCH
{
}
EX_END_CATCH(RethrowTerminalExceptions);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp
index 65692222bb3..62eccc0995f 100644
--- a/src/coreclr/vm/clsload.cpp
+++ b/src/coreclr/vm/clsload.cpp
@@ -3452,7 +3452,7 @@ void ClassLoader::Notify(TypeHandle typeHnd)
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackClasses());
// We don't tell profilers about typedescs, as per IF above. Also, we don't
// tell profilers about:
if (
@@ -3465,7 +3465,7 @@ void ClassLoader::Notify(TypeHandle typeHnd)
{
LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Started1 %p %s\n", pMT, pMT->GetDebugClassName()));
// Record successful load of the class for the profiler
- g_profControlBlock.pProfInterface->ClassLoadStarted(TypeHandleToClassID(typeHnd));
+ (&g_profControlBlock)->ClassLoadStarted(TypeHandleToClassID(typeHnd));
//
// Profiler can turn off TrackClasses during the Started() callback. Need to
@@ -3474,11 +3474,11 @@ void ClassLoader::Notify(TypeHandle typeHnd)
if (CORProfilerTrackClasses())
{
LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Finished1 %p %s\n", pMT, pMT->GetDebugClassName()));
- g_profControlBlock.pProfInterface->ClassLoadFinished(TypeHandleToClassID(typeHnd),
+ (&g_profControlBlock)->ClassLoadFinished(TypeHandleToClassID(typeHnd),
S_OK);
}
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif //PROFILING_SUPPORTED
diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp
index eb5b5abd368..dfee278b891 100644
--- a/src/coreclr/vm/comcallablewrapper.cpp
+++ b/src/coreclr/vm/comcallablewrapper.cpp
@@ -3725,7 +3725,7 @@ BOOL ComMethodTable::LayOutInterfaceMethodTable(MethodTable* pClsMT)
#ifdef PROFILING_SUPPORTED
// Notify profiler of the CCW, so it can avoid double-counting.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackCCW());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackCCW());
#if defined(_DEBUG)
WCHAR rIID[40]; // {00000000-0000-0000-0000-000000000000}
GuidToLPWSTR(m_IID, rIID, lengthof(rIID));
@@ -3735,11 +3735,11 @@ BOOL ComMethodTable::LayOutInterfaceMethodTable(MethodTable* pClsMT)
LOG((LF_CORPROF, LL_INFO100, "COMClassicVTableCreated Class:%#x, IID:{%08x-...}, vTbl:%#08x\n",
pItfClass, m_IID.Data1, pUnkVtable));
#endif
- g_profControlBlock.pProfInterface->COMClassicVTableCreated((ClassID) TypeHandle(pItfClass).AsPtr(),
+ (&g_profControlBlock)->COMClassicVTableCreated((ClassID) TypeHandle(pItfClass).AsPtr(),
m_IID,
pUnkVtable,
m_cbSlots+cbExtraSlots);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -4858,7 +4858,7 @@ ComCallWrapperTemplate* ComCallWrapperTemplate::CreateTemplate(TypeHandle thClas
// Notify profiler of the CCW, so it can avoid double-counting.
if (pTemplate->SupportsIClassX())
{
- BEGIN_PIN_PROFILER(CORProfilerTrackCCW());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackCCW());
// When under the profiler, we'll eagerly generate the IClassX CMT.
pTemplate->GetClassComMT();
@@ -4880,11 +4880,11 @@ ComCallWrapperTemplate* ComCallWrapperTemplate::CreateTemplate(TypeHandle thClas
LOG((LF_CORPROF, LL_INFO100, "COMClassicVTableCreated TypeHandle:%#x, IID:{%08x-...}, vTbl:%#08x\n",
thClass.AsPtr(), IClassXIID.Data1, pComVtable));
#endif
- g_profControlBlock.pProfInterface->COMClassicVTableCreated(
+ (&g_profControlBlock)->COMClassicVTableCreated(
(ClassID) thClass.AsPtr(), IClassXIID, pComVtable,
pTemplate->m_pClassComMT->m_cbSlots +
ComMethodTable::GetNumExtraSlots(pTemplate->m_pClassComMT->GetInterfaceType()));
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
RETURN pTemplate;
diff --git a/src/coreclr/vm/comsynchronizable.cpp b/src/coreclr/vm/comsynchronizable.cpp
index bc79ffcd8fa..39f00d06741 100644
--- a/src/coreclr/vm/comsynchronizable.cpp
+++ b/src/coreclr/vm/comsynchronizable.cpp
@@ -1009,16 +1009,16 @@ void QCALLTYPE ThreadNative::InformThreadNameChange(QCall::ThreadHandle thread,
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackThreads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads());
if (name == NULL)
{
- g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, 0, NULL);
+ (&g_profControlBlock)->ThreadNameChanged((ThreadID)pThread, 0, NULL);
}
else
{
- g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, len, (WCHAR*)name);
+ (&g_profControlBlock)->ThreadNameChanged((ThreadID)pThread, len, (WCHAR*)name);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
diff --git a/src/coreclr/vm/crossgencompile.cpp b/src/coreclr/vm/crossgencompile.cpp
index 1e14e79be7f..df3555e31a7 100644
--- a/src/coreclr/vm/crossgencompile.cpp
+++ b/src/coreclr/vm/crossgencompile.cpp
@@ -123,7 +123,7 @@ DWORD GetCurrentExceptionCode()
// disable PROFILING_SUPPORTED for crossgen because of it affects data layout and FCall tables.
//
-UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction)
+UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL *pbHookFunction)
{
UNREACHABLE();
}
diff --git a/src/coreclr/vm/eetoprofinterfaceimpl.cpp b/src/coreclr/vm/eetoprofinterfaceimpl.cpp
index 34cd1475a42..745f2b6ef1c 100644
--- a/src/coreclr/vm/eetoprofinterfaceimpl.cpp
+++ b/src/coreclr/vm/eetoprofinterfaceimpl.cpp
@@ -103,15 +103,17 @@ enum ClrToProfEntrypointFlags
};
#define ASSERT_EVAC_COUNTER_NONZERO() \
- _ASSERTE((GetThreadNULLOk() == NULL) || \
- (GetThreadNULLOk()->GetProfilerEvacuationCounter() != 0U))
+ _ASSERTE(m_pProfilerInfo->dwProfilerEvacuationCounter.Load() > 0)
#define CHECK_PROFILER_STATUS(ee2pFlags) \
/* If one of these asserts fires, perhaps you forgot to use */ \
- /* BEGIN/END_PIN_PROFILER */ \
+ /* BEGIN/END_PROFILER_CALLBACK */ \
ASSERT_EVAC_COUNTER_NONZERO(); \
- _ASSERTE(g_profControlBlock.pProfInterface.Load() != NULL); \
- _ASSERTE(g_profControlBlock.pProfInterface == this); \
+ /* Either we are initializing, or we have the ProfToEEInterfaceImpl */ \
+ _ASSERTE((((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) || (m_pProfilerInfo->pProfInterface.Load() != NULL)); \
+ /* If we are initializing, null is fine. Otherwise we want to make sure we haven't messed up the association between */ \
+ /* EEToProfInterfaceImpl/ProfToEEInterfaceImpl somehow. */ \
+ _ASSERTE((((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) || (m_pProfilerInfo->pProfInterface == this)); \
/* Early abort if... */ \
if ( \
/* Profiler isn't active, */ \
@@ -121,7 +123,7 @@ enum ClrToProfEntrypointFlags
/* on a detaching profiler, and b) the profiler is detaching */ \
!( \
(((ee2pFlags) & kEE2PAllowableWhileDetaching) != 0) && \
- (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \
+ (m_pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching) \
) && \
\
/* and it's not the case that both a) this callback is allowed */ \
@@ -129,9 +131,9 @@ enum ClrToProfEntrypointFlags
!( \
(((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) && \
( \
- (g_profControlBlock.curProfStatus.Get() \
+ (m_pProfilerInfo->curProfStatus.Get() \
== kProfStatusInitializingForStartupLoad) || \
- (g_profControlBlock.curProfStatus.Get() \
+ (m_pProfilerInfo->curProfStatus.Get() \
== kProfStatusInitializingForAttachLoad) \
) \
) \
@@ -412,14 +414,13 @@ EEToProfInterfaceImpl::EEToProfInterfaceImpl() :
m_pCallback8(NULL),
m_pCallback9(NULL),
m_pCallback10(NULL),
+ m_pCallback11(NULL),
m_hmodProfilerDLL(NULL),
m_fLoadedViaAttach(FALSE),
m_pProfToEE(NULL),
m_pProfilersFuncIDMapper(NULL),
m_pProfilersFuncIDMapper2(NULL),
m_pProfilersFuncIDMapper2ClientData(NULL),
- m_GUID(k_guidZero),
- m_lGUIDCount(0),
m_pGCRefDataFreeList(NULL),
m_csGCRefDataFreeList(NULL),
m_pEnter(NULL),
@@ -437,6 +438,7 @@ EEToProfInterfaceImpl::EEToProfInterfaceImpl() :
m_pTailcall3WithInfo(NULL),
m_fUnrevertiblyModifiedIL(FALSE),
m_fModifiedRejitState(FALSE),
+ m_pProfilerInfo(NULL),
m_pFunctionIDHashTable(NULL),
m_pFunctionIDHashTableRWLock(NULL),
m_dwConcurrentGCWaitTimeoutInMs(INFINITE),
@@ -585,6 +587,12 @@ HRESULT EEToProfInterfaceImpl::Init(
return S_OK;
}
+void EEToProfInterfaceImpl::SetProfilerInfo(ProfilerInfo *pProfilerInfo)
+{
+ LIMITED_METHOD_CONTRACT;
+ m_pProfilerInfo = pProfilerInfo;
+ m_pProfToEE->SetProfilerInfo(pProfilerInfo);
+}
//---------------------------------------------------------------------------------------
//
@@ -660,18 +668,39 @@ HRESULT EEToProfInterfaceImpl::CreateProfiler(
// ATTENTION: Please update EEToProfInterfaceImpl::~EEToProfInterfaceImpl() after adding the next ICorProfilerCallback interface here !!!
- // The profiler may optionally support ICorProfilerCallback3,4,5,6,7,8,9,10. Let's check.
- ReleaseHolder<ICorProfilerCallback10> pCallback10;
+ // The profiler may optionally support ICorProfilerCallback3,4,5,6,7,8,9,10,11. Let's check.
+ ReleaseHolder<ICorProfilerCallback11> pCallback11;
hr = m_pCallback2->QueryInterface(
- IID_ICorProfilerCallback10,
- (LPVOID *)&pCallback10);
- if (SUCCEEDED(hr) && (pCallback10 != NULL))
+ IID_ICorProfilerCallback11,
+ (LPVOID *)&pCallback11);
+ if (SUCCEEDED(hr) && (pCallback11 != NULL))
+ {
+ _ASSERTE(m_pCallback11 == NULL);
+ m_pCallback11 = pCallback11.Extract();
+ pCallback11 = NULL;
+ }
+
+ if (m_pCallback11 == NULL)
+ {
+ ReleaseHolder<ICorProfilerCallback10> pCallback10;
+ hr = m_pCallback2->QueryInterface(
+ IID_ICorProfilerCallback10,
+ (LPVOID *)&pCallback10);
+ if (SUCCEEDED(hr) && (pCallback10 != NULL))
+ {
+ _ASSERTE(m_pCallback10 == NULL);
+ m_pCallback10 = pCallback10.Extract();
+ pCallback10 = NULL;
+ }
+ }
+ else
{
_ASSERTE(m_pCallback10 == NULL);
- m_pCallback10 = pCallback10.Extract();
- pCallback10 = NULL;
+ m_pCallback10 = static_cast<ICorProfilerCallback10 *>(m_pCallback11);
+ m_pCallback10->AddRef();
}
+
// Due to inheritance, if we have an interface we must also have
// all the previous versions
if (m_pCallback10 == NULL)
@@ -847,7 +876,7 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
// scan through list of detaching profilers to make sure none of them give a
// GetEEToProfPtr() equal to this
#ifdef FEATURE_PROFAPI_ATTACH_DETACH
- _ASSERTE(ProfilingAPIDetach::GetEEToProfPtr() == NULL);
+ _ASSERTE(!ProfilingAPIDetach::IsEEToProfPtrRegisteredForDetach(this));
#endif // FEATURE_PROFAPI_ATTACH_DETACH
// Release user-specified profiler DLL
@@ -912,6 +941,12 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
m_pCallback10 = NULL;
}
+ if (m_pCallback11 != NULL)
+ {
+ m_pCallback11->Release();
+ m_pCallback11 = NULL;
+ }
+
// Only unload the V4 profiler if this is not part of shutdown. This protects
// Whidbey profilers that aren't used to being FreeLibrary'd.
if (fIsV4Profiler && !g_fEEShutDown)
@@ -972,8 +1007,6 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
m_pSavedAllocDataBlock = NULL;
}
- m_GUID = k_guidZero;
-
if (m_csGCRefDataFreeList != NULL)
{
ClrDeleteCriticalSection(m_csGCRefDataFreeList);
@@ -993,70 +1026,6 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
}
}
-
-
-//---------------------------------------------------------------------------------------
-//
-// Initialize the GUID used for the cookie in remoting callbacks. If already
-// initialized, this just does nothing and returns S_OK.
-//
-// Return Value:
-// HRESULT indicating success or failure. If the GUID was already initialized,
-// just returns S_OK
-//
-//
-
-HRESULT EEToProfInterfaceImpl::InitGUID()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- CANNOT_TAKE_LOCK;
- ASSERT_NO_EE_LOCKS_HELD();
- }
- CONTRACTL_END;
-
- if (IsEqualGUID(m_GUID, k_guidZero))
- {
- return CoCreateGuid(&m_GUID);
- }
-
- return S_OK;
-}
-
-//---------------------------------------------------------------------------------------
-//
-// Returns a GUID suitable for use as a remoting callback cookie for this thread.
-// The GUID is based on the template GUID (m_GUID), the current thread, and
-// a counter.
-//
-// Arguments:
-// pGUID - [out] The GUID requested
-//
-
-void EEToProfInterfaceImpl::GetGUID(GUID * pGUID)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- ASSERT_NO_EE_LOCKS_HELD();
- }
- CONTRACTL_END;
-
- // the member GUID and the argument should both be valid
- _ASSERTE(!(IsEqualGUID(m_GUID, k_guidZero)));
- _ASSERTE(pGUID);
-
- // Copy the contents of the template GUID
- memcpy(pGUID, &m_GUID, sizeof(GUID));
-
- // Adjust the last two bytes
- pGUID->Data4[6] = (BYTE) GetCurrentThreadId();
- pGUID->Data4[7] = (BYTE) InterlockedIncrement((LPLONG)&m_lGUIDCount);
-}
-
//---------------------------------------------------------------------------------------
//
// Wrapper around calling profiler's FunctionIDMapper hook. Called by JIT.
@@ -1955,14 +1924,13 @@ HRESULT EEToProfInterfaceImpl::EnsureProfilerDetachable()
{
LIMITED_METHOD_CONTRACT;
- if (((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0) ||
- ((g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) != 0))
+ if (m_pProfilerInfo->eventMask.IsEventMaskSet(COR_PRF_MONITOR_IMMUTABLE) ||
+ m_pProfilerInfo->eventMask.IsEventMaskHighSet(COR_PRF_HIGH_MONITOR_IMMUTABLE))
{
LOG((
LF_CORPROF,
LL_ERROR,
- "**PROF: Profiler may not detach because it set an immutable flag. Flags = 0x%x.\n",
- g_profControlBlock.dwEventMask));
+ "**PROF: Profiler may not detach because it set an immutable flag.\n"));
return CORPROF_E_IMMUTABLE_FLAGS_SET;
}
@@ -2172,6 +2140,15 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
}
CONTRACTL_END;
+ BOOL isMainProfiler = g_profControlBlock.IsMainProfiler(this);
+
+ if (!isMainProfiler &&
+ ((dwEventMask & ~COR_PRF_ALLOWABLE_NOTIFICATION_PROFILER)
+ || (dwEventMaskHigh & ~COR_PRF_HIGH_ALLOWABLE_NOTIFICATION_PROFILER)))
+ {
+ return E_INVALIDARG;
+ }
+
static const DWORD kEventFlagsRequiringSlowPathEnterLeaveHooks =
COR_PRF_ENABLE_FUNCTION_ARGS |
COR_PRF_ENABLE_FUNCTION_RETVAL |
@@ -2222,17 +2199,17 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
// not trying to set an immutable attribute
// FUTURE: If we add immutable flags to the high event mask, this would be a good
// place to check for them as well.
- if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
+ if (m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
{
#ifdef _DEBUG
if (((dwEventMask & dwImmutableEventFlags) !=
- (g_profControlBlock.dwEventMask & dwImmutableEventFlags)) ||
+ (m_pProfilerInfo->eventMask.GetEventMask() & dwImmutableEventFlags)) ||
#else //!_DEBUG
if (((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) !=
- (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE)) ||
+ (m_pProfilerInfo->eventMask.GetEventMask() & COR_PRF_MONITOR_IMMUTABLE)) ||
#endif //_DEBUG
((dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) !=
- (g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE)))
+ (m_pProfilerInfo->eventMask.GetEventMaskHigh() & COR_PRF_HIGH_MONITOR_IMMUTABLE)))
{
// FUTURE: Should we have a dedicated HRESULT for setting immutable flag?
return E_FAIL;
@@ -2254,7 +2231,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
// After fast path ELT hooks are set in Initial callback, the startup profiler is not allowed to change flags
// that require slow path ELT hooks or disable ELT hooks.
- if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
+ if ((m_pProfilerInfo->curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
(
(m_pEnter3 != NULL) ||
(m_pLeave3 != NULL) ||
@@ -2266,13 +2243,13 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
)
)
{
- _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0);
+ _ASSERTE(!m_pProfilerInfo->eventMask.IsEventMaskSet(kEventFlagsRequiringSlowPathEnterLeaveHooks));
return CORPROF_E_INCONSISTENT_WITH_FLAGS;
}
// After slow path ELT hooks are set in Initial callback, the startup profiler is not allowed to remove
// all flags that require slow path ELT hooks or to change the flag to disable the ELT hooks.
- if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
+ if ((m_pProfilerInfo->curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
(
(m_pEnter3WithInfo != NULL) ||
(m_pLeave3WithInfo != NULL) ||
@@ -2284,7 +2261,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
)
)
{
- _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0);
+ _ASSERTE(m_pProfilerInfo->eventMask.IsEventMaskSet(kEventFlagsRequiringSlowPathEnterLeaveHooks));
return CORPROF_E_INCONSISTENT_WITH_FLAGS;
}
@@ -2295,7 +2272,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
(
(
// Old flags
- ((g_profControlBlock.dwEventMask & kEventFlagsAffectingEnterLeaveHooks) ^
+ ((m_pProfilerInfo->eventMask.GetEventMask() & kEventFlagsAffectingEnterLeaveHooks) ^
// XORed w/ the new flags
(dwEventMask & kEventFlagsAffectingEnterLeaveHooks))
) != 0
@@ -2316,13 +2293,18 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
(m_pTailcall != NULL)
);
+ if (fEnterLeaveHooksAffected && !isMainProfiler)
+ {
+ return E_INVALIDARG;
+ }
+
BOOL fNeedToTurnOffConcurrentGC = FALSE;
if (((dwEventMask & COR_PRF_MONITOR_GC) != 0) &&
- ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_GC) == 0))
+ ((m_pProfilerInfo->eventMask.GetEventMask() & COR_PRF_MONITOR_GC) == 0))
{
// We don't need to worry about startup load as we'll turn off concurrent GC later
- if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
+ if (m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
{
// Since we're not an initializing startup profiler, the EE must be fully started up
// so we can check whether concurrent GC is on
@@ -2341,7 +2323,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
// If we are attaching and we are turning on COR_PRF_MONITOR_GC, turn off concurrent GC later
// in this function
- if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForAttachLoad)
+ if (m_pProfilerInfo->curProfStatus.Get() == kProfStatusInitializingForAttachLoad)
{
if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
{
@@ -2375,12 +2357,12 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
if ((dwEventMask & COR_PRF_ENABLE_REJIT) != 0)
{
- if ((g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad) && !ReJitManager::IsReJITEnabled())
+ if ((m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad) && !ReJitManager::IsReJITEnabled())
{
return CORPROF_E_REJIT_NOT_ENABLED;
}
- g_profControlBlock.pProfInterface->SetModifiedRejitState();
+ m_pProfilerInfo->pProfInterface->SetModifiedRejitState();
}
// High event bits
@@ -2398,8 +2380,10 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
}
// Now save the modified masks
- g_profControlBlock.dwEventMask = dwEventMask;
- g_profControlBlock.dwEventMaskHigh = dwEventMaskHigh;
+ m_pProfilerInfo->eventMask.SetEventMask(dwEventMask);
+ m_pProfilerInfo->eventMask.SetEventMaskHigh(dwEventMaskHigh);
+
+ g_profControlBlock.UpdateGlobalEventMask();
if (fEnterLeaveHooksAffected)
{
@@ -2410,26 +2394,13 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
}
}
- if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad)
- {
- // If the profiler has requested remoting cookies so that it can
- // track logical call stacks, then we must initialize the cookie
- // template.
- if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_REMOTING_COOKIE)
- == COR_PRF_MONITOR_REMOTING_COOKIE)
- {
- hr = InitGUID();
- if (FAILED(hr))
- {
- return hr;
- }
- }
- }
-
// Turn off concurrent GC as the last step so that we don't need to turn it back on if something
// else failed after that
if (fNeedToTurnOffConcurrentGC)
{
+ // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling
+ g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE;
+
// Turn off concurrent GC if it is on so that user can walk the heap safely in GC callbacks
IGCHeap * pGCHeap = GCHeapUtilities::GetGCHeap();
@@ -2460,13 +2431,14 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
m_bHasTimedOutWaitingForConcurrentGC = TRUE;
}
+ // TODO: think about race conditions... I am pretty sure there is one
+ // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling
+ g_profControlBlock.fConcurrentGCDisabledForAttach = FALSE;
pGCHeap->TemporaryEnableConcurrentGC();
+
return hr;
}
- // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling
- g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE;
-
LOG((LF_CORPROF, LL_INFO10, "**PROF: Concurrent GC has been turned off at attach.\n"));
}
@@ -5339,290 +5311,6 @@ HRESULT EEToProfInterfaceImpl::RuntimeThreadResumed(ThreadID resumedThreadId)
}
//---------------------------------------------------------------------------------------
-// REMOTING
-//
-
-HRESULT EEToProfInterfaceImpl::RemotingClientInvocationStarted()
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingClientInvocationStarted. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingClientInvocationStarted();
- }
-}
-
-HRESULT EEToProfInterfaceImpl::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync)
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingClientSendingMessage. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingClientSendingMessage(pCookie, fIsAsync);
- }
-}
-
-HRESULT EEToProfInterfaceImpl::RemotingClientReceivingReply(GUID * pCookie, BOOL fIsAsync)
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingClientReceivingReply. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingClientReceivingReply(pCookie, fIsAsync);
- }
-}
-
-HRESULT EEToProfInterfaceImpl::RemotingClientInvocationFinished()
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingClientInvocationFinished. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingClientInvocationFinished();
- }
-}
-
-HRESULT EEToProfInterfaceImpl::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync)
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingServerReceivingMessage. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingServerReceivingMessage(pCookie, fIsAsync);
- }
-}
-
-HRESULT EEToProfInterfaceImpl::RemotingServerInvocationStarted()
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingServerInvocationStarted. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingServerInvocationStarted();
- }
-}
-
-HRESULT EEToProfInterfaceImpl::RemotingServerInvocationReturned()
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingServerInvocationReturned. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingServerInvocationReturned();
- }
-}
-
-HRESULT EEToProfInterfaceImpl::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync)
-{
- CONTRACTL
- {
- // Yay!
- NOTHROW;
-
- // Yay!
- GC_TRIGGERS;
-
- // Yay!
- MODE_PREEMPTIVE;
-
- // Yay!
- CAN_TAKE_LOCK;
-
- // Yay!
- ASSERT_NO_EE_LOCKS_HELD();
-
- }
- CONTRACTL_END;
-
- CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
- LL_INFO1000,
- "**PROF: RemotingServerSendingReply. ThreadID: 0x%p\n",
- GetThreadNULLOk()));
-
- {
- // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
- // whose try/catch blocks aren't visible to the contract system
- PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
- return m_pCallback2->RemotingServerSendingReply(pCookie, fIsAsync);
- }
-}
-
-//---------------------------------------------------------------------------------------
// GC EVENTS
//
@@ -6354,4 +6042,31 @@ HRESULT EEToProfInterfaceImpl::EventPipeProviderCreated(EventPipeProvider *provi
#endif // FEATURE_PERFTRACING
}
+HRESULT EEToProfInterfaceImpl::LoadAsNotficationOnly(BOOL *pbNotificationOnly)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // This one API is special, we call in to the profiler before we've set up any of our
+ // machinery to do asserts (m_pProfilerInfo in specific). So we can't use
+ // CLR_TO_PROFILER_ENTRYPOINT here.
+
+ LOG((LF_CORPROF,
+ LL_INFO1000,
+ "**PROF: LoadAsNotficationOnly.\n"));
+
+ if (m_pCallback11 == NULL)
+ {
+ *pbNotificationOnly = FALSE;
+ return S_OK;
+ }
+
+ return m_pCallback11->LoadAsNotficationOnly(pbNotificationOnly);
+}
+
#endif // PROFILING_SUPPORTED
diff --git a/src/coreclr/vm/eetoprofinterfaceimpl.h b/src/coreclr/vm/eetoprofinterfaceimpl.h
index c43b8599465..4ec468a4150 100644
--- a/src/coreclr/vm/eetoprofinterfaceimpl.h
+++ b/src/coreclr/vm/eetoprofinterfaceimpl.h
@@ -33,10 +33,9 @@ class ProfToEEInterfaceImpl;
interface IAssemblyBindingClosure;
struct AssemblyReferenceClosureWalkContextForProfAPI;
-const GUID k_guidZero = {0};
-
class EEToProfInterfaceImpl
{
+ friend class ProfControlBlock;
public:
//
@@ -54,6 +53,8 @@ public:
BOOL fLoadedViaAttach,
DWORD dwConcurrentGCWaitTimeoutInMs);
+ void SetProfilerInfo(ProfilerInfo *pProfilerInfo);
+
BOOL IsCallback3Supported();
BOOL IsCallback4Supported();
BOOL IsCallback5Supported();
@@ -118,15 +119,6 @@ public:
UINT_PTR EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction);
- // This fills in the non call-specific portions of the cookie GUID.
- // This should only be called once at startup if necessary.
- HRESULT InitGUID();
-
- // This will assign a mostly-unique GUID. If enough calls to GetGUID
- // are made from the same thread, then the GUIDs will cycle.
- // (Current, it will cycle every 256 calls)
- void GetGUID(GUID * pGUID);
-
//
// Initialize callback
//
@@ -377,31 +369,6 @@ public:
/* [in] */ void * pVTable);
//
- // Remoting Events
- //
-
- HRESULT RemotingClientInvocationStarted();
-
- HRESULT RemotingClientSendingMessage(GUID * pCookie,
- BOOL fIsAsync);
-
- HRESULT RemotingClientReceivingReply(GUID * pCookie,
- BOOL fIsAsync);
-
- HRESULT RemotingClientInvocationFinished();
-
- HRESULT RemotingServerReceivingMessage(GUID * pCookie,
- BOOL fIsAsync);
-
- HRESULT RemotingServerInvocationStarted();
-
- HRESULT RemotingServerInvocationReturned();
-
- HRESULT RemotingServerSendingReply(GUID * pCookie,
- BOOL fIsAsync);
-
-
- //
// GC Events
//
@@ -507,6 +474,8 @@ public:
HRESULT EventPipeProviderCreated(EventPipeProvider *provider);
+ HRESULT LoadAsNotficationOnly(BOOL *pbNotificationOnly);
+
private:
//
@@ -578,6 +547,7 @@ private:
ICorProfilerCallback8 * m_pCallback8;
ICorProfilerCallback9 * m_pCallback9;
ICorProfilerCallback10 * m_pCallback10;
+ ICorProfilerCallback11 * m_pCallback11;
HMODULE m_hmodProfilerDLL;
@@ -589,13 +559,6 @@ private:
FunctionIDMapper2 * m_pProfilersFuncIDMapper2;
void * m_pProfilersFuncIDMapper2ClientData;
- // This is used as a cookie template for remoting calls
- GUID m_GUID;
-
- // This is an incrementing counter for constructing unique GUIDS from
- // m_GUID
- LONG m_lGUIDCount;
-
// This will contain a list of free ref data structs, so they
// don't have to be re-allocated on every GC
GCReferencesData * m_pGCRefDataFreeList;
@@ -628,6 +591,7 @@ private:
// Remember whether the profiler has enabled Rejit, and prevent detach if it has.
BOOL m_fModifiedRejitState;
+ ProfilerInfo *m_pProfilerInfo;
GCReferencesData * AllocateMovedReferencesData();
diff --git a/src/coreclr/vm/eetoprofinterfaceimpl.inl b/src/coreclr/vm/eetoprofinterfaceimpl.inl
index 48a07b5a237..1ed73db1f58 100644
--- a/src/coreclr/vm/eetoprofinterfaceimpl.inl
+++ b/src/coreclr/vm/eetoprofinterfaceimpl.inl
@@ -247,7 +247,7 @@ inline BOOL EEToProfInterfaceImpl::RequiresGenericsContextForEnterLeave()
return
CORProfilerPresent() &&
- ((g_profControlBlock.dwEventMask & COR_PRF_ENABLE_FRAME_INFO) != 0) &&
+ ((&g_profControlBlock)->globalEventMask.IsEventMaskSet(COR_PRF_ENABLE_FRAME_INFO)) &&
(
(m_pEnter2 != NULL) ||
(m_pLeave2 != NULL) ||
diff --git a/src/coreclr/vm/eetoprofinterfacewrapper.inl b/src/coreclr/vm/eetoprofinterfacewrapper.inl
index bdf328e4c7a..afa00001b17 100644
--- a/src/coreclr/vm/eetoprofinterfacewrapper.inl
+++ b/src/coreclr/vm/eetoprofinterfacewrapper.inl
@@ -32,15 +32,15 @@ class EEToProfilerExceptionInterfaceWrapper
{
WRAPPER_NO_CONTRACT;
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
_ASSERTE(pThread->PreemptiveGCDisabled());
// Get a reference to the object that won't move
OBJECTREF thrown = pThread->GetThrowable();
- g_profControlBlock.pProfInterface->ExceptionThrown(
+ (&g_profControlBlock)->ExceptionThrown(
reinterpret_cast<ObjectID>((*(BYTE **)&thrown)));
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -53,14 +53,14 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the function being searched for a handler.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunction->IsNoMetadata())
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ExceptionSearchFunctionEnter(
+ (&g_profControlBlock)->ExceptionSearchFunctionEnter(
(FunctionID) pFunction);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -69,13 +69,13 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the function being searched for a handler.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunction->IsNoMetadata())
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ExceptionSearchFunctionLeave();
+ (&g_profControlBlock)->ExceptionSearchFunctionLeave();
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -84,14 +84,14 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the filter.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunc->IsNoMetadata())
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ExceptionSearchFilterEnter(
+ (&g_profControlBlock)->ExceptionSearchFilterEnter(
(FunctionID) pFunc);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -100,10 +100,10 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the filter.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ExceptionSearchFilterLeave();
- END_PIN_PROFILER();
+ (&g_profControlBlock)->ExceptionSearchFilterLeave();
+ END_PROFILER_CALLBACK();
}
}
@@ -111,14 +111,14 @@ class EEToProfilerExceptionInterfaceWrapper
{
WRAPPER_NO_CONTRACT;
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunc->IsNoMetadata())
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ExceptionSearchCatcherFound(
+ (&g_profControlBlock)->ExceptionSearchCatcherFound(
(FunctionID) pFunc);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -130,13 +130,13 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the function being searched for a handler.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunc->IsNoMetadata())
{
- g_profControlBlock.pProfInterface->ExceptionUnwindFunctionEnter(
+ (&g_profControlBlock)->ExceptionUnwindFunctionEnter(
(FunctionID) pFunc);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -145,12 +145,12 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler that searching this function is over.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunction->IsNoMetadata())
{
- g_profControlBlock.pProfInterface->ExceptionUnwindFunctionLeave();
+ (&g_profControlBlock)->ExceptionUnwindFunctionLeave();
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -159,13 +159,13 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the function being searched for a handler.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunc->IsNoMetadata())
{
- g_profControlBlock.pProfInterface->ExceptionUnwindFinallyEnter(
+ (&g_profControlBlock)->ExceptionUnwindFinallyEnter(
(FunctionID) pFunc);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -174,9 +174,9 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the function being searched for a handler.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
- g_profControlBlock.pProfInterface->ExceptionUnwindFinallyLeave();
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
+ (&g_profControlBlock)->ExceptionUnwindFinallyLeave();
+ END_PROFILER_CALLBACK();
}
}
@@ -185,7 +185,7 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
if (!pFunc->IsNoMetadata())
{
// <TODO>Remove the thrown variable as well as the
@@ -197,13 +197,13 @@ class EEToProfilerExceptionInterfaceWrapper
GCPROTECT_BEGIN(thrown);
thrown = pThread->GetThrowable();
{
- g_profControlBlock.pProfInterface->ExceptionCatcherEnter(
+ (&g_profControlBlock)->ExceptionCatcherEnter(
(FunctionID) pFunc,
reinterpret_cast<ObjectID>((*(BYTE **)&thrown)));
}
GCPROTECT_END();
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
@@ -212,9 +212,9 @@ class EEToProfilerExceptionInterfaceWrapper
WRAPPER_NO_CONTRACT;
// Notify the profiler of the function being searched for a handler.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackExceptions());
- g_profControlBlock.pProfInterface->ExceptionCatcherLeave();
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions());
+ (&g_profControlBlock)->ExceptionCatcherLeave();
+ END_PROFILER_CALLBACK();
}
}
diff --git a/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h
index 58263ae1a79..8094d7b22d9 100644
--- a/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h
+++ b/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h
@@ -310,10 +310,12 @@ ds_rt_profiler_startup (DiagnosticsStartupProfilerCommandPayload *payload)
STATIC_CONTRACT_NOTHROW;
HRESULT hr = S_OK;
- EX_TRY {
- memcpy(&(g_profControlBlock.clsStoredProfilerGuid), reinterpret_cast<const CLSID *>(ds_startup_profiler_command_payload_get_profiler_guid_cref (payload)), sizeof(CLSID));
- g_profControlBlock.sStoredProfilerPath.Set(reinterpret_cast<LPCWSTR>(ds_startup_profiler_command_payload_get_profiler_path (payload)));
- g_profControlBlock.fIsStoredProfilerRegistered = TRUE;
+ EX_TRY {
+ StoredProfilerNode *profilerData = new StoredProfilerNode();
+ profilerData->guid = *(reinterpret_cast<const CLSID *>(ds_startup_profiler_command_payload_get_profiler_guid_cref (payload)));
+ profilerData->path.Set(reinterpret_cast<LPCWSTR>(ds_startup_profiler_command_payload_get_profiler_path (payload)));
+
+ g_profControlBlock.storedProfilers.InsertHead(profilerData);
}
EX_CATCH_HRESULT (hr);
diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h
index be90259da1d..607286d048b 100644
--- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h
+++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h
@@ -1661,9 +1661,9 @@ ep_rt_notify_profiler_provider_created (EventPipeProvider *provider)
#ifndef DACCESS_COMPILE
// Let the profiler know the provider has been created so it can register if it wants to
- BEGIN_PIN_PROFILER (CORProfilerIsMonitoringEventPipe ());
- g_profControlBlock.pProfInterface->EventPipeProviderCreated (provider);
- END_PIN_PROFILER ();
+ BEGIN_PROFILER_CALLBACK (CORProfilerTrackEventPipe ());
+ (&g_profControlBlock)->EventPipeProviderCreated (provider);
+ END_PROFILER_CALLBACK ();
#endif // DACCESS_COMPILE
}
diff --git a/src/coreclr/vm/eventpipeadapter.h b/src/coreclr/vm/eventpipeadapter.h
index 1510622a265..28a0c9fb1d6 100644
--- a/src/coreclr/vm/eventpipeadapter.h
+++ b/src/coreclr/vm/eventpipeadapter.h
@@ -200,7 +200,8 @@ public:
EventPipeSerializationFormat format,
const bool rundownRequested,
IpcStream *const stream,
- EventPipeSessionSynchronousCallback callback)
+ EventPipeSessionSynchronousCallback callback,
+ void *callbackAdditionalData)
{
CONTRACTL
{
@@ -222,7 +223,8 @@ public:
format,
rundownRequested,
stream,
- callback);
+ callback,
+ callbackAdditionalData);
ep_rt_utf8_string_free (outputPathUTF8);
return result;
}
diff --git a/src/coreclr/vm/eventpipeinternal.cpp b/src/coreclr/vm/eventpipeinternal.cpp
index 7d0e429be2e..7097cb6208d 100644
--- a/src/coreclr/vm/eventpipeinternal.cpp
+++ b/src/coreclr/vm/eventpipeinternal.cpp
@@ -42,6 +42,7 @@ UINT64 QCALLTYPE EventPipeInternal::Enable(
format,
true,
nullptr,
+ nullptr,
nullptr);
EventPipeAdapter::StartStreaming(sessionID);
}
diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp
index 99620ac07e2..14bd22538d2 100644
--- a/src/coreclr/vm/eventtrace.cpp
+++ b/src/coreclr/vm/eventtrace.cpp
@@ -682,13 +682,13 @@ void ETW::GCLog::MovedReference(
// ProfAPI
if (fAllowProfApiNotification)
{
- BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects());
- g_profControlBlock.pProfInterface->MovedReference(pbMemBlockStart,
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects());
+ (&g_profControlBlock)->MovedReference(pbMemBlockStart,
pbMemBlockEnd,
cbRelocDistance,
&(pCtxForEtwAndProfapi->pctxProfAPI),
fCompacting);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -808,9 +808,9 @@ VOID ETW::GCLog::EndMovedReferences(size_t profilingContext, BOOL fAllowProfApiN
// ProfAPI
if (fAllowProfApiNotification)
{
- BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects());
- g_profControlBlock.pProfInterface->EndMovedReferences(&(pCtxForEtwAndProfapi->pctxProfAPI));
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects());
+ (&g_profControlBlock)->EndMovedReferences(&(pCtxForEtwAndProfapi->pctxProfAPI));
+ END_PROFILER_CALLBACK();
}
#endif //PROFILING_SUPPORTED
diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp
index 4df3e3ae1cb..5be5bc2d9ec 100644
--- a/src/coreclr/vm/gcenv.ee.cpp
+++ b/src/coreclr/vm/gcenv.ee.cpp
@@ -559,7 +559,7 @@ BOOL ProfilerShouldTrackConditionalWeakTableElements()
void ProfilerEndConditionalWeakTableElementReferences(void* heapId)
{
#if defined (GC_PROFILING)
- g_profControlBlock.pProfInterface->EndConditionalWeakTableElementReferences(heapId);
+ (&g_profControlBlock)->EndConditionalWeakTableElementReferences(heapId);
#else
UNREFERENCED_PARAMETER(heapId);
#endif // defined (GC_PROFILING)
@@ -570,7 +570,7 @@ void ProfilerEndConditionalWeakTableElementReferences(void* heapId)
void ProfilerEndRootReferences2(void* heapId)
{
#if defined (GC_PROFILING)
- g_profControlBlock.pProfInterface->EndRootReferences2(heapId);
+ (&g_profControlBlock)->EndRootReferences2(heapId);
#else
UNREFERENCED_PARAMETER(heapId);
#endif // defined (GC_PROFILING)
@@ -603,24 +603,24 @@ void ScanHandleForProfilerAndETW(Object** pRef, Object* pSec, uint32_t flags, Sc
{
if (!isDependent)
{
- BEGIN_PIN_PROFILER(CORProfilerTrackGC());
- g_profControlBlock.pProfInterface->RootReference2(
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC());
+ (&g_profControlBlock)->RootReference2(
(uint8_t *)*pRef,
kEtwGCRootKindHandle,
(EtwGCRootFlags)flags,
pRef,
&pSC->pHeapId);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
else
{
- BEGIN_PIN_PROFILER(CORProfilerTrackConditionalWeakTableElements());
- g_profControlBlock.pProfInterface->ConditionalWeakTableElementReference(
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackConditionalWeakTableElements());
+ (&g_profControlBlock)->ConditionalWeakTableElementReference(
(uint8_t*)*pRef,
(uint8_t*)pSec,
pRef,
&pSC->pHeapId);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
#endif // GC_PROFILING
@@ -739,10 +739,10 @@ void GCProfileWalkHeap(bool etwOnly)
#if defined (GC_PROFILING)
{
- BEGIN_PIN_PROFILER(!etwOnly && CORProfilerTrackGC());
+ BEGIN_PROFILER_CALLBACK(!etwOnly && CORProfilerTrackGC());
GCProfileWalkHeapWorker(TRUE /* fProfilerPinned */, fShouldWalkHeapRootsForEtw, fShouldWalkHeapObjectsForEtw);
fWalkedHeapForProfiler = TRUE;
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // defined (GC_PROFILING)
@@ -759,7 +759,7 @@ void GCProfileWalkHeap(bool etwOnly)
void WalkFReachableObjects(bool isCritical, void* objectID)
{
- g_profControlBlock.pProfInterface->FinalizeableObjectQueued(isCritical, (ObjectID)objectID);
+ (&g_profControlBlock)->FinalizeableObjectQueued(isCritical, (ObjectID)objectID);
}
static fq_walk_fn g_FQWalkFn = &WalkFReachableObjects;
@@ -770,7 +770,7 @@ void GCToEEInterface::DiagGCStart(int gen, bool isInduced)
DiagUpdateGenerationBounds();
GarbageCollectionStartedCallback(gen, isInduced);
{
- BEGIN_PIN_PROFILER(CORProfilerTrackGC());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC());
size_t context = 0;
// When we're walking objects allocated by class, then we don't want to walk the large
@@ -778,8 +778,8 @@ void GCToEEInterface::DiagGCStart(int gen, bool isInduced)
GCHeapUtilities::GetGCHeap()->DiagWalkHeap(&AllocByClassHelper, (void *)&context, 0, false);
// Notify that we've reached the end of the Gen 0 scan
- g_profControlBlock.pProfInterface->EndAllocByClass(&context);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->EndAllocByClass(&context);
+ END_PROFILER_CALLBACK();
}
#endif // GC_PROFILING
@@ -815,12 +815,9 @@ void GCToEEInterface::DiagGCEnd(size_t index, int gen, int reason, bool fConcurr
void GCToEEInterface::DiagWalkFReachableObjects(void* gcContext)
{
#ifdef GC_PROFILING
- if (CORProfilerTrackGC())
- {
- BEGIN_PIN_PROFILER(CORProfilerPresent());
- GCHeapUtilities::GetGCHeap()->DiagWalkFinalizeQueue(gcContext, g_FQWalkFn);
- END_PIN_PROFILER();
- }
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC());
+ GCHeapUtilities::GetGCHeap()->DiagWalkFinalizeQueue(gcContext, g_FQWalkFn);
+ END_PROFILER_CALLBACK();
#endif //GC_PROFILING
}
diff --git a/src/coreclr/vm/gchandleutilities.cpp b/src/coreclr/vm/gchandleutilities.cpp
index 2086dacdc62..dcc3682e5b3 100644
--- a/src/coreclr/vm/gchandleutilities.cpp
+++ b/src/coreclr/vm/gchandleutilities.cpp
@@ -22,9 +22,9 @@ void ValidateHandleAssignment(OBJECTHANDLE handle, OBJECTREF objRef)
void DiagHandleCreated(OBJECTHANDLE handle, OBJECTREF objRef)
{
#ifdef GC_PROFILING
- BEGIN_PIN_PROFILER(CORProfilerTrackGC());
- g_profControlBlock.pProfInterface->HandleCreated((uintptr_t)handle, (ObjectID)OBJECTREF_TO_UNCHECKED_OBJECTREF(objRef));
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC());
+ (&g_profControlBlock)->HandleCreated((uintptr_t)handle, (ObjectID)OBJECTREF_TO_UNCHECKED_OBJECTREF(objRef));
+ END_PROFILER_CALLBACK();
#else
UNREFERENCED_PARAMETER(handle);
UNREFERENCED_PARAMETER(objRef);
@@ -34,9 +34,9 @@ void DiagHandleCreated(OBJECTHANDLE handle, OBJECTREF objRef)
void DiagHandleDestroyed(OBJECTHANDLE handle)
{
#ifdef GC_PROFILING
- BEGIN_PIN_PROFILER(CORProfilerTrackGC());
- g_profControlBlock.pProfInterface->HandleDestroyed((uintptr_t)handle);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC());
+ (&g_profControlBlock)->HandleDestroyed((uintptr_t)handle);
+ END_PROFILER_CALLBACK();
#else
UNREFERENCED_PARAMETER(handle);
#endif // GC_PROFILING
diff --git a/src/coreclr/vm/genanalysis.cpp b/src/coreclr/vm/genanalysis.cpp
index 29cb5fc5a6f..fa2fcdf0a22 100644
--- a/src/coreclr/vm/genanalysis.cpp
+++ b/src/coreclr/vm/genanalysis.cpp
@@ -81,6 +81,7 @@ uint32_t gcGenAnalysisBufferMB = 0;
EP_SERIALIZATION_FORMAT_NETTRACE_V4,
false,
nullptr,
+ nullptr,
nullptr
);
if (gcGenAnalysisEventPipeSessionId > 0)
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 9250f436b4b..cb5fe80e0c4 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -7738,12 +7738,12 @@ getMethodInfoHelper(
#if defined(PROFILING_SUPPORTED)
BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
- if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
+ BEGIN_PROFILER_CALLBACK(CORProfilerPresent());
+ if ((&g_profControlBlock)->RequiresGenericsContextForEnterLeave())
{
fProfilerRequiresGenericsContextForEnterLeave = TRUE;
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
if (fProfilerRequiresGenericsContextForEnterLeave)
{
@@ -8134,7 +8134,7 @@ CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
// profiler that this inlining is going to take place, and give them a
// chance to prevent it.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo());
if (pCaller->IsILStub() || pCallee->IsILStub())
{
// do nothing
@@ -8142,7 +8142,7 @@ CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
else
{
BOOL fShouldInline;
- HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
+ HRESULT hr = (&g_profControlBlock)->JITInlining(
(FunctionID)pCaller,
(FunctionID)pCallee,
&fShouldInline);
@@ -8154,7 +8154,7 @@ CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
goto exit;
}
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
#endif // PROFILING_SUPPORTED
@@ -11184,9 +11184,9 @@ void CEEJitInfo::GetProfilingHandle(bool *pbHookFunction,
void * profilerHandle = m_pMethodBeingCompiled;
{
- BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
- profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled());
+ profilerHandle = (void *)(&g_profControlBlock)->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
+ END_PROFILER_CALLBACK();
}
m_gphCache.m_pvGphProfilerHandle = profilerHandle;
@@ -13961,9 +13961,9 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
{
- BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
- profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled());
+ profilerHandle = (CORINFO_PROFILING_HANDLE)(&g_profControlBlock)->EEFunctionIDMapper(funId, &bHookFunction);
+ END_PROFILER_CALLBACK();
}
// Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp
index f75d62bdef2..20f5cbfaf72 100644
--- a/src/coreclr/vm/prestub.cpp
+++ b/src/coreclr/vm/prestub.cpp
@@ -537,9 +537,9 @@ PCODE MethodDesc::GetPrecompiledNgenCode(PrepareCodeConfig* pConfig)
{
BOOL fShouldSearchCache = TRUE;
{
- BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
- g_profControlBlock.pProfInterface->JITCachedFunctionSearchStarted((FunctionID)this, &fShouldSearchCache);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches());
+ (&g_profControlBlock)->JITCachedFunctionSearchStarted((FunctionID)this, &fShouldSearchCache);
+ END_PROFILER_CALLBACK();
}
if (!fShouldSearchCache)
@@ -585,10 +585,10 @@ PCODE MethodDesc::GetPrecompiledNgenCode(PrepareCodeConfig* pConfig)
* cached jitted function has been made.
*/
{
- BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
- g_profControlBlock.pProfInterface->
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches());
+ (&g_profControlBlock)->
JITCachedFunctionSearchFinished((FunctionID)this, COR_PRF_CACHED_FUNCTION_FOUND);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -866,7 +866,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo());
// For methods with non-zero rejit id we send ReJITCompilationStarted, otherwise
// JITCompilationStarted. It isn't clear if this is the ideal policy for these
// notifications yet.
@@ -875,7 +875,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
if (rejitId != 0)
{
_ASSERTE(!nativeCodeVersion.IsDefaultVersion());
- g_profControlBlock.pProfInterface->ReJITCompilationStarted((FunctionID)this,
+ (&g_profControlBlock)->ReJITCompilationStarted((FunctionID)this,
rejitId,
TRUE);
}
@@ -886,7 +886,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
{
if (!IsNoMetadata())
{
- g_profControlBlock.pProfInterface->JITCompilationStarted((FunctionID)this, TRUE);
+ (&g_profControlBlock)->JITCompilationStarted((FunctionID)this, TRUE);
}
else
@@ -895,7 +895,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
CorInfoOptions corOptions;
LPCBYTE ilHeaderPointer = this->AsDynamicMethodDesc()->GetResolver()->GetCodeInfo(&ilSize, &unused, &corOptions, &unused);
- g_profControlBlock.pProfInterface->DynamicMethodJITCompilationStarted((FunctionID)this, TRUE, ilHeaderPointer, ilSize);
+ (&g_profControlBlock)->DynamicMethodJITCompilationStarted((FunctionID)this, TRUE, ilHeaderPointer, ilSize);
}
if (nativeCodeVersion.IsDefaultVersion())
@@ -903,7 +903,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
pConfig->SetProfilerMayHaveActivatedNonDefaultCodeVersion();
}
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -955,7 +955,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo());
// For methods with non-zero rejit id we send ReJITCompilationFinished, otherwise
// JITCompilationFinished. It isn't clear if this is the ideal policy for these
// notifications yet.
@@ -964,7 +964,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
if (rejitId != 0)
{
_ASSERTE(!nativeCodeVersion.IsDefaultVersion());
- g_profControlBlock.pProfInterface->ReJITCompilationFinished((FunctionID)this,
+ (&g_profControlBlock)->ReJITCompilationFinished((FunctionID)this,
rejitId,
S_OK,
TRUE);
@@ -976,14 +976,14 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
{
if (!IsNoMetadata())
{
- g_profControlBlock.pProfInterface->
+ (&g_profControlBlock)->
JITCompilationFinished((FunctionID)this,
pEntry->m_hrResultCode,
TRUE);
}
else
{
- g_profControlBlock.pProfInterface->DynamicMethodJITCompilationFinished((FunctionID)this, pEntry->m_hrResultCode, TRUE);
+ (&g_profControlBlock)->DynamicMethodJITCompilationFinished((FunctionID)this, pEntry->m_hrResultCode, TRUE);
}
if (nativeCodeVersion.IsDefaultVersion())
@@ -991,7 +991,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
pConfig->SetProfilerMayHaveActivatedNonDefaultCodeVersion();
}
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
diff --git a/src/coreclr/vm/profdetach.cpp b/src/coreclr/vm/profdetach.cpp
index 392fde6c0a1..0161bef9529 100644
--- a/src/coreclr/vm/profdetach.cpp
+++ b/src/coreclr/vm/profdetach.cpp
@@ -19,9 +19,9 @@
#include "eetoprofinterfaceimpl.inl"
// Class static member variables
-ProfilerDetachInfo ProfilingAPIDetach::s_profilerDetachInfo;
-CLREvent ProfilingAPIDetach::s_eventDetachWorkAvailable;
-
+CQuickArrayList<ProfilerDetachInfo> ProfilingAPIDetach::s_profilerDetachInfos;
+CLREvent ProfilingAPIDetach::s_eventDetachWorkAvailable;
+Volatile<BOOL> ProfilingAPIDetach::s_profilerDetachThreadCreated;
// ---------------------------------------------------------------------------------------
// ProfilerDetachInfo constructor
@@ -49,7 +49,7 @@ void ProfilerDetachInfo::Init()
// use real contracts, as this requires that utilcode has been initialized.
STATIC_CONTRACT_LEAF;
- m_pEEToProf = NULL;
+ m_pProfilerInfo = NULL;
m_ui64DetachStartTime = 0;
m_dwExpectedCompletionMilliseconds = 0;
}
@@ -145,7 +145,7 @@ HRESULT ProfilingAPIDetach::Initialize()
//
// static
-HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
+HRESULT ProfilingAPIDetach::RequestProfilerDetach(ProfilerInfo *pProfilerInfo, DWORD dwExpectedCompletionMilliseconds)
{
CONTRACTL
{
@@ -178,14 +178,19 @@ HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMill
{
CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
- // return immediately if detach is in progress
+ EEToProfInterfaceImpl *pEEToProf = pProfilerInfo->pProfInterface;
- if (s_profilerDetachInfo.m_pEEToProf != NULL)
+ // return immediately if detach is in progress
+ for (SIZE_T pos = 0; pos < s_profilerDetachInfos.Size(); ++pos)
{
- return CORPROF_E_PROFILER_DETACHING;
+ ProfilerDetachInfo &current = s_profilerDetachInfos[pos];
+ if (current.m_pProfilerInfo->pProfInterface == pEEToProf)
+ {
+ return CORPROF_E_PROFILER_DETACHING;
+ }
}
- ProfilerStatus curProfStatus = g_profControlBlock.curProfStatus.Get();
+ ProfilerStatus curProfStatus = pProfilerInfo->curProfStatus.Get();
if ((curProfStatus == kProfStatusInitializingForStartupLoad) ||
(curProfStatus == kProfStatusInitializingForAttachLoad))
@@ -201,8 +206,6 @@ HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMill
return CORPROF_E_PROFILER_DETACHING;
}
- EEToProfInterfaceImpl * pEEToProf = g_profControlBlock.pProfInterface;
-
// Since prof status was active after entering the lock, the profiler must not
// have unloaded out from under us.
_ASSERTE(pEEToProf != NULL);
@@ -219,13 +222,25 @@ HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMill
{
return hr;
}
- s_profilerDetachInfo.m_pEEToProf = pEEToProf;
- s_profilerDetachInfo.m_ui64DetachStartTime = CLRGetTickCount64();
- s_profilerDetachInfo.m_dwExpectedCompletionMilliseconds = dwExpectedCompletionMilliseconds;
+
+ EX_TRY
+ {
+ ProfilerDetachInfo detachInfo;
+ detachInfo.m_pProfilerInfo = pProfilerInfo;
+ detachInfo.m_ui64DetachStartTime = CLRGetTickCount64();
+ detachInfo.m_dwExpectedCompletionMilliseconds = dwExpectedCompletionMilliseconds;
+ s_profilerDetachInfos.Push(detachInfo);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ if (FAILED(hr))
+ {
+ return hr;
+ }
// Ok, time to seal the profiler from receiving or making calls with the CLR.
// (This will force a FlushStoreBuffers().)
- g_profControlBlock.curProfStatus.Set(kProfStatusDetaching);
+ pProfilerInfo->curProfStatus.Set(kProfStatusDetaching);
}
// Sealing done. Wake up the DetachThread so it can loop until the profiler code is
@@ -274,58 +289,58 @@ void ProfilingAPIDetach::ExecuteEvacuationLoop()
}
CONTRACTL_END;
- // Wait until there's a profiler to detach (or until this thread should "wake up"
- // for some other reason, such as exiting due to an unsuccessful startup-load of a
- // profiler).
- DWORD dwRet = s_eventDetachWorkAvailable.Wait(INFINITE, FALSE /* alertable */);
- if (dwRet != WAIT_OBJECT_0)
+ while (true)
{
- // The wait ended due to a failure or a reason other than the event getting
- // signaled (e.g., WAIT_ABANDONED)
- DWORD dwErr;
- if (dwRet == WAIT_FAILED)
+ // Wait until there's a profiler to detach (or until this thread should "wake up"
+ // for some other reason, such as exiting due to an unsuccessful startup-load of a
+ // profiler).
+ DWORD dwRet = s_eventDetachWorkAvailable.Wait(INFINITE, FALSE /* alertable */);
+ if (dwRet != WAIT_OBJECT_0)
{
- dwErr = GetLastError();
- LOG((
- LF_CORPROF,
- LL_ERROR,
- "**PROF: DetachThread wait for s_eventDetachWorkAvailable failed with GetLastError = %d.\n",
- dwErr));
+ // The wait ended due to a failure or a reason other than the event getting
+ // signaled (e.g., WAIT_ABANDONED)
+ DWORD dwErr;
+ if (dwRet == WAIT_FAILED)
+ {
+ dwErr = GetLastError();
+ LOG((
+ LF_CORPROF,
+ LL_ERROR,
+ "**PROF: DetachThread wait for s_eventDetachWorkAvailable failed with GetLastError = %d.\n",
+ dwErr));
+ }
+ else
+ {
+ dwErr = dwRet; // No extra error info available beyond the return code
+ LOG((
+ LF_CORPROF,
+ LL_ERROR,
+ "**PROF: DetachThread wait for s_eventDetachWorkAvailable terminated with %d.\n",
+ dwErr));
+ }
+
+ ProfilingAPIUtility::LogProfError(IDS_PROF_DETACH_THREAD_ERROR, dwErr);
+ return;
}
- else
+
{
- dwErr = dwRet; // No extra error info available beyond the return code
- LOG((
- LF_CORPROF,
- LL_ERROR,
- "**PROF: DetachThread wait for s_eventDetachWorkAvailable terminated with %d.\n",
- dwErr));
- }
+ CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
- ProfilingAPIUtility::LogProfError(IDS_PROF_DETACH_THREAD_ERROR, dwErr);
- return;
- }
+ for (SIZE_T pos = 0; pos < s_profilerDetachInfos.Size(); ++pos)
+ {
+ ProfilerDetachInfo current = s_profilerDetachInfos.Pop();
- // Peek to make sure there's actually a profiler to detach
- {
- CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
+ do
+ {
+ // Give profiler a chance to return from its procs
+ SleepWhileProfilerEvacuates(&current);
+ }
+ while (!ProfilingAPIUtility::IsProfilerEvacuated(current.m_pProfilerInfo));
- if (s_profilerDetachInfo.m_pEEToProf == NULL)
- {
- // Nothing to detach. This can happen if the DetachThread (i.e., current
- // thread) was created but then the profiler failed to load.
- return;
+ UnloadProfiler(&current);
+ }
}
}
-
- do
- {
- // Give profiler a chance to return from its procs
- SleepWhileProfilerEvacuates();
- }
- while (!ProfilingAPIUtility::IsProfilerEvacuated());
-
- UnloadProfiler();
}
//---------------------------------------------------------------------------------------
@@ -335,7 +350,7 @@ void ProfilingAPIDetach::ExecuteEvacuationLoop()
//
// static
-void ProfilingAPIDetach::SleepWhileProfilerEvacuates()
+void ProfilingAPIDetach::SleepWhileProfilerEvacuates(ProfilerDetachInfo *pDetachInfo)
{
CONTRACTL
{
@@ -398,9 +413,9 @@ void ProfilingAPIDetach::SleepWhileProfilerEvacuates()
{
CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
- _ASSERTE(s_profilerDetachInfo.m_pEEToProf != NULL);
- ui64ExpectedCompletionMilliseconds = s_profilerDetachInfo.m_dwExpectedCompletionMilliseconds;
- ui64DetachStartTime = s_profilerDetachInfo.m_ui64DetachStartTime;
+ _ASSERTE(pDetachInfo->m_pProfilerInfo != NULL);
+ ui64ExpectedCompletionMilliseconds = pDetachInfo->m_dwExpectedCompletionMilliseconds;
+ ui64DetachStartTime = pDetachInfo->m_ui64DetachStartTime;
}
// ui64SleepMilliseconds is calculated to ensure that CLR checks evacuation status roughly:
@@ -456,7 +471,7 @@ void ProfilingAPIDetach::SleepWhileProfilerEvacuates()
//
// static
-void ProfilingAPIDetach::UnloadProfiler()
+void ProfilingAPIDetach::UnloadProfiler(ProfilerDetachInfo *pDetachInfo)
{
CONTRACTL
{
@@ -467,27 +482,39 @@ void ProfilingAPIDetach::UnloadProfiler()
}
CONTRACTL_END;
- _ASSERTE(g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching);
+ _ASSERTE(pDetachInfo->m_pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching);
{
CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
// Notify profiler it's about to be unloaded
- _ASSERTE(s_profilerDetachInfo.m_pEEToProf != NULL);
- s_profilerDetachInfo.m_pEEToProf->ProfilerDetachSucceeded();
-
- // Reset detach state.
- s_profilerDetachInfo.Init();
+ _ASSERTE(pDetachInfo->m_pProfilerInfo != NULL);
+
+ {
+ // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy.
+ // Using it like this without the dirty read/evac counter increment/clean read pattern
+ // is not safe generally, but in this specific case we can skip all that since we are in
+ // a critical section and are the only ones with access to the ProfilerInfo *
+ EvacuationCounterHolder evacuationCounter(pDetachInfo->m_pProfilerInfo);
+ pDetachInfo->m_pProfilerInfo->pProfInterface->ProfilerDetachSucceeded();
+ }
+
+ EEToProfInterfaceImpl *pProfInterface = pDetachInfo->m_pProfilerInfo->pProfInterface.Load();
+ pDetachInfo->m_pProfilerInfo->pProfInterface.Store(NULL);
+ delete pProfInterface;
// This deletes the EEToProfInterfaceImpl object managing the detaching profiler,
// releases the profiler's callback interfaces, unloads the profiler DLL, sets
// the status to kProfStatusNone, and resets g_profControlBlock for use next time
// a profiler tries to attach.
//
- // Note that s_profilerDetachInfo.Init() has already NULL'd out
- // s_profilerDetachInfo.m_pEEToProf, so we won't have a dangling pointer to the
+ // Note that we've already NULL'd out
+ // pDetachInfo->m_pProfilerInfo->pProfInterface, so we won't have a dangling pointer to the
// EEToProfInterfaceImpl that's about to be destroyed.
- ProfilingAPIUtility::TerminateProfiling();
+ ProfilingAPIUtility::TerminateProfiling(pDetachInfo->m_pProfilerInfo);
+
+ // Reset detach state.
+ pDetachInfo->Init();
}
ProfilingAPIUtility::LogProfInfo(IDS_PROF_DETACH_COMPLETE);
@@ -570,56 +597,69 @@ HRESULT ProfilingAPIDetach::CreateDetachThread()
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
- CANNOT_TAKE_LOCK;
+ CAN_TAKE_LOCK;
}
CONTRACTL_END;
- // FUTURE: When reattach with neutered profilers is implemented, this
- // function should check if a DetachThread already exists (use synchronization
- // to prevent race), and just return if so.
-
- HandleHolder hDetachThread;
-
- // The DetachThread is intentionally not an EE Thread-object thread (it won't
- // execute managed code).
- hDetachThread = ::CreateThread(
- NULL, // lpThreadAttributes; don't want child processes inheriting this handle
- 0, // dwStackSize (0 = use default)
- ProfilingAPIDetachThreadStart,
- NULL, // lpParameter (none to pass)
- 0, // dwCreationFlags (0 = use default flags, start thread immediately)
- NULL // lpThreadId (don't need therad ID)
- );
- if (hDetachThread == NULL)
+ if (s_profilerDetachThreadCreated)
+ {
+ return S_OK;
+ }
+
{
- DWORD dwErr = GetLastError();
+ CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
+
+ if (!s_profilerDetachThreadCreated)
+ {
+ HandleHolder hDetachThread;
+
+ // The DetachThread is intentionally not an EE Thread-object thread (it won't
+ // execute managed code).
+ hDetachThread = ::CreateThread(
+ NULL, // lpThreadAttributes; don't want child processes inheriting this handle
+ 0, // dwStackSize (0 = use default)
+ ProfilingAPIDetachThreadStart,
+ NULL, // lpParameter (none to pass)
+ 0, // dwCreationFlags (0 = use default flags, start thread immediately)
+ NULL // lpThreadId (don't need therad ID)
+ );
+ if (hDetachThread == NULL)
+ {
+ DWORD dwErr = GetLastError();
- LOG((
- LF_CORPROF,
- LL_ERROR,
- "**PROF: Failed to create DetachThread. GetLastError=%d.\n",
- dwErr));
+ LOG((
+ LF_CORPROF,
+ LL_ERROR,
+ "**PROF: Failed to create DetachThread. GetLastError=%d.\n",
+ dwErr));
- return HRESULT_FROM_WIN32(dwErr);
+ return HRESULT_FROM_WIN32(dwErr);
+ }
+
+ s_profilerDetachThreadCreated = TRUE;
+ }
}
return S_OK;
}
-//---------------------------------------------------------------------------------------
-//
-// Accessor for ProfilingAPIDetach::s_profilerDetachInfo.m_pEEToProf, which is the
-// profiler being detached (or NULL if no profiler is being detached).
-//
-// Return Value:
-// EEToProfInterfaceImpl * for the profiler being detached.
-//
-
// static
-EEToProfInterfaceImpl * ProfilingAPIDetach::GetEEToProfPtr()
+BOOL ProfilingAPIDetach::IsEEToProfPtrRegisteredForDetach(EEToProfInterfaceImpl *pEEToProf)
{
LIMITED_METHOD_CONTRACT;
- return s_profilerDetachInfo.m_pEEToProf;
+
+ CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
+
+ for (SIZE_T pos = 0; pos < s_profilerDetachInfos.Size(); ++pos)
+ {
+ ProfilerDetachInfo &current = s_profilerDetachInfos[pos];
+ if (current.m_pProfilerInfo->pProfInterface == pEEToProf)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
#endif // FEATURE_PROFAPI_ATTACH_DETACH
diff --git a/src/coreclr/vm/profdetach.h b/src/coreclr/vm/profdetach.h
index 7b85cb61c9d..5f97e4e59a9 100644
--- a/src/coreclr/vm/profdetach.h
+++ b/src/coreclr/vm/profdetach.h
@@ -24,13 +24,8 @@ struct ProfilerDetachInfo
ProfilerDetachInfo();
void Init();
- // NULL if we're not trying to detach a profiler. Otherwise, this is the
- // EEToProfInterfaceImpl instance we're detaching.
- //
- // FUTURE: Although m_pEEToProf, when non-NULL, is always the same as
- // g_profControlBlock.pProfInterface, that will no longer be the case once we allow
- // re-attach with neutered profilers.
- EEToProfInterfaceImpl * m_pEEToProf;
+ // This is the profiler instance we're detaching.
+ ProfilerInfo *m_pProfilerInfo;
// Time when profiler originally called RequestProfilerDetach()
ULONGLONG m_ui64DetachStartTime;
@@ -48,23 +43,25 @@ class ProfilingAPIDetach
public:
static HRESULT Initialize();
- static HRESULT RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds);
+ static HRESULT RequestProfilerDetach(ProfilerInfo *profilerInfo, DWORD dwExpectedCompletionMilliseconds);
static HRESULT CreateDetachThread();
static DWORD WINAPI ProfilingAPIDetachThreadStart(LPVOID lpParameter);
static void ExecuteEvacuationLoop();
- static EEToProfInterfaceImpl * GetEEToProfPtr();
+ static BOOL IsEEToProfPtrRegisteredForDetach(EEToProfInterfaceImpl *pEEToProf);
private:
- static ProfilerDetachInfo s_profilerDetachInfo;
+ static CQuickArrayList<ProfilerDetachInfo> s_profilerDetachInfos;
// Signaled by RequestProfilerDetach() when there is detach work ready to be
// done by the DetachThread
static CLREvent s_eventDetachWorkAvailable;
- static void SleepWhileProfilerEvacuates();
- static void UnloadProfiler();
+ static Volatile<BOOL> s_profilerDetachThreadCreated;
+
+ static void SleepWhileProfilerEvacuates(ProfilerDetachInfo *pDetachInfo);
+ static void UnloadProfiler(ProfilerDetachInfo *pDetachInfo);
// Prevent instantiation of ProfilingAPIDetach objects (should be static-only)
ProfilingAPIDetach();
diff --git a/src/coreclr/vm/profilinghelper.cpp b/src/coreclr/vm/profilinghelper.cpp
index ea1738f871a..ac2ea1469a4 100644
--- a/src/coreclr/vm/profilinghelper.cpp
+++ b/src/coreclr/vm/profilinghelper.cpp
@@ -52,9 +52,9 @@
// issue a profiler callback. Readers are scattered throughout the runtime, and have the
// following format:
// {
-// BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
+// BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads());
// g_profControlBlock.pProfInterface->AppDomainCreationStarted(MyAppDomainID);
-// END_PIN_PROFILER();
+// END_PROFILER_CALLBACK();
// }
// The BEGIN / END macros do the following:
// * Evaluate the expression argument (e.g., CORProfilerTrackAppDomainLoads()). This is a
@@ -95,33 +95,6 @@
// first, which the writer will be sure to see in (c). For more details about how the
// evacuation counters work, see code:ProfilingAPIUtility::IsProfilerEvacuated.
//
-// WHEN ARE BEGIN/END_PIN_PROFILER REQUIRED?
-//
-// In general, any time you access g_profControlBlock.pProfInterface, you must be inside
-// a BEGIN/END_PIN_PROFILER block. This is pretty much always true throughout the EE, but
-// there are some exceptions inside the profiling API code itself, where the BEGIN / END
-// macros are unnecessary:
-// * If you are inside a public ICorProfilerInfo function's implementation, the
-// profiler is already pinned. This is because the profiler called the Info
-// function from either:
-// * a callback implemented inside of g_profControlBlock.pProfInterface, in which
-// case the BEGIN/END macros are already in place around the call to that
-// callback, OR
-// * a hijacked thread or a thread of the profiler's own creation. In either
-// case, it's the profiler's responsibility to end hijacking and end its own
-// threads before requesting a detach. So the profiler DLL is guaranteed not
-// to disappear while hijacking or profiler-created threads are in action.
-// * If you're executing while code:ProfilingAPIUtility::s_csStatus is held, then
-// you're explicitly serialized against all code that might unload the profiler's
-// DLL and delete g_profControlBlock.pProfInterface. So the profiler is therefore
-// still guaranteed not to disappear.
-// * If slow ELT helpers, fast ELT hooks, or profiler-instrumented code is on the
-// stack, then the profiler cannot be detached yet anyway. Today, we outright
-// refuse a detach request from a profiler that instrumented code or enabled ELT.
-// Once rejit / revert is implemented, the evacuation checks will ensure all
-// instrumented code (including ELT) are reverted and off all stacks before
-// attempting to unload the profielr.
-
#include "common.h"
@@ -148,44 +121,6 @@
#include "securitywrapper.h"
#endif // !TARGET_UNIX
-//---------------------------------------------------------------------------------------
-// Normally, this would go in profilepriv.inl, but it's not easily inlineable because of
-// the use of BEGIN/END_PIN_PROFILER
-//
-// Return Value:
-// TRUE iff security transparency checks in full trust assemblies should be disabled
-// due to the profiler.
-//
-BOOL CORProfilerBypassSecurityChecks()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- CANNOT_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- {
- BEGIN_PIN_PROFILER(CORProfilerPresent());
-
- // V2 profiler binaries, for compatibility purposes, should bypass transparency
- // checks in full trust assemblies.
- if (!(&g_profControlBlock)->pProfInterface->IsCallback3Supported())
- return TRUE;
-
- // V4 profiler binaries must opt in to bypassing transparency checks in full trust
- // assemblies.
- if (((&g_profControlBlock)->dwEventMask & COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST) != 0)
- return TRUE;
-
- END_PIN_PROFILER();
- }
-
- // All other cases, including no profiler loaded at all: Don't bypass
- return FALSE;
-}
-
// ----------------------------------------------------------------------------
// CurrentProfilerStatus methods
@@ -379,6 +314,9 @@ void ProfilingAPIUtility::LogProfEventVA(
AppendSupplementaryInformation(iStringResourceID, &messageToLog);
+ // Write to ETW and EventPipe with the message
+ FireEtwProfilerMessage(GetClrInstanceId(), messageToLog.GetUnicode());
+
// Ouput debug strings for diagnostic messages.
WszOutputDebugString(messageToLog);
}
@@ -498,6 +436,9 @@ HRESULT ProfilingAPIUtility::InitializeProfiling()
}
AttemptLoadProfilerForStartup();
+ AttemptLoadDelayedStartupProfilers();
+ AttemptLoadProfilerList();
+
// For now, the return value from AttemptLoadProfilerForStartup is of no use to us.
// Any event has been logged already by AttemptLoadProfilerForStartup, and
// regardless of whether a profiler got loaded, we still need to continue.
@@ -687,108 +628,85 @@ HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup()
fProfEnabled = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_ENABLE_PROFILING);
NewArrayHolder<WCHAR> wszClsid(NULL);
- NewArrayHolder<const WCHAR> cwszProfilerDLL(NULL);
+ NewArrayHolder<WCHAR> wszProfilerDLL(NULL);
CLSID *pClsid;
CLSID clsid;
- if (fProfEnabled != 0)
+ if (fProfEnabled == 0)
{
- LOG((LF_CORPROF, LL_INFO10, "**PROF: Initializing Profiling Services.\n"));
+ LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling not enabled.\n"));
+ return S_FALSE;
+ }
- NewArrayHolder<WCHAR> wszProfilerDLL(NULL);
+ LOG((LF_CORPROF, LL_INFO10, "**PROF: Initializing Profiling Services.\n"));
- IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid));
+ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid));
- #if defined(TARGET_ARM64)
- IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM64, &wszProfilerDLL));
- #elif defined(TARGET_ARM)
- IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM32, &wszProfilerDLL));
- #endif
+#if defined(TARGET_ARM64)
+ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM64, &wszProfilerDLL));
+#elif defined(TARGET_ARM)
+ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM32, &wszProfilerDLL));
+#endif
+ if(wszProfilerDLL == NULL)
+ {
+#ifdef TARGET_64BIT
+ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL));
+#else
+ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL));
+#endif
if(wszProfilerDLL == NULL)
{
- #ifdef TARGET_64BIT
- IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL));
- #else
- IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL));
- #endif
- if(wszProfilerDLL == NULL)
- {
- IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH, &wszProfilerDLL));
- }
+ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH, &wszProfilerDLL));
}
+ }
- // If the environment variable doesn't exist, profiling is not enabled.
- if (wszClsid == NULL)
- {
- LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
- "environment variable does not exist.\n"));
-
- LogProfError(IDS_E_PROF_NO_CLSID);
-
- return S_FALSE;
- }
+ // If the environment variable doesn't exist, profiling is not enabled.
+ if (wszClsid == NULL)
+ {
+ LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
+ "environment variable does not exist.\n"));
- if ((wszProfilerDLL != NULL) && (wcslen(wszProfilerDLL) >= MAX_LONGPATH))
- {
- LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but COR_PROFILER_PATH was not set properly.\n"));
+ LogProfError(IDS_E_PROF_NO_CLSID);
- LogProfError(IDS_E_PROF_BAD_PATH);
+ return S_FALSE;
+ }
- return S_FALSE;
- }
+ if ((wszProfilerDLL != NULL) && (wcslen(wszProfilerDLL) >= MAX_LONGPATH))
+ {
+ LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but COR_PROFILER_PATH was not set properly.\n"));
- #ifdef TARGET_UNIX
- // If the environment variable doesn't exist, profiling is not enabled.
- if (wszProfilerDLL == NULL)
- {
- LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
- "environment variable does not exist.\n"));
+ LogProfError(IDS_E_PROF_BAD_PATH);
- LogProfError(IDS_E_PROF_BAD_PATH);
+ return S_FALSE;
+ }
- return S_FALSE;
- }
- #endif // TARGET_UNIX
+#ifdef TARGET_UNIX
+ // If the environment variable doesn't exist, profiling is not enabled.
+ if (wszProfilerDLL == NULL)
+ {
+ LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
+ "environment variable does not exist.\n"));
- hr = ProfilingAPIUtility::ProfilerCLSIDFromString(wszClsid, &clsid);
- if (FAILED(hr))
- {
- // ProfilerCLSIDFromString already logged an event if there was a failure
- return hr;
- }
+ LogProfError(IDS_E_PROF_BAD_PATH);
- pClsid = &clsid;
- cwszProfilerDLL.Assign(wszProfilerDLL.GetValue());
- wszProfilerDLL.SuppressRelease();
- }
- else if (g_profControlBlock.fIsStoredProfilerRegistered)
- {
- LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiler loading from GUID/Path stored from the IPC channel."));
- pClsid = &(g_profControlBlock.clsStoredProfilerGuid);
-
- // Convert to string for logging
- constexpr size_t guidStringSize = 128;
- wszClsid.Assign(new (nothrow) WCHAR[guidStringSize]);
- if (wszClsid != NULL)
- {
- StringFromGUID2(*pClsid, wszClsid, guidStringSize);
- }
-
- // Assign, but don't take ownership of, the stored profiler path. This relies on
- // g_profControlBlock.sStoredProfilerPath not mutating, which would invalidate the pointer.
- cwszProfilerDLL.Assign(g_profControlBlock.sStoredProfilerPath.GetUnicode(), FALSE);
+ return S_FALSE;
}
- else
+#endif // TARGET_UNIX
+
+ hr = ProfilingAPIUtility::ProfilerCLSIDFromString(wszClsid, &clsid);
+ if (FAILED(hr))
{
- LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling not enabled.\n"));
- return S_FALSE;
+ // ProfilerCLSIDFromString already logged an event if there was a failure
+ return hr;
}
+ pClsid = &clsid;
+
hr = LoadProfiler(
kStartupLoad,
pClsid,
wszClsid,
- cwszProfilerDLL,
+ wszProfilerDLL,
NULL, // No client data for startup load
0); // No client data for startup load
if (FAILED(hr))
@@ -801,6 +719,121 @@ HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup()
return S_OK;
}
+//static
+HRESULT ProfilingAPIUtility::AttemptLoadDelayedStartupProfilers()
+{
+ if (g_profControlBlock.storedProfilers.IsEmpty())
+ {
+ return S_OK;
+ }
+
+ HRESULT storedHr = S_OK;
+ STOREDPROFILERLIST *profilers = &g_profControlBlock.storedProfilers;
+ for (StoredProfilerNode* item = profilers->GetHead(); item != NULL; item = STOREDPROFILERLIST::GetNext(item))
+ {
+ LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiler loading from GUID/Path stored from the IPC channel."));
+ CLSID *pClsid = &(item->guid);
+
+ // Convert to string for logging
+ constexpr size_t guidStringSize = 39;
+ NewArrayHolder<WCHAR> wszClsid(new (nothrow) WCHAR[guidStringSize]);
+ // GUIDs should always be the same number of characters...
+ _ASSERTE(wszClsid != NULL);
+ if (wszClsid != NULL)
+ {
+ StringFromGUID2(*pClsid, wszClsid, guidStringSize);
+ }
+
+ HRESULT hr = LoadProfiler(
+ kStartupLoad,
+ pClsid,
+ wszClsid,
+ item->path.GetUnicode(),
+ NULL, // No client data for startup load
+ 0); // No client data for startup load
+ if (FAILED(hr))
+ {
+ // LoadProfiler logs if there is an error
+ storedHr = hr;
+ }
+ }
+
+ return storedHr;
+}
+
+// static
+HRESULT ProfilingAPIUtility::AttemptLoadProfilerList()
+{
+ HRESULT hr = S_OK;
+ DWORD dwEnabled = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_ENABLE_NOTIFICATION_PROFILERS);
+ if (dwEnabled == 0)
+ {
+ // Profiler list explicitly disabled, bail
+ LogProfInfo(IDS_E_PROF_NOTIFICATION_DISABLED);
+ return S_OK;
+ }
+
+ NewArrayHolder<WCHAR> wszProfilerList(NULL);
+#ifdef TARGET_64BIT
+ CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_NOTIFICATION_PROFILERS_64, &wszProfilerList);
+#else // TARGET_64BIT
+ CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_NOTIFICATION_PROFILERS_32, &wszProfilerList);
+#endif // TARGET_64BIT
+ if (wszProfilerList == NULL)
+ {
+ CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_NOTIFICATION_PROFILERS, &wszProfilerList);
+ if (wszProfilerList == NULL)
+ {
+ // No profiler list specified, bail
+ return S_OK;
+ }
+ }
+
+ WCHAR *pOuter = NULL;
+ WCHAR *pInner = NULL;
+ WCHAR *currentSection = NULL;
+ WCHAR *currentPath = NULL;
+ WCHAR *currentGuid = NULL;
+
+ HRESULT storedHr = S_OK;
+ // Get each semicolon delimited config
+ currentSection = wcstok_s(wszProfilerList, W(";"), &pOuter);
+ while (currentSection != NULL)
+ {
+ // Parse this config "path={guid}"
+ currentPath = wcstok_s(currentSection, W("="), &pInner);
+ currentGuid = wcstok_s(NULL, W("="), &pInner);
+
+ CLSID clsid;
+ hr = ProfilingAPIUtility::ProfilerCLSIDFromString(currentGuid, &clsid);
+ if (FAILED(hr))
+ {
+ // ProfilerCLSIDFromString already logged an event if there was a failure
+ storedHr = hr;
+ goto NextSection;
+ }
+
+ hr = LoadProfiler(
+ kStartupLoad,
+ &clsid,
+ currentGuid,
+ currentPath,
+ NULL, // No client data for startup load
+ 0); // No client data for startup load
+ if (FAILED(hr))
+ {
+ // LoadProfiler already logged if there was an error
+ storedHr = hr;
+ goto NextSection;
+ }
+
+NextSection:
+ // Get next config
+ currentSection = wcstok_s(NULL, W(";"), &pOuter);
+ }
+
+ return storedHr;
+}
//---------------------------------------------------------------------------------------
//
@@ -1060,6 +1093,12 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
// Client data is currently only specified on attach
_ASSERTE((pvClientData == NULL) || (loadType == kAttachLoad));
+ ProfilerInfo profilerInfo;
+ // RAII type that will deregister if we bail at any point
+ ProfilerInfoHolder profilerInfoHolder(&profilerInfo);
+ profilerInfo.Init();
+ profilerInfo.inUse = TRUE;
+
HRESULT hr = PerformDeferredInit();
if (FAILED(hr))
{
@@ -1073,19 +1112,10 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
}
{
- // To prevent race conditions we need to signal that a load is already happening.
- // The diagnostics server is single threaded, but it can potentially be
- // racing with the startup path, or theoretically in the future it could be
- // racing with another attach request if the diagnostic server becomes
- // multithreaded.
- CRITSEC_Holder csh(s_csStatus);
-
- if (g_profControlBlock.curProfStatus.Get() != kProfStatusNone)
- {
- return CORPROF_E_PROFILER_ALREADY_ACTIVE;
- }
-
- g_profControlBlock.curProfStatus.Set(kProfStatusPreInitialize);
+ // Usually we need to take the lock when modifying profiler status, but at this
+ // point no one else could have a pointer to this ProfilerInfo so we don't
+ // need to synchronize. Once we store it in g_profControlBlock we need to.
+ profilerInfo.curProfStatus.Set(kProfStatusPreInitialize);
}
NewHolder<EEToProfInterfaceImpl> pEEProf(new (nothrow) EEToProfInterfaceImpl());
@@ -1100,17 +1130,13 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
hr = DoPreInitialization(pEEProf, pClsid, wszClsid, wszProfilerDLL, loadType, dwConcurrentGCWaitTimeoutInMs);
if (FAILED(hr))
{
- CRITSEC_Holder csh(s_csStatus);
- g_profControlBlock.curProfStatus.Set(kProfStatusNone);
return hr;
}
{
- // All modification of the profiler's status and
- // g_profControlBlock.pProfInterface need to be serialized against each other,
- // in particular, this code should be serialized against detach and unloading
- // code.
- CRITSEC_Holder csh(s_csStatus);
+ // Usually we need to take the lock when modifying profiler status, but at this
+ // point no one else could have a pointer to this ProfilerInfo so we don't
+ // need to synchronize. Once we store it in g_profControlBlock we need to.
// We've successfully allocated and initialized the callback wrapper object and the
// Info interface implementation objects. The profiler DLL is therefore also
@@ -1122,18 +1148,64 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
// callback (which we do immediately below), and have it successfully call
// back into us via the Info interface (ProfToEEInterfaceImpl) to perform its
// initialization.
- g_profControlBlock.pProfInterface = pEEProf.GetValue();
+ profilerInfo.pProfInterface = pEEProf.GetValue();
pEEProf.SuppressRelease();
pEEProf = NULL;
// Set global status to reflect the proper type of Init we're doing (attach vs
// startup)
- g_profControlBlock.curProfStatus.Set(
+ profilerInfo.curProfStatus.Set(
(loadType == kStartupLoad) ?
kProfStatusInitializingForStartupLoad :
kProfStatusInitializingForAttachLoad);
}
+ ProfilerInfo *pProfilerInfo = NULL;
+ {
+ // Now we register the profiler, from this point on we need to worry about
+ // synchronization
+ CRITSEC_Holder csh(s_csStatus);
+
+ // Check if this profiler is notification only and load as appropriate
+ BOOL notificationOnly = FALSE;
+ {
+ EvacuationCounterHolder holder(&profilerInfo);
+ HRESULT callHr = profilerInfo.pProfInterface->LoadAsNotficationOnly(&notificationOnly);
+ if (FAILED(callHr))
+ {
+ notificationOnly = FALSE;
+ }
+ }
+
+ if (notificationOnly)
+ {
+ pProfilerInfo = g_profControlBlock.FindNextFreeProfilerInfoSlot();
+ if (pProfilerInfo == NULL)
+ {
+ LogProfError(IDS_E_PROF_NOTIFICATION_LIMIT_EXCEEDED);
+ return CORPROF_E_PROFILER_ALREADY_ACTIVE;
+ }
+
+ *pProfilerInfo = profilerInfo;
+ }
+ else
+ {
+ // "main" profiler, there can only be one
+ if (g_profControlBlock.mainProfilerInfo.curProfStatus.Get() != kProfStatusNone)
+ {
+ LogProfError(IDS_PROF_ALREADY_LOADED);
+ return CORPROF_E_PROFILER_ALREADY_ACTIVE;
+ }
+
+ // This profiler cannot be a notification only profiler, copy it over to the
+ // main slot and the ProfilerInfoHolder above will clear out the notification slot
+ g_profControlBlock.mainProfilerInfo = profilerInfo;
+ pProfilerInfo = &(g_profControlBlock.mainProfilerInfo);
+ }
+
+ pProfilerInfo->pProfInterface->SetProfilerInfo(pProfilerInfo);
+ }
+
// Now that the profiler is officially loaded and in Init status, call into the
// profiler's appropriate Initialize() callback. Note that if the profiler fails this
// call, we should abort the rest of the profiler loading, and reset our state so we
@@ -1141,13 +1213,25 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
if (loadType == kStartupLoad)
{
- hr = g_profControlBlock.pProfInterface->Initialize();
+ // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy.
+ // Using it like this without the dirty read/evac counter increment/clean read pattern
+ // is not safe generally, but in this specific case we can skip all that since we haven't
+ // published it yet, so we are the only thread that can access it.
+ EvacuationCounterHolder holder(pProfilerInfo);
+ hr = pProfilerInfo->pProfInterface->Initialize();
}
else
{
+ // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy.
+ // Using it like this without the dirty read/evac counter increment/clean read pattern
+ // is not safe generally, but in this specific case we can skip all that since we haven't
+ // published it yet, so we are the only thread that can access it.
+ EvacuationCounterHolder holder(pProfilerInfo);
+
_ASSERTE(loadType == kAttachLoad);
- _ASSERTE(g_profControlBlock.pProfInterface->IsCallback3Supported());
- hr = g_profControlBlock.pProfInterface->InitializeForAttach(pvClientData, cbClientData);
+ _ASSERTE(pProfilerInfo->pProfInterface->IsCallback3Supported());
+
+ hr = pProfilerInfo->pProfInterface->InitializeForAttach(pvClientData, cbClientData);
}
if (FAILED(hr))
@@ -1162,7 +1246,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
// the reason InitializeForAttach callback failed even though we cannot be sure and we cannot
// cannot assume hr is going to be CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC.
// The best we can do in this case is to report this failure anyway.
- if (g_profControlBlock.pProfInterface->HasTimedOutWaitingForConcurrentGC())
+ if (pProfilerInfo->pProfInterface->HasTimedOutWaitingForConcurrentGC())
{
ProfilingAPIUtility::LogProfError(IDS_E_PROF_TIMEOUT_WAITING_FOR_CONCURRENT_GC, dwConcurrentGCWaitTimeoutInMs, wszClsid);
}
@@ -1171,7 +1255,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
if ((loadType == kAttachLoad) &&
((hr == CORPROF_E_PROFILER_NOT_ATTACHABLE) || (hr == E_NOTIMPL)))
{
- _ASSERTE(g_profControlBlock.pProfInterface->IsCallback3Supported());
+ _ASSERTE(pProfilerInfo->pProfInterface->IsCallback3Supported());
// Profiler supports ICorProfilerCallback3, but explicitly doesn't support
// Attach loading. So log specialized event
@@ -1196,14 +1280,14 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
// Profiler failed; reset everything. This will automatically reset
// g_profControlBlock and will unload the profiler's DLL.
- TerminateProfiling();
+ TerminateProfiling(pProfilerInfo);
return hr;
}
#ifdef FEATURE_MULTICOREJIT
// Disable multicore JIT when profiling is enabled
- if (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_JIT_COMPILATION)
+ if (pProfilerInfo->eventMask.IsEventMaskSet(COR_PRF_MONITOR_JIT_COMPILATION))
{
MulticoreJitManager::DisableMulticoreJit();
}
@@ -1213,7 +1297,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
// Indicate that profiling is properly initialized. On an attach-load, this will
// force a FlushStoreBuffers(), which is important for catch-up synchronization (see
// code:#ProfCatchUpSynchronization)
- g_profControlBlock.curProfStatus.Set(kProfStatusActive);
+ pProfilerInfo->curProfStatus.Set(kProfStatusActive);
LOG((
LF_CORPROF,
@@ -1229,7 +1313,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
// For startup profilers only: If the profiler is interested in tracking GC
// events, then we must disable concurrent GC since concurrent GC can allocate
// and kill objects without relocating and thus not doing a heap walk.
- if (CORProfilerTrackGC())
+ if (pProfilerInfo->eventMask.IsEventMaskSet(COR_PRF_MONITOR_GC))
{
LOG((LF_CORPROF, LL_INFO10, "**PROF: Turning off concurrent GC at startup.\n"));
// Previously we would use SetGCConcurrent(0) to indicate to the GC that it shouldn't even
@@ -1303,11 +1387,17 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
// code:ProfilerFunctionEnum::Init#ProfilerEnumGeneral
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
- g_profControlBlock.pProfInterface->ProfilerAttachComplete();
- END_PIN_PROFILER();
+ // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy.
+ // Using it like this without the dirty read/evac counter increment/clean read pattern
+ // is not safe generally, but in this specific case we can skip all that since we haven't
+ // published it yet, so we are the only thread that can access it.
+ EvacuationCounterHolder holder(pProfilerInfo);
+ pProfilerInfo->pProfInterface->ProfilerAttachComplete();
}
}
+
+ // Yay, the profiler is started up. Don't deregister it if we get to this point
+ profilerInfoHolder.SuppressRelease();
return S_OK;
}
@@ -1323,7 +1413,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler(
//
// static
-BOOL ProfilingAPIUtility::IsProfilerEvacuated()
+BOOL ProfilingAPIUtility::IsProfilerEvacuated(ProfilerInfo *pProfilerInfo)
{
CONTRACTL
{
@@ -1334,64 +1424,36 @@ BOOL ProfilingAPIUtility::IsProfilerEvacuated()
}
CONTRACTL_END;
- _ASSERTE(g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching);
-
- // Check evacuation counters on all the threads (see
+ _ASSERTE(pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching);
+
+ // Note that threads are still in motion as we check its evacuation counter.
+ // This is ok, because we've already changed the profiler status to
+ // kProfStatusDetaching and flushed CPU buffers. So at this point the counter
+ // will typically only go down to 0 (and not increment anymore), with one
+ // small exception (below). So if we get a read of 0 below, the counter will
+ // typically stay there. Specifically:
+ // * Profiler is most likely not about to increment its evacuation counter
+ // from 0 to 1 because pThread sees that the status is
+ // kProfStatusDetaching.
+ // * Note that there is a small race where pThread might actually
+ // increment its evac counter from 0 to 1 (if it dirty-read the
+ // profiler status a tad too early), but that implies that when
+ // pThread rechecks the profiler status (clean read) then pThread
+ // will immediately decrement the evac counter back to 0 and avoid
+ // calling into the EEToProfInterfaceImpl pointer.
+ //
+ // (see
// code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
- // for details). Doing this under the thread store lock not only ensures we can
- // iterate through the Thread objects safely, but also forces us to serialize with
- // the GC. The latter is important, as server GC enters the profiler on non-EE
- // Threads, and so no evacuation counters might be incremented during server GC even
- // though control could be entering the profiler.
+ // for details)
+ DWORD dwEvacCounter = pProfilerInfo->dwProfilerEvacuationCounter;
+ if (dwEvacCounter != 0)
{
- ThreadStoreLockHolder TSLockHolder;
-
- Thread * pThread = ThreadStore::GetAllThreadList(
- NULL, // cursor thread; always NULL to begin with
- 0, // mask to AND with Thread::m_State to filter returned threads
- 0); // bits to match the result of the above AND. (m_State & 0 == 0,
- // so we won't filter out any threads)
-
- // Note that, by not filtering out any of the threads, we're intentionally including
- // stuff like TS_Dead or TS_Unstarted. But that keeps us on the safe
- // side. If an EE Thread object exists, we want to check its counters to be
- // absolutely certain it isn't executing in a profiler.
-
- while (pThread != NULL)
- {
- // Note that pThread is still in motion as we check its evacuation counter.
- // This is ok, because we've already changed the profiler status to
- // kProfStatusDetaching and flushed CPU buffers. So at this point the counter
- // will typically only go down to 0 (and not increment anymore), with one
- // small exception (below). So if we get a read of 0 below, the counter will
- // typically stay there. Specifically:
- // * pThread is most likely not about to increment its evacuation counter
- // from 0 to 1 because pThread sees that the status is
- // kProfStatusDetaching.
- // * Note that there is a small race where pThread might actually
- // increment its evac counter from 0 to 1 (if it dirty-read the
- // profiler status a tad too early), but that implies that when
- // pThread rechecks the profiler status (clean read) then pThread
- // will immediately decrement the evac counter back to 0 and avoid
- // calling into the EEToProfInterfaceImpl pointer.
- //
- // (see
- // code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
- // for details)
- DWORD dwEvacCounter = pThread->GetProfilerEvacuationCounter();
- if (dwEvacCounter != 0)
- {
- LOG((
- LF_CORPROF,
- LL_INFO100,
- "**PROF: Profiler not yet evacuated because OS Thread ID 0x%x has evac counter of %d (decimal).\n",
- pThread->GetOSThreadId(),
- dwEvacCounter));
- return FALSE;
- }
-
- pThread = ThreadStore::GetAllThreadList(pThread, 0, 0);
- }
+ LOG((
+ LF_CORPROF,
+ LL_INFO100,
+ "**PROF: Profiler not yet evacuated because it has evac counter of %d (decimal).\n",
+ dwEvacCounter));
+ return FALSE;
}
// FUTURE: When rejit feature crew complete, add code to verify all rejitted
@@ -1412,7 +1474,7 @@ BOOL ProfilingAPIUtility::IsProfilerEvacuated()
//
// static
-void ProfilingAPIUtility::TerminateProfiling()
+void ProfilingAPIUtility::TerminateProfiling(ProfilerInfo *pProfilerInfo)
{
CONTRACTL
{
@@ -1439,7 +1501,7 @@ void ProfilingAPIUtility::TerminateProfiling()
#ifdef FEATURE_PROFAPI_ATTACH_DETACH
- if (ProfilingAPIDetach::GetEEToProfPtr() != NULL)
+ if (pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching && pProfilerInfo->pProfInterface.Load() != NULL)
{
// The profiler is still being referenced by
// ProfilingAPIDetach::s_profilerDetachInfo, so don't try to release and
@@ -1461,9 +1523,9 @@ void ProfilingAPIUtility::TerminateProfiling()
}
#endif // FEATURE_PROFAPI_ATTACH_DETACH
- if (g_profControlBlock.curProfStatus.Get() == kProfStatusActive)
+ if (pProfilerInfo->curProfStatus.Get() == kProfStatusActive)
{
- g_profControlBlock.curProfStatus.Set(kProfStatusDetaching);
+ pProfilerInfo->curProfStatus.Set(kProfStatusDetaching);
// Profiler was active when TerminateProfiling() was called, so we're unloading
// it due to shutdown. But other threads may still be trying to enter profiler
@@ -1471,7 +1533,7 @@ void ProfilingAPIUtility::TerminateProfiling()
// that the status has been changed to kProfStatusDetaching, no new threads will
// attempt to enter the profiler. But use the detach evacuation counters to see
// if other threads already began to enter the profiler.
- if (!ProfilingAPIUtility::IsProfilerEvacuated())
+ if (!ProfilingAPIUtility::IsProfilerEvacuated(pProfilerInfo))
{
// Other threads might be entering the profiler, so just skip cleanup
return;
@@ -1482,34 +1544,40 @@ void ProfilingAPIUtility::TerminateProfiling()
// If we have a profiler callback wrapper and / or info implementation
// active, then terminate them.
- if (g_profControlBlock.pProfInterface.Load() != NULL)
+ if (pProfilerInfo->pProfInterface.Load() != NULL)
{
// This destructor takes care of releasing the profiler's ICorProfilerCallback*
// interface, and unloading the DLL when we're not in process teardown.
- delete g_profControlBlock.pProfInterface;
- g_profControlBlock.pProfInterface.Store(NULL);
+ delete pProfilerInfo->pProfInterface;
+ pProfilerInfo->pProfInterface.Store(NULL);
}
// NOTE: Intentionally not destroying / NULLing s_csStatus. If
// s_csStatus is already initialized, we can reuse it each time we do another
// attach / detach, so no need to destroy it.
+ // Attach/Load/Detach are all synchronized with the Status Crst, don't need to worry about races
// If we disabled concurrent GC and somehow failed later during the initialization
- if (g_profControlBlock.fConcurrentGCDisabledForAttach)
+ if (g_profControlBlock.fConcurrentGCDisabledForAttach.Load() && g_profControlBlock.IsMainProfiler(pProfilerInfo->pProfInterface))
{
+ g_profControlBlock.fConcurrentGCDisabledForAttach = FALSE;
+
// We know for sure GC has been fully initialized as we've turned off concurrent GC before
_ASSERTE(IsGarbageCollectorFullyInitialized());
GCHeapUtilities::GetGCHeap()->TemporaryEnableConcurrentGC();
- g_profControlBlock.fConcurrentGCDisabledForAttach = FALSE;
}
// #ProfileResetSessionStatus Reset all the status variables that are for the current
// profiling attach session.
// When you are adding new status in g_profControlBlock, you need to think about whether
// your new status is per-session, or consistent across sessions
- g_profControlBlock.ResetPerSessionStatus();
+ pProfilerInfo->ResetPerSessionStatus();
- g_profControlBlock.curProfStatus.Set(kProfStatusNone);
+ pProfilerInfo->curProfStatus.Set(kProfStatusNone);
+
+ g_profControlBlock.DeRegisterProfilerInfo(pProfilerInfo);
+
+ g_profControlBlock.UpdateGlobalEventMask();
}
}
diff --git a/src/coreclr/vm/profilinghelper.h b/src/coreclr/vm/profilinghelper.h
index 4c8ed1dc5c2..1cf7ea4ab50 100644
--- a/src/coreclr/vm/profilinghelper.h
+++ b/src/coreclr/vm/profilinghelper.h
@@ -64,52 +64,13 @@ public:
UINT cbClientData,
DWORD dwConcurrentGCWaitTimeoutInMs);
- static BOOL IsProfilerEvacuated();
- static void TerminateProfiling();
+ static BOOL IsProfilerEvacuated(ProfilerInfo *pDetachInfo);
+ static void TerminateProfiling(ProfilerInfo *pProfilerInfo);
static void LogProfError(int iStringResourceID, ...);
static void LogProfInfo(int iStringResourceID, ...);
static void LogNoInterfaceError(REFIID iidRequested, LPCWSTR wszClsid);
INDEBUG(static BOOL ShouldInjectProfAPIFault(ProfAPIFaultFlags faultFlag);)
-#ifdef FEATURE_PROFAPI_ATTACH_DETACH
- // ----------------------------------------------------------------------------
- // ProfilingAPIUtility::IncEvacuationCounter
- //
- // Description:
- // Simple helper to increase the evacuation counter inside an EE thread by one
- //
- // Arguments:
- // * pThread - pointer to an EE Thread
- //
- template<typename ThreadType>
- static FORCEINLINE void IncEvacuationCounter(ThreadType * pThread)
- {
- LIMITED_METHOD_CONTRACT;
-
- if (pThread)
- pThread->IncProfilerEvacuationCounter();
- }
-
- // ----------------------------------------------------------------------------
- // ProfilingAPIUtility::DecEvacuationCounter
- //
- // Description:
- // Simple helper to decrease the evacuation counter inside an EE thread by one
- //
- // Arguments:
- // * pThread - pointer to an EE Thread
- //
- template<typename ThreadType>
- static FORCEINLINE void DecEvacuationCounter(ThreadType * pThread)
- {
- LIMITED_METHOD_CONTRACT;
-
- if (pThread)
- pThread->DecProfilerEvacuationCounter();
- }
-
-#endif // FEATURE_PROFAPI_ATTACH_DETACH
-
// See code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
static CRITSEC_COOKIE GetStatusCrst();
@@ -147,6 +108,8 @@ private:
DWORD dwConcurrentGCWaitTimeoutInMs = INFINITE);
static HRESULT ProfilerCLSIDFromString(__inout_z LPWSTR wszClsid, CLSID * pClsid);
static HRESULT AttemptLoadProfilerForStartup();
+ static HRESULT AttemptLoadDelayedStartupProfilers();
+ static HRESULT AttemptLoadProfilerList();
static void AppendSupplementaryInformation(int iStringResource, SString * pString);
@@ -173,4 +136,11 @@ private:
DWORD m_dwOriginalFullState;
};
+FORCEINLINE void DeregisterProfilerIfNotificationOnly(ProfilerInfo *pProfilerInfo)
+{
+ g_profControlBlock.DeRegisterProfilerInfo(pProfilerInfo);
+}
+
+typedef Wrapper<ProfilerInfo *, DoNothing, DeregisterProfilerIfNotificationOnly> ProfilerInfoHolder;
+
#endif //__PROFILING_HELPER_H__
diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp
index 94161378380..c1e98330498 100644
--- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp
+++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp
@@ -177,7 +177,7 @@ enum ProfToClrEntrypointFlags
do \
{ \
if ((((p2eeFlags) & kP2EEAllowableAfterAttach) == 0) && \
- (g_profControlBlock.pProfInterface->IsLoadedViaAttach())) \
+ (m_pProfilerInfo->pProfInterface->IsLoadedViaAttach())) \
{ \
LOG((LF_CORPROF, \
LL_ERROR, \
@@ -214,10 +214,10 @@ enum ProfToClrEntrypointFlags
do \
{ \
INCONTRACT(AssertTriggersContract(((p2eeFlags) & kP2EETriggers))); \
- _ASSERTE(g_profControlBlock.curProfStatus.Get() != kProfStatusNone); \
+ _ASSERTE(m_pProfilerInfo->curProfStatus.Get() != kProfStatusNone); \
LOG(logParams); \
/* If profiler was neutered, disallow call */ \
- if (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \
+ if (m_pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching) \
{ \
LOG((LF_CORPROF, \
LL_ERROR, \
@@ -256,8 +256,8 @@ enum ProfToClrEntrypointFlags
do \
{ \
PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams); \
- if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad && \
- g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForAttachLoad) \
+ if (m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad && \
+ m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForAttachLoad) \
{ \
return CORPROF_E_CALL_ONLY_FROM_INIT; \
} \
@@ -622,13 +622,13 @@ void __stdcall ProfilerObjectAllocatedCallback(OBJECTREF objref, ClassID classId
// Notify the profiler of the allocation
{
- BEGIN_PIN_PROFILER(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations());
// Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs.
// Thus we strip any instantiations of the ClassID (which is really a type handle) here.
- g_profControlBlock.pProfInterface->ObjectAllocated(
+ g_profControlBlock.ObjectAllocated(
(ObjectID) OBJECTREFToObject(objref),
classId);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
}
@@ -661,18 +661,18 @@ void __stdcall GarbageCollectionStartedCallback(int generation, BOOL induced)
// Notify the profiler of start of the collection
{
- BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
BOOL generationCollected[COR_PRF_GC_PINNED_OBJECT_HEAP+1];
if (generation == COR_PRF_GC_GEN_2)
generation = COR_PRF_GC_PINNED_OBJECT_HEAP;
for (int gen = 0; gen <= COR_PRF_GC_PINNED_OBJECT_HEAP; gen++)
generationCollected[gen] = gen <= generation;
- g_profControlBlock.pProfInterface->GarbageCollectionStarted(
+ g_profControlBlock.GarbageCollectionStarted(
COR_PRF_GC_PINNED_OBJECT_HEAP+1,
generationCollected,
induced ? COR_PRF_GC_INDUCED : COR_PRF_GC_OTHER);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
}
@@ -695,9 +695,9 @@ void __stdcall GarbageCollectionFinishedCallback()
#ifdef PROFILING_SUPPORTED
// Notify the profiler of end of the collection
{
- BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
- g_profControlBlock.pProfInterface->GarbageCollectionFinished();
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
+ g_profControlBlock.GarbageCollectionFinished();
+ END_PROFILER_CALLBACK();
}
// Mark that GC is finished.
@@ -1131,7 +1131,7 @@ bool HeapWalkHelper(Object * pBO, void * pvContext)
// It is not safe and could be overflowed to downcast size_t to ULONG on WIN64.
// However, we have to do this dangerous downcast here to comply with the existing Profiling COM interface.
// We are currently evaluating ways to fix this potential overflow issue.
- hr = g_profControlBlock.pProfInterface->ObjectReference(
+ hr = g_profControlBlock.ObjectReference(
(ObjectID) pBO,
SafeGetClassIDFromObject(pBO),
(ULONG) cNumRefs,
@@ -1210,13 +1210,13 @@ bool AllocByClassHelper(Object * pBO, void * pv)
_ASSERTE(pv != NULL);
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackAllocations());
// Pass along the call
- g_profControlBlock.pProfInterface->AllocByClass(
+ g_profControlBlock.AllocByClass(
(ObjectID) pBO,
SafeGetClassIDFromObject(pBO),
pv);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
return TRUE;
@@ -1286,8 +1286,7 @@ void ScanRootsHelper(Object* pObj, Object ** ppRoot, ScanContext *pSC, uint32_t
if (pPSC->fProfilerPinned)
{
// Let the profiling code know about this root reference
- g_profControlBlock.pProfInterface->
- RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId));
+ g_profControlBlock.RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId));
}
#endif
@@ -1451,7 +1450,7 @@ HRESULT ProfToEEInterfaceImpl::SetEventMask(DWORD dwEventMask)
_ASSERTE(CORProfilerPresentOrInitializing());
- return g_profControlBlock.pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */);
+ return m_pProfilerInfo->pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */);
}
HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHigh)
@@ -1483,7 +1482,7 @@ HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHi
_ASSERTE(CORProfilerPresentOrInitializing());
- return g_profControlBlock.pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh);
+ return m_pProfilerInfo->pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh);
}
@@ -2571,7 +2570,7 @@ HRESULT ProfToEEInterfaceImpl::GetEventMask(DWORD * pdwEvents)
return E_INVALIDARG;
}
- *pdwEvents = g_profControlBlock.dwEventMask;
+ *pdwEvents = m_pProfilerInfo->eventMask.GetEventMask();
return S_OK;
}
@@ -2608,8 +2607,8 @@ HRESULT ProfToEEInterfaceImpl::GetEventMask2(DWORD *pdwEventsLow, DWORD *pdwEven
return E_INVALIDARG;
}
- *pdwEventsLow = g_profControlBlock.dwEventMask;
- *pdwEventsHigh = g_profControlBlock.dwEventMaskHigh;
+ *pdwEventsLow = m_pProfilerInfo->eventMask.GetEventMask();
+ *pdwEventsHigh = m_pProfilerInfo->eventMask.GetEventMaskHigh();
return S_OK;
}
@@ -4462,6 +4461,11 @@ HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId,
return E_INVALIDARG;
}
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
Module *pModule; // Working pointer for real class.
HRESULT hr = S_OK;
@@ -4478,7 +4482,7 @@ HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId,
}
// Remember the profiler is doing this, as that means we must never detach it!
- g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag();
// This action is not temporary!
// If the profiler want to be able to revert, they need to use
@@ -5751,7 +5755,12 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncE
pFuncLeave,
pFuncTailcall));
- return g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall);
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
+ return g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall);
}
@@ -5787,8 +5796,13 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFun
pFuncLeave,
pFuncTailcall));
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
return
- g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall);
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall);
}
@@ -5824,8 +5838,13 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFun
pFuncLeave3,
pFuncTailcall3));
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
return
- g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3,
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3,
pFuncLeave3,
pFuncTailcall3);
}
@@ -5864,8 +5883,13 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter
pFuncLeave3WithInfo,
pFuncTailcall3WithInfo));
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
return
- g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo,
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo,
pFuncLeave3WithInfo,
pFuncTailcall3WithInfo);
}
@@ -5898,7 +5922,12 @@ HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper(FunctionIDMapper *pFunc)
"**PROF: SetFunctionIDMapper 0x%p.\n",
pFunc));
- g_profControlBlock.pProfInterface->SetFunctionIDMapper(pFunc);
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetFunctionIDMapper(pFunc);
return (S_OK);
}
@@ -5931,7 +5960,12 @@ HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper2(FunctionIDMapper2 *pFunc, vo
pFunc,
clientData));
- g_profControlBlock.pProfInterface->SetFunctionIDMapper2(pFunc, clientData);
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetFunctionIDMapper2(pFunc, clientData);
return (S_OK);
}
@@ -6709,7 +6743,12 @@ HRESULT ProfToEEInterfaceImpl::RequestReJITWithInliners(
LL_INFO1000,
"**PROF: RequestReJITWithInliners.\n"));
- if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
+ if (!m_pProfilerInfo->pProfInterface->IsCallback4Supported())
{
return CORPROF_E_CALLBACK4_REQUIRED;
}
@@ -6737,7 +6776,7 @@ HRESULT ProfToEEInterfaceImpl::RequestReJITWithInliners(
}
// Remember the profiler is doing this, as that means we must never detach it!
- g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag();
HRESULT hr = SetupThreadForReJIT();
if (FAILED(hr))
@@ -7067,7 +7106,8 @@ HRESULT ProfToEEInterfaceImpl::EventPipeStartSession(
EP_SERIALIZATION_FORMAT_NETTRACE_V4,
requestRundown,
NULL,
- reinterpret_cast<EventPipeSessionSynchronousCallback>(&ProfToEEInterfaceImpl::EventPipeCallbackHelper));
+ reinterpret_cast<EventPipeSessionSynchronousCallback>(&ProfToEEInterfaceImpl::EventPipeCallbackHelper),
+ reinterpret_cast<void *>(m_pProfilerInfo));
if (sessionID != 0)
{
EventPipeAdapter::StartStreaming(sessionID);
@@ -7378,28 +7418,33 @@ void ProfToEEInterfaceImpl::EventPipeCallbackHelper(EventPipeProvider *provider,
LPCGUID pRelatedActivityId,
Thread *pEventThread,
ULONG numStackFrames,
- UINT_PTR stackFrames[])
-{
- // If we got here we know a profiler has started an EventPipe session
- BEGIN_PIN_PROFILER(true);
- // But, a profiler could always register for a session and then detach without
- // closing the session. So check if we have an interface before proceeding.
- if (g_profControlBlock.pProfInterface != nullptr)
- {
- g_profControlBlock.pProfInterface->EventPipeEventDelivered(provider,
- eventId,
- eventVersion,
- cbMetadataBlob,
- metadataBlob,
- cbEventData,
- eventData,
- pActivityId,
- pRelatedActivityId,
- pEventThread,
- numStackFrames,
- stackFrames);
- }
- END_PIN_PROFILER();
+ UINT_PTR stackFrames[],
+ void *additionalData)
+{
+ _ASSERTE(additionalData != NULL);
+ ProfilerInfo *pProfilerInfo = reinterpret_cast<ProfilerInfo *>(additionalData);
+
+ _ASSERTE(pProfilerInfo->pProfInterface.Load() != NULL);
+ {
+ EvacuationCounterHolder holder(pProfilerInfo);
+ // But, a profiler could always register for a session and then detach without
+ // closing the session. So check if we have an interface before proceeding.
+ if (pProfilerInfo->pProfInterface.Load() != NULL)
+ {
+ pProfilerInfo->pProfInterface->EventPipeEventDelivered(provider,
+ eventId,
+ eventVersion,
+ cbMetadataBlob,
+ metadataBlob,
+ cbEventData,
+ eventData,
+ pActivityId,
+ pRelatedActivityId,
+ pEventThread,
+ numStackFrames,
+ stackFrames);
+ }
+ }
};
@@ -9116,7 +9161,12 @@ HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in
LL_INFO1000,
"**PROF: RequestReJIT.\n"));
- if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
+ if (!m_pProfilerInfo->pProfInterface->IsCallback4Supported())
{
return CORPROF_E_CALLBACK4_REQUIRED;
}
@@ -9133,7 +9183,7 @@ HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in
}
// Remember the profiler is doing this, as that means we must never detach it!
- g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag();
HRESULT hr = SetupThreadForReJIT();
if (FAILED(hr))
@@ -9178,6 +9228,11 @@ HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in
LL_INFO1000,
"**PROF: RequestRevert.\n"));
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
if (!CORProfilerEnableRejit())
{
return CORPROF_E_REJIT_NOT_ENABLED;
@@ -9190,7 +9245,7 @@ HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in
}
// Remember the profiler is doing this, as that means we must never detach it!
- g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
+ g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag();
// Initialize the status array
if (rgHrStatuses != NULL)
@@ -9497,7 +9552,7 @@ HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionM
"**PROF: RequestProfilerDetach.\n"));
#ifdef FEATURE_PROFAPI_ATTACH_DETACH
- return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
+ return ProfilingAPIDetach::RequestProfilerDetach(g_profControlBlock.GetProfilerInfo(this), dwExpectedCompletionMilliseconds);
#else // FEATURE_PROFAPI_ATTACH_DETACH
return E_NOTIMPL;
#endif // FEATURE_PROFAPI_ATTACH_DETACH
@@ -9710,7 +9765,12 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId,
LL_INFO1000,
"**PROF: GetFunctionEnter3Info.\n"));
- _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook() != NULL);
+
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
if (!CORProfilerELT3SlowPathEnterEnabled())
{
@@ -9868,7 +9928,12 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId,
LL_INFO1000,
"**PROF: GetFunctionLeave3Info.\n"));
- _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
+
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook() != NULL);
if (!CORProfilerELT3SlowPathLeaveEnabled())
{
@@ -10000,7 +10065,12 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId,
LL_INFO1000,
"**PROF: GetFunctionTailcall3Info.\n"));
- _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook() != NULL);
+
+ if (!g_profControlBlock.IsMainProfiler(this))
+ {
+ return E_INVALIDARG;
+ }
if (!CORProfilerELT3SlowPathTailcallEnabled())
{
@@ -10409,10 +10479,9 @@ void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
// Do not notify the profiler about QCalls
if (pMD == NULL || !pMD->IsQCall())
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
- g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
- reason);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackTransitions());
+ g_profControlBlock.ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD), reason);
+ END_PROFILER_CALLBACK();
}
}
@@ -10444,10 +10513,9 @@ void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
// Do not notify the profiler about QCalls
if (pMD == NULL || !pMD->IsQCall())
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
- g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
- reason);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackTransitions());
+ g_profControlBlock.UnmanagedToManagedTransition(MethodDescToFunctionID(pMD), reason);
+ END_PROFILER_CALLBACK();
}
}
@@ -10472,12 +10540,12 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi
// code:ProfControlBlock#TestOnlyELT
if (g_profControlBlock.fTestOnlyForceEnterLeave)
{
- if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
+ if ((g_profControlBlock.mainProfilerInfo.pProfInterface.Load() == NULL) ||
(
- (g_profControlBlock.pProfInterface->GetEnterHook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetEnter2Hook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnterHook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3Hook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook() == NULL)
)
)
{
@@ -10487,7 +10555,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi
#endif // PROF_TEST_ONLY_FORCE_ELT
// ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
- _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3Hook() == NULL);
_ASSERTE(GetThread()->PreemptiveGCDisabled());
_ASSERTE(platformSpecificHandle != NULL);
@@ -10505,21 +10573,21 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi
//
// CLR v4 Slow-Path ELT
//
- if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
+ if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook() != NULL)
{
FunctionIDOrClientID functionIDOrClientID;
functionIDOrClientID.clientID = clientData;
- g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook()(
functionIDOrClientID,
(COR_PRF_ELT_INFO)&eltInfo);
goto LExit;
}
- if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
+ if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook() != NULL)
{
// We have run out of heap memory, so the content of the mapping table becomes stale.
// All Whidbey ETL hooks must be turned off.
- if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
+ if (!g_profControlBlock.mainProfilerInfo.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
{
goto LExit;
}
@@ -10531,14 +10599,14 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi
// key to retrieve the corresponding clientID from the internal FunctionID hash table.
FunctionID functionId = clientData;
_ASSERTE(functionId != NULL);
- clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
+ clientData = g_profControlBlock.mainProfilerInfo.pProfInterface->LookupClientIDFromCache(functionId);
//
// Whidbey Fast-Path ELT
//
if (CORProfilerELT2FastPathEnterEnabled())
{
- g_profControlBlock.pProfInterface->GetEnter2Hook()(
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook()(
functionId,
clientData,
NULL,
@@ -10594,7 +10662,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi
HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
_ASSERTE(hr == S_OK);
- g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
goto LExit;
}
@@ -10606,7 +10674,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi
// in the first place. (Note that SetEnterLeaveFunctionHooks* will return
// an error unless it's called in the profiler's Initialize(), so a profiler can't change
// its mind about where the hooks are.)
- _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnterHook() != NULL);
// Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
// COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
@@ -10618,7 +10686,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi
// Everett ELT
//
{
- g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnterHook()((FunctionID)clientData);
}
LExit:
@@ -10644,12 +10712,12 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi
// code:ProfControlBlock#TestOnlyELT
if (g_profControlBlock.fTestOnlyForceEnterLeave)
{
- if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
+ if ((g_profControlBlock.mainProfilerInfo.pProfInterface.Load() == NULL) ||
(
- (g_profControlBlock.pProfInterface->GetLeaveHook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetLeave2Hook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeaveHook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3Hook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook() == NULL)
)
)
{
@@ -10659,7 +10727,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi
#endif // PROF_TEST_ONLY_FORCE_ELT
// ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
- _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3Hook() == NULL);
_ASSERTE(GetThread()->PreemptiveGCDisabled());
_ASSERTE(platformSpecificHandle != NULL);
@@ -10677,21 +10745,21 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi
//
// CLR v4 Slow-Path ELT
//
- if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
+ if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook() != NULL)
{
FunctionIDOrClientID functionIDOrClientID;
functionIDOrClientID.clientID = clientData;
- g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook()(
functionIDOrClientID,
(COR_PRF_ELT_INFO)&eltInfo);
goto LExit;
}
- if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
+ if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook() != NULL)
{
// We have run out of heap memory, so the content of the mapping table becomes stale.
// All Whidbey ETL hooks must be turned off.
- if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
+ if (!g_profControlBlock.mainProfilerInfo.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
{
goto LExit;
}
@@ -10703,14 +10771,14 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi
// key to retrieve the corresponding clientID from the internal FunctionID hash table.
FunctionID functionId = clientData;
_ASSERTE(functionId != NULL);
- clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
+ clientData = g_profControlBlock.mainProfilerInfo.pProfInterface->LookupClientIDFromCache(functionId);
//
// Whidbey Fast-Path ELT
//
if (CORProfilerELT2FastPathLeaveEnabled())
{
- g_profControlBlock.pProfInterface->GetLeave2Hook()(
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook()(
functionId,
clientData,
NULL,
@@ -10727,7 +10795,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi
HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
_ASSERTE(hr == S_OK);
- g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
goto LExit;
}
@@ -10737,7 +10805,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi
// in the first place. (Note that SetEnterLeaveFunctionHooks* will return
// an error unless it's called in the profiler's Initialize(), so a profiler can't change
// its mind about where the hooks are.)
- _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeaveHook() != NULL);
// Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
// COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
@@ -10749,7 +10817,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi
// Everett ELT
//
{
- g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeaveHook()((FunctionID)clientData);
}
LExit:
@@ -10776,12 +10844,12 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
// code:ProfControlBlock#TestOnlyELT
if (g_profControlBlock.fTestOnlyForceEnterLeave)
{
- if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
+ if ((g_profControlBlock.mainProfilerInfo.pProfInterface.Load() == NULL) ||
(
- (g_profControlBlock.pProfInterface->GetTailcallHook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetTailcall2Hook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL) &&
- (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcallHook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3Hook() == NULL) &&
+ (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook() == NULL)
)
)
{
@@ -10791,7 +10859,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
#endif // PROF_TEST_ONLY_FORCE_ELT
// ELT3 fast-path hooks should be NULL when ELT intermediary is used.
- _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3Hook() == NULL);
_ASSERTE(GetThread()->PreemptiveGCDisabled());
_ASSERTE(platformSpecificHandle != NULL);
@@ -10809,21 +10877,21 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
//
// CLR v4 Slow-Path ELT
//
- if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
+ if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook() != NULL)
{
FunctionIDOrClientID functionIDOrClientID;
functionIDOrClientID.clientID = clientData;
- g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook()(
functionIDOrClientID,
(COR_PRF_ELT_INFO)&eltInfo);
goto LExit;
}
- if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
+ if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook() != NULL)
{
// We have run out of heap memory, so the content of the mapping table becomes stale.
// All Whidbey ETL hooks must be turned off.
- if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
+ if (!g_profControlBlock.mainProfilerInfo.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
{
goto LExit;
}
@@ -10835,14 +10903,14 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
// key to retrieve the corresponding clientID from the internal FunctionID hash table.
FunctionID functionId = clientData;
_ASSERTE(functionId != NULL);
- clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
+ clientData = g_profControlBlock.mainProfilerInfo.pProfInterface->LookupClientIDFromCache(functionId);
//
// Whidbey Fast-Path ELT
//
if (CORProfilerELT2FastPathTailcallEnabled())
{
- g_profControlBlock.pProfInterface->GetTailcall2Hook()(
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook()(
functionId,
clientData,
NULL);
@@ -10857,7 +10925,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
_ASSERTE(hr == S_OK);
- g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
goto LExit;
}
@@ -10867,7 +10935,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
// in the first place. (Note that SetEnterLeaveFunctionHooks* will return
// an error unless it's called in the profiler's Initialize(), so a profiler can't change
// its mind about where the hooks are.)
- _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
+ _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcallHook() != NULL);
// Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
// COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
@@ -10878,7 +10946,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
//
// Everett ELT
//
- g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
+ g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcallHook()((FunctionID)clientData);
LExit:
diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.h b/src/coreclr/vm/proftoeeinterfaceimpl.h
index de5b75a3434..1cb340713ac 100644
--- a/src/coreclr/vm/proftoeeinterfaceimpl.h
+++ b/src/coreclr/vm/proftoeeinterfaceimpl.h
@@ -145,6 +145,9 @@ typedef struct _PROFILER_STACK_WALK_DATA PROFILER_STACK_WALK_DATA;
class ProfToEEInterfaceImpl : public ICorProfilerInfo12
{
+private:
+ ProfilerInfo *m_pProfilerInfo;
+
public:
// Internal Housekeeping
@@ -156,6 +159,12 @@ public:
virtual ~ProfToEEInterfaceImpl();
HRESULT Init();
+ void SetProfilerInfo(ProfilerInfo *pProfilerInfo)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pProfilerInfo = pProfilerInfo;
+ }
+
// IUnknown
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
@@ -694,7 +703,6 @@ public:
protected:
// Internal Helper Functions
-
static void EventPipeCallbackHelper(EventPipeProvider *provider,
DWORD eventId,
DWORD eventVersion,
@@ -706,7 +714,8 @@ protected:
LPCGUID pRelatedActivityId,
Thread *pEventThread,
ULONG numStackFrames,
- UINT_PTR stackFrames[]);
+ UINT_PTR stackFrames[],
+ void *additionalData);
HRESULT GetCodeInfoHelper(FunctionID functionId,
ReJITID reJitId,
diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp
index a7a7e0394a1..cf2803dec93 100644
--- a/src/coreclr/vm/readytoruninfo.cpp
+++ b/src/coreclr/vm/readytoruninfo.cpp
@@ -946,10 +946,10 @@ PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig
#ifndef CROSSGEN_COMPILE
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
- g_profControlBlock.pProfInterface->
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches());
+ (&g_profControlBlock)->
JITCachedFunctionSearchStarted((FunctionID)pMD, &fShouldSearchCache);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
if (!fShouldSearchCache)
{
@@ -1001,10 +1001,10 @@ PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig
#ifndef CROSSGEN_COMPILE
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
- g_profControlBlock.pProfInterface->
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches());
+ (&g_profControlBlock)->
JITCachedFunctionSearchFinished((FunctionID)pMD, COR_PRF_CACHED_FUNCTION_FOUND);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
#endif // CROSSGEN_COMPILE
diff --git a/src/coreclr/vm/rejit.cpp b/src/coreclr/vm/rejit.cpp
index ff180ceba33..d66c999c7ce 100644
--- a/src/coreclr/vm/rejit.cpp
+++ b/src/coreclr/vm/rejit.cpp
@@ -1079,12 +1079,12 @@ HRESULT ReJitManager::ConfigureILCodeVersion(ILCodeVersion ilCodeVersion)
}
else
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
- hr = g_profControlBlock.pProfInterface->GetReJITParameters(
+ BEGIN_PROFILER_CALLBACK(CORProfilerPresent());
+ hr = (&g_profControlBlock)->GetReJITParameters(
(ModuleID)pModule,
methodDef,
pFuncControl);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
}
diff --git a/src/coreclr/vm/rejit.inl b/src/coreclr/vm/rejit.inl
index b69b63d9f55..f59c536af78 100644
--- a/src/coreclr/vm/rejit.inl
+++ b/src/coreclr/vm/rejit.inl
@@ -68,17 +68,17 @@ inline void ReJitManager::ReportReJITError(Module* pModule, mdMethodDef methodDe
CONTRACTL_END;
{
- BEGIN_PIN_PROFILER(CORProfilerPresent());
+ BEGIN_PROFILER_CALLBACK(CORProfilerEnableRejit());
_ASSERTE(CORProfilerEnableRejit());
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ReJITError(
+ (&g_profControlBlock)->mainProfilerInfo.pProfInterface->ReJITError(
reinterpret_cast< ModuleID > (pModule),
methodDef,
reinterpret_cast< FunctionID > (pMD),
hrStatus);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
}
diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp
index 401be0abd27..a8851f307ed 100644
--- a/src/coreclr/vm/runtimehandles.cpp
+++ b/src/coreclr/vm/runtimehandles.cpp
@@ -2304,9 +2304,9 @@ void QCALLTYPE RuntimeMethodHandle::Destroy(MethodDesc * pMethod)
// Fire Unload Dynamic Method Event here
ETW::MethodLog::DynamicMethodDestroyed(pMethod);
- BEGIN_PIN_PROFILER(CORProfilerIsMonitoringDynamicFunctionUnloads());
- g_profControlBlock.pProfInterface->DynamicMethodUnloaded((FunctionID)pMethod);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackDynamicFunctionUnloads());
+ (&g_profControlBlock)->DynamicMethodUnloaded((FunctionID)pMethod);
+ END_PROFILER_CALLBACK();
pDynamicMethodDesc->Destroy();
diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index ee66f3ebe63..4dfa4a22b3f 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -762,17 +762,17 @@ Thread* SetupThread()
// thread has been created.
if (!IsGCSpecialThread())
{
- BEGIN_PIN_PROFILER(CORProfilerTrackThreads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads());
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ThreadCreated(
+ (&g_profControlBlock)->ThreadCreated(
(ThreadID)pThread);
}
DWORD osThreadId = ::GetCurrentThreadId();
- g_profControlBlock.pProfInterface->ThreadAssignedToOSThread(
+ (&g_profControlBlock)->ThreadAssignedToOSThread(
(ThreadID)pThread, osThreadId);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -1429,9 +1429,6 @@ Thread::Thread()
m_debuggerFilterContext = NULL;
m_fInteropDebuggingHijacked = FALSE;
m_profilerCallbackState = 0;
-#if defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA)
- m_dwProfilerEvacuationCounter = 0;
-#endif // defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA)
m_pProfilerFilterContext = NULL;
@@ -1871,20 +1868,20 @@ BOOL Thread::HasStarted()
// information
if (!IsGCSpecial())
{
- BEGIN_PIN_PROFILER(CORProfilerTrackThreads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads());
BOOL gcOnTransition = GC_ON_TRANSITIONS(FALSE); // disable GCStress 2 to avoid the profiler receiving a RuntimeThreadSuspended notification even before the ThreadCreated notification
-
+
{
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ThreadCreated((ThreadID) this);
+ (&g_profControlBlock)->ThreadCreated((ThreadID) this);
}
GC_ON_TRANSITIONS(gcOnTransition);
DWORD osThreadId = ::GetCurrentThreadId();
- g_profControlBlock.pProfInterface->ThreadAssignedToOSThread(
+ (&g_profControlBlock)->ThreadAssignedToOSThread(
(ThreadID) this, osThreadId);
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -3009,10 +3006,10 @@ void Thread::OnThreadTerminate(BOOL holdingLock)
#ifdef PROFILING_SUPPORTED
// If a profiler is present, then notify the profiler of thread destroy
{
- BEGIN_PIN_PROFILER(CORProfilerTrackThreads());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads());
GCX_PREEMP();
- g_profControlBlock.pProfInterface->ThreadDestroyed((ThreadID) this);
- END_PIN_PROFILER();
+ (&g_profControlBlock)->ThreadDestroyed((ThreadID) this);
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h
index 5fe312d8e86..0aadbf40260 100644
--- a/src/coreclr/vm/threads.h
+++ b/src/coreclr/vm/threads.h
@@ -3623,16 +3623,6 @@ private:
//---------------------------------------------------------------
DWORD m_profilerCallbackState;
-#if defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA)
- //---------------------------------------------------------------
- // m_dwProfilerEvacuationCounter keeps track of how many profiler
- // callback calls remain on the stack
- //---------------------------------------------------------------
- // Why volatile?
- // See code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization.
- Volatile<DWORD> m_dwProfilerEvacuationCounter;
-#endif // defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA)
-
private:
UINT32 m_workerThreadPoolCompletionCount;
static UINT64 s_workerThreadPoolCompletionCountOverflow;
@@ -3802,30 +3792,6 @@ public:
return m_pProfilerFilterContext;
}
-#ifdef PROFILING_SUPPORTED
-
- FORCEINLINE DWORD GetProfilerEvacuationCounter(void)
- {
- LIMITED_METHOD_CONTRACT;
- return m_dwProfilerEvacuationCounter;
- }
-
- FORCEINLINE void IncProfilerEvacuationCounter(void)
- {
- LIMITED_METHOD_CONTRACT;
- m_dwProfilerEvacuationCounter++;
- _ASSERTE(m_dwProfilerEvacuationCounter != 0U);
- }
-
- FORCEINLINE void DecProfilerEvacuationCounter(void)
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(m_dwProfilerEvacuationCounter != 0U);
- m_dwProfilerEvacuationCounter--;
- }
-
-#endif // PROFILING_SUPPORTED
-
//-------------------------------------------------------------------------
// The hijack lock enforces that a thread on which a profiler is currently
// performing a stack walk cannot be hijacked.
diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp
index d9d2c9b0ee7..cf09d505b1c 100644
--- a/src/coreclr/vm/threadsuspend.cpp
+++ b/src/coreclr/vm/threadsuspend.cpp
@@ -401,12 +401,12 @@ retry:
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
if (str == STR_Success)
{
- g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this);
+ (&g_profControlBlock)->RuntimeThreadSuspended((ThreadID)this);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -456,12 +456,12 @@ DWORD Thread::ResumeThread()
}
#ifdef PROFILING_SUPPORTED
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
if ((res != 0) && (res != (DWORD)-1))
{
- g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)this);
+ (&g_profControlBlock)->RuntimeThreadResumed((ThreadID)this);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif
return res;
@@ -2142,12 +2142,12 @@ void Thread::RareDisablePreemptiveGC()
// If profiler desires GC events, notify it that this thread is waiting until the GC is over
// Do not send suspend notifications for debugger suspensions
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
if (!(m_State & TS_DebugSuspendPending))
{
- g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this);
+ (&g_profControlBlock)->RuntimeThreadSuspended((ThreadID)this);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -2168,9 +2168,9 @@ void Thread::RareDisablePreemptiveGC()
#ifdef PROFILING_SUPPORTED
// Let the profiler know that this thread is resuming
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
- g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)this);
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
+ (&g_profControlBlock)->RuntimeThreadResumed((ThreadID)this);
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
}
@@ -3226,12 +3226,12 @@ void ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason)
// If the profiler desires information about GCs, then let it know that one
// is starting.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
_ASSERTE(reason != ThreadSuspend::SUSPEND_FOR_DEBUGGER);
_ASSERTE(reason != ThreadSuspend::SUSPEND_FOR_DEBUGGER_SWEEP);
{
- g_profControlBlock.pProfInterface->RuntimeSuspendStarted(
+ (&g_profControlBlock)->RuntimeSuspendStarted(
GCSuspendReasonToProfSuspendReason(reason));
}
if (pCurThread)
@@ -3239,9 +3239,9 @@ void ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason)
// Notify the profiler that the thread that is actually doing the GC is 'suspended',
// meaning that it is doing stuff other than run the managed code it was before the
// GC started.
- g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)pCurThread);
+ (&g_profControlBlock)->RuntimeThreadSuspended((ThreadID)pCurThread);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -3588,9 +3588,9 @@ void ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason)
#ifdef PROFILING_SUPPORTED
// If a profiler is keeping track of GC events, notify it
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
- g_profControlBlock.pProfInterface->RuntimeSuspendFinished();
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
+ (&g_profControlBlock)->RuntimeSuspendFinished();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -3711,12 +3711,12 @@ void ThreadSuspend::ResumeRuntime(BOOL bFinishedGC, BOOL SuspendSucceded)
#ifdef PROFILING_SUPPORTED
// Need to give resume event for the GC thread
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
if (pCurThread)
{
- g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)pCurThread);
+ (&g_profControlBlock)->RuntimeThreadResumed((ThreadID)pCurThread);
}
- END_PIN_PROFILER();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -3739,10 +3739,10 @@ void ThreadSuspend::ResumeRuntime(BOOL bFinishedGC, BOOL SuspendSucceded)
// This thread is logically "resuming" from a GC now. Tell the profiler.
//
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
GCX_PREEMP();
- g_profControlBlock.pProfInterface->RuntimeResumeFinished();
- END_PIN_PROFILER();
+ (&g_profControlBlock)->RuntimeResumeFinished();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED
@@ -5481,9 +5481,9 @@ void ThreadSuspend::RestartEE(BOOL bFinishedGC, BOOL SuspendSucceded)
// corresponding call to RuntimeSuspendStarted is done at a lower architectural layer,
// in ThreadSuspend::SuspendRuntime.
{
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
- g_profControlBlock.pProfInterface->RuntimeResumeStarted();
- END_PIN_PROFILER();
+ BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends());
+ (&g_profControlBlock)->RuntimeResumeStarted();
+ END_PROFILER_CALLBACK();
}
#endif // PROFILING_SUPPORTED