summaryrefslogtreecommitdiff
path: root/src/vm/profilinghelper.inl
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/profilinghelper.inl')
-rw-r--r--src/vm/profilinghelper.inl276
1 files changed, 276 insertions, 0 deletions
diff --git a/src/vm/profilinghelper.inl b/src/vm/profilinghelper.inl
new file mode 100644
index 0000000000..b195a3165e
--- /dev/null
+++ b/src/vm/profilinghelper.inl
@@ -0,0 +1,276 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// ProfilingHelper.inl
+//
+
+//
+// Inlined implementation of some helper class methods used for
+// miscellaneous purposes within the profiling API
+//
+
+// ======================================================================================
+
+#ifndef __PROFILING_HELPER_INL__
+#define __PROFILING_HELPER_INL__
+
+FORCEINLINE SetCallbackStateFlagsHolder::SetCallbackStateFlagsHolder(DWORD dwFlags)
+{
+ // This is called before entering a profiler. We set the specified dwFlags on
+ // the Thread object, and remember the previous flags for later.
+ BEGIN_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;
+ m_pThread = GetThread();
+ if (m_pThread != NULL)
+ {
+ m_dwOriginalFullState = m_pThread->SetProfilerCallbackStateFlags(dwFlags);
+ }
+ else
+ {
+ m_dwOriginalFullState = 0;
+ }
+ END_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;
+}
+
+FORCEINLINE SetCallbackStateFlagsHolder::~SetCallbackStateFlagsHolder()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ // This is called after the profiler returns to us. We reinstate the
+ // original flag set here.
+ if (m_pThread != NULL)
+ {
+ BEGIN_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;
+ m_pThread->SetProfilerCallbackFullState(m_dwOriginalFullState);
+ END_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;
+ }
+}
+
+#ifdef ENABLE_CONTRACTS
+//---------------------------------------------------------------------------------------
+//
+// This function, used only on debug builds, fetches the triggers bits from the contract
+// to help verify that the contract is compatible with the flags passed in to the
+// entrypoint macros.
+//
+// Arguments:
+// * fTriggers - If nonzero, this function asserts the contract says GC_TRIGGERS,
+// else this function asserts the contract says GC_NOTRIGGER
+//
+inline void AssertTriggersContract(BOOL fTriggers)
+{
+ // NOTE: This function cannot have contract, as this function needs to inspect the
+ // contract of the calling function
+
+ ClrDebugState * pClrDbgState = GetClrDebugState(FALSE);
+ if ((pClrDbgState == NULL) || (pClrDbgState->GetContractStackTrace() == NULL))
+ {
+ return;
+ }
+
+ UINT testMask = pClrDbgState->GetContractStackTrace()->m_testmask;
+
+ if (fTriggers)
+ {
+ // If this assert fires, the contract says GC_NOTRIGGER (or is disabled), but the
+ // PROFILER_TO_CLR_ENTRYPOINT* / CLR_TO_PROFILER_ENTRYPOINT* macro implies triggers
+ _ASSERTE((testMask & Contract::GC_Mask) == Contract::GC_Triggers);
+ }
+ else
+ {
+ // If this assert fires, the contract says GC_TRIGGERS, but the
+ // PROFILER_TO_CLR_ENTRYPOINT* / CLR_TO_PROFILER_ENTRYPOINT* macro implies no
+ // trigger
+ _ASSERTE(((testMask & Contract::GC_Mask) == Contract::GC_NoTrigger) ||
+ ((testMask & Contract::GC_Disabled) != 0));
+
+ }
+}
+#endif //ENABLE_CONTRACTS
+
+// ----------------------------------------------------------------------------
+// ProfilingAPIUtility::LogNoInterfaceError
+//
+// Description:
+// Simple helper to log an IDS_E_PROF_NO_CALLBACK_IFACE event
+//
+// Arguments:
+// * iidRequested - IID to convert to string and log (as insertion string)
+// * wszCLSID - CLSID to log (as insertion string)
+//
+
+// static
+inline void ProfilingAPIUtility::LogNoInterfaceError(REFIID iidRequested, LPCWSTR wszCLSID)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ SO_INTOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ WCHAR wszIidRequested[39];
+ if (StringFromGUID2(iidRequested, wszIidRequested, lengthof(wszIidRequested)) == 0)
+ {
+ // This is a little super-paranoid; but just use an empty string if GUIDs
+ // get bigger than we expect.
+ _ASSERTE(!"IID buffer too small.");
+ wszIidRequested[0] = L'\0';
+ }
+ ProfilingAPIUtility::LogProfError(IDS_E_PROF_NO_CALLBACK_IFACE, wszCLSID, wszIidRequested);
+}
+
+#ifdef _DEBUG
+
+// ----------------------------------------------------------------------------
+// ProfilingAPIUtility::ShouldInjectProfAPIFault
+//
+// Description:
+// Determines whether COMPlus_ProfAPIFault is set to a bitmask value
+// with the specified flag set
+//
+// Return Value:
+// Nonzero if the specified fault flag is set; 0 otherwise.
+//
+
+// static
+inline BOOL ProfilingAPIUtility::ShouldInjectProfAPIFault(ProfAPIFaultFlags faultFlag)
+{
+ return ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ProfAPIFault) & faultFlag) != 0);
+}
+
+#endif // _DEBUG
+
+
+// ----------------------------------------------------------------------------
+// ProfilingAPIUtility::LoadProfilerForAttach
+//
+// Description:
+// Simple, public wrapper around code:ProfilingAPIUtility::LoadProfiler to load a
+// profiler in response to an Attach request.
+//
+// Arguments:
+// * pClsid - Profiler's CLSID
+// * wszProfilerDLL - Profiler's DLL
+// * pvClientData - Client data received from trigger, to send to profiler DLL
+// * cbClientData - Size of client data
+//
+// Return Value:
+// HRESULT indicating success or failure
+//
+
+// static
+inline HRESULT ProfilingAPIUtility::LoadProfilerForAttach(
+ const CLSID * pClsid,
+ LPCWSTR wszProfilerDLL,
+ LPVOID pvClientData,
+ UINT cbClientData,
+ DWORD dwConcurrentGCWaitTimeoutInMs)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+
+ // This causes events to be logged, which loads resource strings,
+ // which takes locks.
+ CAN_TAKE_LOCK;
+
+ MODE_PREEMPTIVE;
+ }
+ CONTRACTL_END;
+
+ // Need string version of CLSID for event log messages
+ WCHAR wszClsid[40];
+ if (StringFromGUID2(*pClsid, wszClsid, _countof(wszClsid)) == 0)
+ {
+ _ASSERTE(!"StringFromGUID2 failed!");
+ return E_UNEXPECTED;
+ }
+
+ // Inform user we're about to try attaching the profiler
+ ProfilingAPIUtility::LogProfInfo(IDS_PROF_ATTACH_REQUEST_RECEIVED, wszClsid);
+
+ return LoadProfiler(
+ kAttachLoad,
+ pClsid,
+ wszClsid,
+ wszProfilerDLL,
+ pvClientData,
+ cbClientData,
+ dwConcurrentGCWaitTimeoutInMs);
+}
+
+inline /* static */ CRITSEC_COOKIE ProfilingAPIUtility::GetStatusCrst()
+{
+ LIMITED_METHOD_CONTRACT;
+ return s_csStatus;
+}
+
+#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
+//
+// static
+FORCEINLINE void ProfilingAPIUtility::IncEvacuationCounter(Thread * pThread)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ MODE_ANY;
+ CANNOT_TAKE_LOCK;
+ SO_NOT_MAINLINE;
+ }
+ CONTRACTL_END;
+
+ 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
+//
+// static
+FORCEINLINE void ProfilingAPIUtility::DecEvacuationCounter(Thread * pThread)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ MODE_ANY;
+ CANNOT_TAKE_LOCK;
+ SO_NOT_MAINLINE;
+ }
+ CONTRACTL_END;
+
+ if (pThread)
+ pThread->DecProfilerEvacuationCounter();
+}
+
+#endif // FEATURE_PROFAPI_ATTACH_DETACH
+
+#endif //__PROFILING_HELPER_INL__