diff options
Diffstat (limited to 'src/vm/profilingenumerators.h')
-rw-r--r-- | src/vm/profilingenumerators.h | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/src/vm/profilingenumerators.h b/src/vm/profilingenumerators.h new file mode 100644 index 0000000000..7162ba0552 --- /dev/null +++ b/src/vm/profilingenumerators.h @@ -0,0 +1,533 @@ +// 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. +// +// FILE: ProfilingEnumerators.h +// +// All enumerators returned by the profiling API to enumerate objects or to catch up on +// the current CLR state (usually for attaching profilers) are defined in +// ProfilingEnumerators.h,cpp. +// +// This header file contains the base enumerator template implementation, plus the +// definitions of the derived enumerators. +// + + +#ifndef __PROFILINGENUMERATORS_H__ +#define __PROFILINGENUMERATORS_H__ + + +//--------------------------------------------------------------------------------------- +// +// ProfilerEnum +// +// This class is a one-size-fits-all implementation for COM style enumerators +// +// Template parameters: +// EnumInterface -- the parent interface for this enumerator +// (e.g., ICorProfilerObjectEnum) +// Element -- the type of the objects this enumerator returns. +// +// +template< typename EnumInterface, typename Element > +class ProfilerEnum : public EnumInterface +{ +public: + ProfilerEnum(CDynArray< Element >* elements); + ProfilerEnum(); + virtual ~ProfilerEnum(); + + // IUnknown functions + + virtual HRESULT __stdcall QueryInterface(REFIID id, void** pInterface); + virtual ULONG __stdcall AddRef(); + virtual ULONG __stdcall Release(); + + + // This template assumes that the enumerator confors to the interface + // + // (this matches the IEnumXXX interface documented in MSDN) + + virtual HRESULT __stdcall Skip(ULONG count); + virtual HRESULT __stdcall Reset(); + virtual HRESULT __stdcall Clone(EnumInterface** ppEnum); + virtual HRESULT __stdcall GetCount(ULONG *count); + virtual HRESULT __stdcall Next(ULONG count, + Element elements[], + ULONG* elementsFetched); + + +protected: + ULONG m_currentElement; + + CDynArray< Element > m_elements; + + LONG m_refCount; + +private: + static const IID& m_pEnumInterfaceIID; +}; + +template< typename EnumInterface, typename Element > +const IID& ProfilerEnum< EnumInterface, Element >::m_pEnumInterfaceIID = __uuidof(EnumInterface); + +// +// +// ProfilerEnum implementation +// +// + + +// +// ProfilerEnum::ProfilerEnum +// +// Description +// The enumerator constructor +// +// Parameters +// elements -- the array of elements in the enumeration. +// +// Notes +// The enumerator does NOT take ownership of data in the array of elements; +// it maintains its own private copy. +// +// <TODO> +// nickbe 12/12/2003 11:31:34 +// +// If someone comes back and complains that the enumerators are too slow or use +// too much memory, I can reference count or otherwise garbage collect the data +// used by the enumerators +// </TODO> +// +// +template< typename EnumInterface, typename Element > +ProfilerEnum< EnumInterface, Element >::ProfilerEnum(CDynArray< Element >* elements) : + m_currentElement(0), + m_refCount(1) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + const ULONG count = elements->Count(); + m_elements.AllocateBlockThrowing(count); + + for (ULONG i = 0; i < count; ++i) + { + m_elements[i] = (*elements)[i]; + } +} + +template< typename EnumInterface, typename Element > +ProfilerEnum< EnumInterface, Element >::ProfilerEnum() : + m_currentElement(0), + m_refCount(1) +{ +} + + +// +// ProfilerEnum::ProfileEnum +// +// Description +// Destructor for enumerators +// +// Parameters +// None +// +// Returns +// None +// +template< typename EnumInterface, typename Element > +ProfilerEnum< EnumInterface, Element >::~ProfilerEnum() +{ +} + +// +// ProfilerEnum::QueryInterface +// +// Description +// dynamically cast this object to a specific interface. +// +// Parameters +// id -- the interface ID requested +// ppInterface -- [out] pointer to the appropriate interface +// +// Returns +// S_OK -- if the QueryInterface succeeded +// E_NOINTERFACE -- if the enumerator does not implement the requested interface +// + +template< typename EnumInterface, typename Element > +HRESULT +ProfilerEnum< EnumInterface, Element >::QueryInterface(REFIID id, void** pInterface) +{ + if (m_pEnumInterfaceIID == id) + { + *pInterface = static_cast< EnumInterface* >(this); + } + else if (IID_IUnknown == id) + { + *pInterface = static_cast< IUnknown* >(this); + } + else + { + *pInterface = NULL; + return E_NOINTERFACE; + } + + this->AddRef(); + return S_OK; +} + +template< typename EnumInterface, typename Element > +ULONG +ProfilerEnum< EnumInterface, Element >::AddRef() +{ + return InterlockedIncrement(&m_refCount); +} + +template< typename EnumInterface, typename Element > +ULONG +ProfilerEnum< EnumInterface, Element >::Release() +{ + ULONG refCount = InterlockedDecrement(&m_refCount); + + if (0 == refCount) + { + delete this; + } + + return refCount; +} + +// +// ProfilerEnum::Next +// +// Description +// Retrieves elements from the enumeration and advances the enumerator +// +// Parameters +// elementsRequested -- the number of elements to read +// elements -- [out] an array to store the retrieved elements +// elementsFetched -- [out] the number of elements actually retrieved +// +// +// Returns +// S_OK -- elementedRequested was fully satisfied +// S_FALSE -- less than elementsRequested were returned +// E_INVALIDARG +// +// Notes +// if elementsRequested is 1 and elementsFetched is NULL, the enumerator will +// try to advance 1 item and return S_OK if it is successful +// + +template< typename EnumInterface, typename Element > +HRESULT +ProfilerEnum< EnumInterface, Element >::Next(ULONG elementsRequested, + Element elements[], + ULONG* elementsFetched) +{ + // sanity check the location of the iterator + _ASSERTE(0 <= m_currentElement); + _ASSERTE(m_currentElement <= static_cast< ULONG >(m_elements.Count())); + + // It's illegal to try and advance more than one element without giving a + // legitimate pointer for elementsRequested + if ((NULL == elementsFetched) && (1 < elementsRequested)) + { + return E_INVALIDARG; + } + + // If, for some reason, you ask for zero elements, well, we'll just tell + // you that's fine. + if (0 == elementsRequested) + { + if (NULL != elementsFetched) + { + *elementsFetched = 0; + } + + return S_OK; + } + + if (elements == NULL) + { + return E_INVALIDARG; + } + + // okay, enough with the corner cases. + + // We don't want to walk past the end of our array, so figure out how far we + // need to walk. + const ULONG elementsToCopy = min(elementsRequested, m_elements.Count() - m_currentElement); + + for (ULONG i = 0; i < elementsToCopy; ++i) + { + elements[i] = m_elements[m_currentElement + i]; + } + + // advance the enumerator + m_currentElement += elementsToCopy; + + // sanity check that we haven't gone any further than we were supposed to + _ASSERTE(0 <= m_currentElement); + _ASSERTE(m_currentElement <= static_cast< ULONG >(m_elements.Count())); + + + if (NULL != elementsFetched) + { + *elementsFetched = elementsToCopy; + } + + if (elementsToCopy < elementsRequested) + { + return S_FALSE; + } + + return S_OK; +} + + +// +// ProfilerEnum:GetCount +// +// Description +// Computes the number of elements remaining in the enumeration +// +// Parameters +// count -- [out] the number of element remaining in the enumeration +// +// Returns +// S_OK +// E_INVALIDARG -- if count is an invalid pointer +// +// + +template< typename EnumInterface, typename Element > +HRESULT +ProfilerEnum< EnumInterface, Element >::GetCount(ULONG* count) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_NOT_MAINLINE; + } + CONTRACTL_END; + + if (NULL == count) + { + return E_INVALIDARG; + } + + *count = m_elements.Count() - m_currentElement; + + return S_OK; +} + +// +// ProfilerEnum::Skip +// +// Description +// Advances the enumerator without retrieving any elements. +// +// Parameters +// count -- number of elements to skip +// +// Returns +// S_OK -- if the number of elements skipped was equal to count +// S_FALSE -- if the number of elements skipped was less than count +// +// +// TODO +// +// The API for IEnumXXX listed in MSDN here is broken. We should really have an +// out parameter that represents the number of elements actually skipped ... all +// though you could theoretically work that number out by calling GetCount() +// before and after calling Skip() +// +// +template< typename EnumInterface, typename Element > +HRESULT +ProfilerEnum< EnumInterface, Element >::Skip(ULONG count) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_NOT_MAINLINE; + } + CONTRACTL_END; + + const ULONG elementsToSkip = min(count, m_elements.Count() - m_currentElement); + m_currentElement += elementsToSkip; + + if (elementsToSkip < count) + { + return S_FALSE; + } + + return S_OK; +} + + + +// +// ProfilerEnum::Reset +// +// Description +// Returns the enumerator to the beginning of the enumeration +// +// Parameters +// None +// +// Returns +// S_OK -- always (function never fails) +// +// + +template< typename EnumInterface, typename Element > +HRESULT +ProfilerEnum< EnumInterface, Element >::Reset() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_NOT_MAINLINE; + } + CONTRACTL_END; + + m_currentElement = 0; + return S_OK; +} + +// +// ProfilerEnum::Clone +// +// Description +// Creates a copy of this enumerator. +// +// Parameters +// None +// +// Returns +// S_OK -- if copying is successful +// E_OUTOFMEMORY -- if OOM occurs +// E_INVALIDARG -- if pInterface is an invalid pointer +// + +template< typename EnumInterface, typename Element > +HRESULT +ProfilerEnum< EnumInterface, Element >::Clone(EnumInterface** pInterface) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + + SO_NOT_MAINLINE; + } + CONTRACTL_END; + + if (pInterface == NULL) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + EX_TRY + { + *pInterface = new ProfilerEnum< EnumInterface, Element >(&m_elements); + } + EX_CATCH + { + *pInterface = NULL; + hr = E_OUTOFMEMORY; + } + EX_END_CATCH(RethrowTerminalExceptions) + + return hr; +} + +// --------------------------------------------------------------------------------------- +// Enumerators have their base class defined here, as an instantiation of ProfilerEnum +// --------------------------------------------------------------------------------------- + +typedef ProfilerEnum< ICorProfilerObjectEnum, ObjectID > ProfilerObjectEnum; +typedef ProfilerEnum< ICorProfilerFunctionEnum, COR_PRF_FUNCTION > ProfilerFunctionEnumBase; +typedef ProfilerEnum< ICorProfilerModuleEnum, ModuleID > ProfilerModuleEnumBase; +typedef ProfilerEnum< ICorProfilerThreadEnum, ThreadID > ProfilerThreadEnumBase; +typedef ProfilerEnum< ICorProfilerMethodEnum, COR_PRF_METHOD > ProfilerMethodEnum; + +// --------------------------------------------------------------------------------------- +// This class derives from the template enumerator instantiation, and provides specific +// code to populate the enumerator with the function list + +class ProfilerFunctionEnum : public ProfilerFunctionEnumBase +{ +public: + BOOL Init(BOOL fWithReJITIDs = FALSE); +}; + + +// --------------------------------------------------------------------------------------- +// This class derives from the template enumerator instantiation, and provides specific +// code to populate the enumerator with the module list + +class ProfilerModuleEnum : public ProfilerModuleEnumBase +{ +public: + HRESULT Init(); + HRESULT AddUnsharedModulesFromAppDomain(AppDomain * pAppDomain); + HRESULT AddUnsharedModule(Module * pModule); +}; + + +class IterateAppDomainContainingModule +{ +public: + IterateAppDomainContainingModule(Module * pModule, ULONG32 cAppDomainIds, ULONG32 * pcAppDomainIds, AppDomainID * pAppDomainIds) + : m_pModule(pModule), m_cAppDomainIds(cAppDomainIds), m_pcAppDomainIds(pcAppDomainIds), m_rgAppDomainIds(pAppDomainIds), m_index(0) + { + LIMITED_METHOD_CONTRACT; + + _ASSERTE((pModule != NULL) && + ((m_rgAppDomainIds != NULL) || (m_cAppDomainIds == 0)) && + (m_pcAppDomainIds != NULL)); + } + + HRESULT PopulateArray(); + + HRESULT AddAppDomainContainingModule(AppDomain * pAppDomain); + +private: + Module * m_pModule; + ULONG32 m_cAppDomainIds; + ULONG32 * m_pcAppDomainIds; + AppDomainID * m_rgAppDomainIds; + ULONG32 m_index; +}; + + +// --------------------------------------------------------------------------------------- +// This class derives from the template enumerator instantiation, and provides specific +// code to populate the enumerator with the thread store +class ProfilerThreadEnum : public ProfilerThreadEnumBase +{ + +public : + HRESULT Init(); +}; + +#endif //__PROFILINGENUMERATORS_H__ |