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 | // |
32 | template< typename EnumInterface, typename Element > |
33 | class ProfilerEnum : public EnumInterface |
34 | { |
35 | public: |
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 | |
60 | protected: |
61 | ULONG m_currentElement; |
62 | |
63 | CDynArray< Element > m_elements; |
64 | |
65 | LONG m_refCount; |
66 | |
67 | private: |
68 | static const IID& m_pEnumInterfaceIID; |
69 | }; |
70 | |
71 | template< typename EnumInterface, typename Element > |
72 | const 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 | // |
103 | template< typename EnumInterface, typename Element > |
104 | ProfilerEnum< 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 | |
125 | template< typename EnumInterface, typename Element > |
126 | ProfilerEnum< 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 | // |
145 | template< typename EnumInterface, typename Element > |
146 | ProfilerEnum< 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 | |
165 | template< typename EnumInterface, typename Element > |
166 | HRESULT |
167 | ProfilerEnum< 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 | |
187 | template< typename EnumInterface, typename Element > |
188 | ULONG |
189 | ProfilerEnum< EnumInterface, Element >::AddRef() |
190 | { |
191 | return InterlockedIncrement(&m_refCount); |
192 | } |
193 | |
194 | template< typename EnumInterface, typename Element > |
195 | ULONG |
196 | ProfilerEnum< 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 | |
230 | template< typename EnumInterface, typename Element > |
231 | HRESULT |
232 | ProfilerEnum< 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 | |
312 | template< typename EnumInterface, typename Element > |
313 | HRESULT |
314 | ProfilerEnum< 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 | // |
357 | template< typename EnumInterface, typename Element > |
358 | HRESULT |
359 | ProfilerEnum< 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 | |
397 | template< typename EnumInterface, typename Element > |
398 | HRESULT |
399 | ProfilerEnum< 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 | |
429 | template< typename EnumInterface, typename Element > |
430 | HRESULT |
431 | ProfilerEnum< 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 | |
467 | typedef ProfilerEnum< ICorProfilerObjectEnum, ObjectID > ProfilerObjectEnum; |
468 | typedef ProfilerEnum< ICorProfilerFunctionEnum, COR_PRF_FUNCTION > ProfilerFunctionEnumBase; |
469 | typedef ProfilerEnum< ICorProfilerModuleEnum, ModuleID > ProfilerModuleEnumBase; |
470 | typedef ProfilerEnum< ICorProfilerThreadEnum, ThreadID > ProfilerThreadEnumBase; |
471 | typedef 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 | |
477 | class ProfilerFunctionEnum : public ProfilerFunctionEnumBase |
478 | { |
479 | public: |
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 | |
488 | class ProfilerModuleEnum : public ProfilerModuleEnumBase |
489 | { |
490 | public: |
491 | HRESULT Init(); |
492 | HRESULT AddUnsharedModulesFromAppDomain(AppDomain * pAppDomain); |
493 | HRESULT AddUnsharedModule(Module * pModule); |
494 | }; |
495 | |
496 | |
497 | class IterateAppDomainContainingModule |
498 | { |
499 | public: |
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 | |
514 | private: |
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 |
526 | class ProfilerThreadEnum : public ProfilerThreadEnumBase |
527 | { |
528 | |
529 | public : |
530 | HRESULT Init(); |
531 | }; |
532 | |
533 | #endif //__PROFILINGENUMERATORS_H__ |
534 | |