1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// FILE: ProfilingEnumerators.h
6//
7// All enumerators returned by the profiling API to enumerate objects or to catch up on
8// the current CLR state (usually for attaching profilers) are defined in
9// ProfilingEnumerators.h,cpp.
10//
11// This header file contains the base enumerator template implementation, plus the
12// definitions of the derived enumerators.
13//
14
15
16#ifndef __PROFILINGENUMERATORS_H__
17#define __PROFILINGENUMERATORS_H__
18
19
20//---------------------------------------------------------------------------------------
21//
22// ProfilerEnum
23//
24// This class is a one-size-fits-all implementation for COM style enumerators
25//
26// Template parameters:
27// EnumInterface -- the parent interface for this enumerator
28// (e.g., ICorProfilerObjectEnum)
29// Element -- the type of the objects this enumerator returns.
30//
31//
32template< typename EnumInterface, typename Element >
33class ProfilerEnum : public EnumInterface
34{
35public:
36 ProfilerEnum(CDynArray< Element >* elements);
37 ProfilerEnum();
38 virtual ~ProfilerEnum();
39
40 // IUnknown functions
41
42 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, void** pInterface);
43 virtual ULONG STDMETHODCALLTYPE AddRef();
44 virtual ULONG STDMETHODCALLTYPE Release();
45
46
47 // This template assumes that the enumerator confors to the interface
48 //
49 // (this matches the IEnumXXX interface documented in MSDN)
50
51 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG count);
52 virtual HRESULT STDMETHODCALLTYPE Reset();
53 virtual HRESULT STDMETHODCALLTYPE Clone(EnumInterface** ppEnum);
54 virtual HRESULT STDMETHODCALLTYPE GetCount(ULONG *count);
55 virtual HRESULT STDMETHODCALLTYPE Next(ULONG count,
56 Element elements[],
57 ULONG* elementsFetched);
58
59
60protected:
61 ULONG m_currentElement;
62
63 CDynArray< Element > m_elements;
64
65 LONG m_refCount;
66
67private:
68 static const IID& m_pEnumInterfaceIID;
69};
70
71template< typename EnumInterface, typename Element >
72const IID& ProfilerEnum< EnumInterface, Element >::m_pEnumInterfaceIID = __uuidof(EnumInterface);
73
74//
75//
76// ProfilerEnum implementation
77//
78//
79
80
81//
82// ProfilerEnum::ProfilerEnum
83//
84// Description
85// The enumerator constructor
86//
87// Parameters
88// elements -- the array of elements in the enumeration.
89//
90// Notes
91// The enumerator does NOT take ownership of data in the array of elements;
92// it maintains its own private copy.
93//
94// <TODO>
95// nickbe 12/12/2003 11:31:34
96//
97// If someone comes back and complains that the enumerators are too slow or use
98// too much memory, I can reference count or otherwise garbage collect the data
99// used by the enumerators
100// </TODO>
101//
102//
103template< typename EnumInterface, typename Element >
104ProfilerEnum< EnumInterface, Element >::ProfilerEnum(CDynArray< Element >* elements) :
105 m_currentElement(0),
106 m_refCount(1)
107{
108 CONTRACTL
109 {
110 THROWS;
111 GC_NOTRIGGER;
112 MODE_ANY;
113 }
114 CONTRACTL_END;
115
116 const ULONG count = elements->Count();
117 m_elements.AllocateBlockThrowing(count);
118
119 for (ULONG i = 0; i < count; ++i)
120 {
121 m_elements[i] = (*elements)[i];
122 }
123}
124
125template< typename EnumInterface, typename Element >
126ProfilerEnum< EnumInterface, Element >::ProfilerEnum() :
127 m_currentElement(0),
128 m_refCount(1)
129{
130}
131
132
133//
134// ProfilerEnum::ProfileEnum
135//
136// Description
137// Destructor for enumerators
138//
139// Parameters
140// None
141//
142// Returns
143// None
144//
145template< typename EnumInterface, typename Element >
146ProfilerEnum< EnumInterface, Element >::~ProfilerEnum()
147{
148}
149
150//
151// ProfilerEnum::QueryInterface
152//
153// Description
154// dynamically cast this object to a specific interface.
155//
156// Parameters
157// id -- the interface ID requested
158// ppInterface -- [out] pointer to the appropriate interface
159//
160// Returns
161// S_OK -- if the QueryInterface succeeded
162// E_NOINTERFACE -- if the enumerator does not implement the requested interface
163//
164
165template< typename EnumInterface, typename Element >
166HRESULT
167ProfilerEnum< EnumInterface, Element >::QueryInterface(REFIID id, void** pInterface)
168{
169 if (m_pEnumInterfaceIID == id)
170 {
171 *pInterface = static_cast< EnumInterface* >(this);
172 }
173 else if (IID_IUnknown == id)
174 {
175 *pInterface = static_cast< IUnknown* >(this);
176 }
177 else
178 {
179 *pInterface = NULL;
180 return E_NOINTERFACE;
181 }
182
183 this->AddRef();
184 return S_OK;
185}
186
187template< typename EnumInterface, typename Element >
188ULONG
189ProfilerEnum< EnumInterface, Element >::AddRef()
190{
191 return InterlockedIncrement(&m_refCount);
192}
193
194template< typename EnumInterface, typename Element >
195ULONG
196ProfilerEnum< EnumInterface, Element >::Release()
197{
198 ULONG refCount = InterlockedDecrement(&m_refCount);
199
200 if (0 == refCount)
201 {
202 delete this;
203 }
204
205 return refCount;
206}
207
208//
209// ProfilerEnum::Next
210//
211// Description
212// Retrieves elements from the enumeration and advances the enumerator
213//
214// Parameters
215// elementsRequested -- the number of elements to read
216// elements -- [out] an array to store the retrieved elements
217// elementsFetched -- [out] the number of elements actually retrieved
218//
219//
220// Returns
221// S_OK -- elementedRequested was fully satisfied
222// S_FALSE -- less than elementsRequested were returned
223// E_INVALIDARG
224//
225// Notes
226// if elementsRequested is 1 and elementsFetched is NULL, the enumerator will
227// try to advance 1 item and return S_OK if it is successful
228//
229
230template< typename EnumInterface, typename Element >
231HRESULT
232ProfilerEnum< EnumInterface, Element >::Next(ULONG elementsRequested,
233 Element elements[],
234 ULONG* elementsFetched)
235{
236 // sanity check the location of the iterator
237 _ASSERTE(0 <= m_currentElement);
238 _ASSERTE(m_currentElement <= static_cast< ULONG >(m_elements.Count()));
239
240 // It's illegal to try and advance more than one element without giving a
241 // legitimate pointer for elementsRequested
242 if ((NULL == elementsFetched) && (1 < elementsRequested))
243 {
244 return E_INVALIDARG;
245 }
246
247 // If, for some reason, you ask for zero elements, well, we'll just tell
248 // you that's fine.
249 if (0 == elementsRequested)
250 {
251 if (NULL != elementsFetched)
252 {
253 *elementsFetched = 0;
254 }
255
256 return S_OK;
257 }
258
259 if (elements == NULL)
260 {
261 return E_INVALIDARG;
262 }
263
264 // okay, enough with the corner cases.
265
266 // We don't want to walk past the end of our array, so figure out how far we
267 // need to walk.
268 const ULONG elementsToCopy = min(elementsRequested, m_elements.Count() - m_currentElement);
269
270 for (ULONG i = 0; i < elementsToCopy; ++i)
271 {
272 elements[i] = m_elements[m_currentElement + i];
273 }
274
275 // advance the enumerator
276 m_currentElement += elementsToCopy;
277
278 // sanity check that we haven't gone any further than we were supposed to
279 _ASSERTE(0 <= m_currentElement);
280 _ASSERTE(m_currentElement <= static_cast< ULONG >(m_elements.Count()));
281
282
283 if (NULL != elementsFetched)
284 {
285 *elementsFetched = elementsToCopy;
286 }
287
288 if (elementsToCopy < elementsRequested)
289 {
290 return S_FALSE;
291 }
292
293 return S_OK;
294}
295
296
297//
298// ProfilerEnum:GetCount
299//
300// Description
301// Computes the number of elements remaining in the enumeration
302//
303// Parameters
304// count -- [out] the number of element remaining in the enumeration
305//
306// Returns
307// S_OK
308// E_INVALIDARG -- if count is an invalid pointer
309//
310//
311
312template< typename EnumInterface, typename Element >
313HRESULT
314ProfilerEnum< EnumInterface, Element >::GetCount(ULONG* count)
315{
316 CONTRACTL
317 {
318 NOTHROW;
319 GC_NOTRIGGER;
320 MODE_ANY;
321 SO_NOT_MAINLINE;
322 }
323 CONTRACTL_END;
324
325 if (NULL == count)
326 {
327 return E_INVALIDARG;
328 }
329
330 *count = m_elements.Count() - m_currentElement;
331
332 return S_OK;
333}
334
335//
336// ProfilerEnum::Skip
337//
338// Description
339// Advances the enumerator without retrieving any elements.
340//
341// Parameters
342// count -- number of elements to skip
343//
344// Returns
345// S_OK -- if the number of elements skipped was equal to count
346// S_FALSE -- if the number of elements skipped was less than count
347//
348//
349// TODO
350//
351// The API for IEnumXXX listed in MSDN here is broken. We should really have an
352// out parameter that represents the number of elements actually skipped ... all
353// though you could theoretically work that number out by calling GetCount()
354// before and after calling Skip()
355//
356//
357template< typename EnumInterface, typename Element >
358HRESULT
359ProfilerEnum< EnumInterface, Element >::Skip(ULONG count)
360{
361 CONTRACTL
362 {
363 NOTHROW;
364 GC_NOTRIGGER;
365 MODE_ANY;
366 SO_NOT_MAINLINE;
367 }
368 CONTRACTL_END;
369
370 const ULONG elementsToSkip = min(count, m_elements.Count() - m_currentElement);
371 m_currentElement += elementsToSkip;
372
373 if (elementsToSkip < count)
374 {
375 return S_FALSE;
376 }
377
378 return S_OK;
379}
380
381
382
383//
384// ProfilerEnum::Reset
385//
386// Description
387// Returns the enumerator to the beginning of the enumeration
388//
389// Parameters
390// None
391//
392// Returns
393// S_OK -- always (function never fails)
394//
395//
396
397template< typename EnumInterface, typename Element >
398HRESULT
399ProfilerEnum< EnumInterface, Element >::Reset()
400{
401 CONTRACTL
402 {
403 NOTHROW;
404 GC_NOTRIGGER;
405 MODE_ANY;
406 SO_NOT_MAINLINE;
407 }
408 CONTRACTL_END;
409
410 m_currentElement = 0;
411 return S_OK;
412}
413
414//
415// ProfilerEnum::Clone
416//
417// Description
418// Creates a copy of this enumerator.
419//
420// Parameters
421// None
422//
423// Returns
424// S_OK -- if copying is successful
425// E_OUTOFMEMORY -- if OOM occurs
426// E_INVALIDARG -- if pInterface is an invalid pointer
427//
428
429template< typename EnumInterface, typename Element >
430HRESULT
431ProfilerEnum< EnumInterface, Element >::Clone(EnumInterface** pInterface)
432{
433 CONTRACTL
434 {
435 NOTHROW;
436 GC_NOTRIGGER;
437 MODE_ANY;
438
439 SO_NOT_MAINLINE;
440 }
441 CONTRACTL_END;
442
443 if (pInterface == NULL)
444 {
445 return E_INVALIDARG;
446 }
447
448 HRESULT hr = S_OK;
449 EX_TRY
450 {
451 *pInterface = new ProfilerEnum< EnumInterface, Element >(&m_elements);
452 }
453 EX_CATCH
454 {
455 *pInterface = NULL;
456 hr = E_OUTOFMEMORY;
457 }
458 EX_END_CATCH(RethrowTerminalExceptions)
459
460 return hr;
461}
462
463// ---------------------------------------------------------------------------------------
464// Enumerators have their base class defined here, as an instantiation of ProfilerEnum
465// ---------------------------------------------------------------------------------------
466
467typedef ProfilerEnum< ICorProfilerObjectEnum, ObjectID > ProfilerObjectEnum;
468typedef ProfilerEnum< ICorProfilerFunctionEnum, COR_PRF_FUNCTION > ProfilerFunctionEnumBase;
469typedef ProfilerEnum< ICorProfilerModuleEnum, ModuleID > ProfilerModuleEnumBase;
470typedef ProfilerEnum< ICorProfilerThreadEnum, ThreadID > ProfilerThreadEnumBase;
471typedef ProfilerEnum< ICorProfilerMethodEnum, COR_PRF_METHOD > ProfilerMethodEnum;
472
473// ---------------------------------------------------------------------------------------
474// This class derives from the template enumerator instantiation, and provides specific
475// code to populate the enumerator with the function list
476
477class ProfilerFunctionEnum : public ProfilerFunctionEnumBase
478{
479public:
480 BOOL Init(BOOL fWithReJITIDs = FALSE);
481};
482
483
484// ---------------------------------------------------------------------------------------
485// This class derives from the template enumerator instantiation, and provides specific
486// code to populate the enumerator with the module list
487
488class ProfilerModuleEnum : public ProfilerModuleEnumBase
489{
490public:
491 HRESULT Init();
492 HRESULT AddUnsharedModulesFromAppDomain(AppDomain * pAppDomain);
493 HRESULT AddUnsharedModule(Module * pModule);
494};
495
496
497class IterateAppDomainContainingModule
498{
499public:
500 IterateAppDomainContainingModule(Module * pModule, ULONG32 cAppDomainIds, ULONG32 * pcAppDomainIds, AppDomainID * pAppDomainIds)
501 : m_pModule(pModule), m_cAppDomainIds(cAppDomainIds), m_pcAppDomainIds(pcAppDomainIds), m_rgAppDomainIds(pAppDomainIds), m_index(0)
502 {
503 LIMITED_METHOD_CONTRACT;
504
505 _ASSERTE((pModule != NULL) &&
506 ((m_rgAppDomainIds != NULL) || (m_cAppDomainIds == 0)) &&
507 (m_pcAppDomainIds != NULL));
508 }
509
510 HRESULT PopulateArray();
511
512 HRESULT AddAppDomainContainingModule(AppDomain * pAppDomain);
513
514private:
515 Module * m_pModule;
516 ULONG32 m_cAppDomainIds;
517 ULONG32 * m_pcAppDomainIds;
518 AppDomainID * m_rgAppDomainIds;
519 ULONG32 m_index;
520};
521
522
523// ---------------------------------------------------------------------------------------
524// This class derives from the template enumerator instantiation, and provides specific
525// code to populate the enumerator with the thread store
526class ProfilerThreadEnum : public ProfilerThreadEnumBase
527{
528
529public :
530 HRESULT Init();
531};
532
533#endif //__PROFILINGENUMERATORS_H__
534