diff options
Diffstat (limited to 'src/vm/profilinghelper.inl')
-rw-r--r-- | src/vm/profilinghelper.inl | 276 |
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__ |