e6d5fb4909f8e1b810fe60ef99a3418760877c1a
[platform/upstream/coreclr.git] / src / vm / profilinghelper.cpp
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 // ProfilingHelper.cpp
6 // 
7
8 //
9 // Implementation of helper classes used for miscellaneous purposes within the profiling
10 // API
11 // 
12 // ======================================================================================
13
14 // 
15 // #LoadUnloadCallbackSynchronization
16 // 
17 // There is synchronization around loading profilers, unloading profilers, and issuing
18 // callbacks to profilers, to ensure that we know when it's safe to detach profilers or
19 // to call into profilers. The synchronization scheme is intentionally lockless on the
20 // mainline path (issuing callbacks into the profiler), with heavy locking on the
21 // non-mainline path (loading / unloading profilers).
22 // 
23 // PROTECTED DATA
24 // 
25 // The synchronization protects the following data:
26 // 
27 //     * ProfilingAPIDetach::s_profilerDetachInfo
28 //     * (volatile) g_profControlBlock.curProfStatus.m_profStatus
29 //     * (volatile) g_profControlBlock.pProfInterface
30 //         * latter implies the profiler DLL's load status is protected as well, as
31 //             pProfInterface changes between non-NULL and NULL as a profiler DLL is
32 //             loaded and unloaded, respectively.
33 //         
34 // SYNCHRONIZATION COMPONENTS
35 // 
36 // * Simple Crst: code:ProfilingAPIUtility::s_csStatus
37 // * Lockless, volatile per-thread counters: code:EvacuationCounterHolder
38 // * Profiler status transition invariants and CPU buffer flushing:
39 //     code:CurrentProfilerStatus::Set
40 //         
41 // WRITERS
42 // 
43 // The above data is considered to be "written to" when a profiler is loaded or unloaded,
44 // or the status changes (see code:ProfilerStatus), or a request to detach the profiler
45 // is received (see code:ProfilingAPIDetach::RequestProfilerDetach), or the DetachThread
46 // consumes or modifies the contents of code:ProfilingAPIDetach::s_profilerDetachInfo.
47 // All these cases are serialized with each other by the simple Crst:
48 // code:ProfilingAPIUtility::s_csStatus
49 // 
50 // READERS
51 // 
52 // Readers are the mainline case and are lockless. A "reader" is anyone who wants to
53 // issue a profiler callback. Readers are scattered throughout the runtime, and have the
54 // following format:
55 //    {
56 //        BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
57 //        g_profControlBlock.pProfInterface->AppDomainCreationStarted(MyAppDomainID);
58 //        END_PIN_PROFILER();
59 //    }
60 // The BEGIN / END macros do the following:
61 // * Evaluate the expression argument (e.g., CORProfilerTrackAppDomainLoads()). This is a
62 //     "dirty read" as the profiler could be detached at any moment during or after that
63 //     evaluation.
64 // * If true, push a code:EvacuationCounterHolder on the stack, which increments the
65 //     per-thread evacuation counter (not interlocked).
66 // * Re-evaluate the expression argument. This time, it's a "clean read" (see below for
67 //     why).
68 // * If still true, execute the statements inside the BEGIN/END block. Inside that block,
69 //     the profiler is guaranteed to remain loaded, because the evacuation counter
70 //     remains nonzero (again, see below).
71 // * Once the BEGIN/END block is exited, the evacuation counter is decremented, and the
72 //     profiler is unpinned and allowed to detach.
73 //     
74 // READER / WRITER COORDINATION
75 // 
76 // The above ensures that a reader never touches g_profControlBlock.pProfInterface and
77 // all it embodies (including the profiler DLL code and callback implementations) unless
78 // the reader was able to increment its thread's evacuation counter AND re-verify that
79 // the profiler's status is still active (the status check is included in the macro's
80 // expression argument, such as CORProfilerTrackAppDomainLoads()).
81 // 
82 // At the same time, a profiler DLL is never unloaded (nor
83 // g_profControlBlock.pProfInterface deleted and NULLed out) UNLESS the writer performs
84 // these actions:
85 // * (a) Set the profiler's status to a non-active state like kProfStatusDetaching or
86 //     kProfStatusNone
87 // * (b) Call FlushProcessWriteBuffers()
88 // * (c) Grab thread store lock, iterate through all threads, and verify each per-thread
89 //     evacuation counter is zero.
90 //     
91 // The above steps are why it's considered a "clean read" if a reader first increments
92 // its evacuation counter and then checks the profiler status. Once the writer flushes
93 // the CPU buffers (b), the reader will see the updated status (from a) and know not to
94 // use g_profControlBlock.pProfInterface. And if the reader clean-reads the status before
95 // the buffers were flushed, then the reader will have incremented its evacuation counter
96 // first, which the writer will be sure to see in (c).  For more details about how the
97 // evacuation counters work, see code:ProfilingAPIUtility::IsProfilerEvacuated.
98 // 
99 // WHEN ARE BEGIN/END_PIN_PROFILER REQUIRED?
100 // 
101 // In general, any time you access g_profControlBlock.pProfInterface, you must be inside
102 // a BEGIN/END_PIN_PROFILER block. This is pretty much always true throughout the EE, but
103 // there are some exceptions inside the profiling API code itself, where the BEGIN / END
104 // macros are unnecessary:
105 //     * If you are inside a public ICorProfilerInfo function's implementation, the
106 //         profiler is already pinned. This is because the profiler called the Info
107 //         function from either:
108 //         * a callback implemented inside of g_profControlBlock.pProfInterface, in which
109 //             case the BEGIN/END macros are already in place around the call to that
110 //             callback, OR
111 //         * a hijacked thread or a thread of the profiler's own creation. In either
112 //             case, it's the profiler's responsibility to end hijacking and end its own
113 //             threads before requesting a detach. So the profiler DLL is guaranteed not
114 //             to disappear while hijacking or profiler-created threads are in action.
115 //    * If you're executing while code:ProfilingAPIUtility::s_csStatus is held, then
116 //        you're explicitly serialized against all code that might unload the profiler's
117 //        DLL and delete g_profControlBlock.pProfInterface. So the profiler is therefore
118 //        still guaranteed not to disappear.
119 //    * If slow ELT helpers, fast ELT hooks, or profiler-instrumented code is on the
120 //        stack, then the profiler cannot be detached yet anyway. Today, we outright
121 //        refuse a detach request from a profiler that instrumented code or enabled ELT.
122 //        Once rejit / revert is implemented, the evacuation checks will ensure all
123 //        instrumented code (including ELT) are reverted and off all stacks before
124 //        attempting to unload the profielr.
125
126
127 #include "common.h"
128
129 #ifdef PROFILING_SUPPORTED
130
131 #include "eeprofinterfaces.h"
132 #include "eetoprofinterfaceimpl.h"
133 #include "eetoprofinterfaceimpl.inl"
134 #include "corprof.h"
135 #include "proftoeeinterfaceimpl.h"
136 #include "proftoeeinterfaceimpl.inl"
137 #include "profilinghelper.h"
138 #include "profilinghelper.inl"
139 #include "eemessagebox.h"
140
141
142 #ifdef FEATURE_PROFAPI_ATTACH_DETACH 
143 #include "profdetach.h"
144 #endif // FEATURE_PROFAPI_ATTACH_DETACH 
145
146 #include "utilcode.h"
147
148 #ifndef FEATURE_PAL
149 #include "securitywrapper.h"
150 #endif // !FEATURE_PAL
151
152 //---------------------------------------------------------------------------------------
153 // Normally, this would go in profilepriv.inl, but it's not easily inlineable because of
154 // the use of BEGIN/END_PIN_PROFILER
155 //
156 // Return Value:
157 //      TRUE iff security transparency checks in full trust assemblies should be disabled
158 //      due to the profiler.
159 //
160 BOOL CORProfilerBypassSecurityChecks()
161 {
162     CONTRACTL
163     {
164         NOTHROW;
165         GC_NOTRIGGER;
166         CANNOT_TAKE_LOCK;
167     }
168     CONTRACTL_END;
169
170     {
171         BEGIN_PIN_PROFILER(CORProfilerPresent());
172
173         // V2 profiler binaries, for compatibility purposes, should bypass transparency
174         // checks in full trust assemblies.
175         if (!(&g_profControlBlock)->pProfInterface->IsCallback3Supported())
176             return TRUE;
177         
178         // V4 profiler binaries must opt in to bypasssing transparency checks in full trust
179         // assemblies.
180         if (((&g_profControlBlock)->dwEventMask & COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST) != 0)
181             return TRUE;
182
183         END_PIN_PROFILER();
184     }
185
186     // All other cases, including no profiler loaded at all: Don't bypass
187     return FALSE;
188 }
189
190 // ----------------------------------------------------------------------------
191 // CurrentProfilerStatus methods
192
193
194 //---------------------------------------------------------------------------------------
195 //
196 // Updates the value indicating the profiler's current status
197 //
198 // Arguments:
199 //      profStatus - New value (from enum ProfilerStatus) to set.
200 //
201 // Notes:
202 //    Sets the status under a lock, and performs a debug-only check to verify that the
203 //    status transition is a legal one.  Also performs a FlushStoreBuffers() after
204 //    changing the status when necessary.
205 //
206
207 void CurrentProfilerStatus::Set(ProfilerStatus newProfStatus)
208 {
209     CONTRACTL
210     {
211         NOTHROW;
212         GC_TRIGGERS;
213         MODE_ANY;
214         CAN_TAKE_LOCK;
215     }
216     CONTRACTL_END;
217
218     _ASSERTE(ProfilingAPIUtility::GetStatusCrst() != NULL);
219
220     {
221         // Need to serialize attempts to transition the profiler status.  For example, a
222         // profiler in one thread could request a detach, while the CLR in another
223         // thread is transitioning the profiler from kProfStatusInitializing* to
224         // kProfStatusActive
225         CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst());
226
227         // Based on what the old status is, verify the new status is a legal transition.
228         switch(m_profStatus)
229         {
230         default:
231             _ASSERTE(!"Unknown ProfilerStatus");
232             break;
233
234         case kProfStatusNone:
235             _ASSERTE((newProfStatus == kProfStatusInitializingForStartupLoad) ||
236                 (newProfStatus == kProfStatusInitializingForAttachLoad));
237             break;
238
239         case kProfStatusDetaching:
240             _ASSERTE(newProfStatus == kProfStatusNone);
241             break;
242
243         case kProfStatusInitializingForStartupLoad:
244         case kProfStatusInitializingForAttachLoad:
245             _ASSERTE((newProfStatus == kProfStatusActive) ||
246                 (newProfStatus == kProfStatusNone));
247             break;
248
249         case kProfStatusActive:
250             _ASSERTE((newProfStatus == kProfStatusNone) ||
251                 (newProfStatus == kProfStatusDetaching));
252             break;
253         }
254
255         m_profStatus = newProfStatus;
256     }
257
258 #if !defined(DACCESS_COMPILE)
259     if (((newProfStatus == kProfStatusNone) ||
260          (newProfStatus == kProfStatusDetaching) ||
261          (newProfStatus == kProfStatusActive)))
262     {
263         // Flush the store buffers on all CPUs, to ensure other threads see that
264         // g_profControlBlock.curProfStatus has changed. The important status changes to
265         // flush are:
266         //     * to kProfStatusNone or kProfStatusDetaching so other threads know to stop
267         //         making calls into the profiler
268         //     * to kProfStatusActive, to ensure callbacks can be issued by the time an
269         //         attaching profiler receives ProfilerAttachComplete(), so the profiler
270         //         can safely perform catchup at that time (see
271         //         code:#ProfCatchUpSynchronization).
272         //         
273         ::FlushProcessWriteBuffers();
274     }
275 #endif // !defined(DACCESS_COMPILE)
276 }
277
278
279 //---------------------------------------------------------------------------------------
280 // ProfilingAPIUtility members
281
282
283 // See code:#LoadUnloadCallbackSynchronization.
284 CRITSEC_COOKIE ProfilingAPIUtility::s_csStatus = NULL;
285
286
287 SidBuffer * ProfilingAPIUtility::s_pSidBuffer = NULL;
288
289 // ----------------------------------------------------------------------------
290 // ProfilingAPIUtility::AppendSupplementaryInformation
291 // 
292 // Description:
293 //    Helper to the event logging functions to append the process ID and string
294 //    resource ID to the end of the message.
295 //    
296 // Arguments:
297 //    * iStringResource - [in] String resource ID to append to message.
298 //    * pString - [in/out] On input, the string to log so far. On output, the original
299 //        string with the process ID info appended.
300 //        
301
302 // static
303 void ProfilingAPIUtility::AppendSupplementaryInformation(int iStringResource, SString * pString)
304 {
305     CONTRACTL
306     {
307         THROWS;
308         GC_TRIGGERS;
309         MODE_ANY;
310
311         // This loads resource strings, which takes locks.
312         CAN_TAKE_LOCK;
313     }
314     CONTRACTL_END;
315
316     StackSString supplementaryInformation;
317
318     if (!supplementaryInformation.LoadResource(
319         CCompRC::Debugging,
320         IDS_PROF_SUPPLEMENTARY_INFO 
321         ))
322     {
323         // Resource not found; should never happen.
324         return;
325     }
326
327     pString->Append(W("  "));
328     pString->AppendPrintf(
329         supplementaryInformation, 
330         GetCurrentProcessId(),
331         iStringResource);
332 }
333
334 //---------------------------------------------------------------------------------------
335 //
336 // Helper function to log publicly-viewable errors about profiler loading and
337 // initialization.
338 // 
339 //
340 // Arguments:
341 //      * iStringResourceID - resource ID of string containing message to log
342 //      * wEventType - same constant used in win32 to specify the type of event:
343 //                   usually EVENTLOG_ERROR_TYPE, EVENTLOG_WARNING_TYPE, or
344 //                   EVENTLOG_INFORMATION_TYPE
345 //      * insertionArgs - 0 or more values to be inserted into the string to be logged
346 //          (>0 only if iStringResourceID contains format arguments (%)).
347 //
348
349 // static
350 void ProfilingAPIUtility::LogProfEventVA(
351     int iStringResourceID, 
352     WORD wEventType,
353     va_list insertionArgs)
354 {
355     CONTRACTL
356     {
357         THROWS;
358         GC_TRIGGERS;
359         MODE_ANY;
360
361         // This loads resource strings, which takes locks.
362         CAN_TAKE_LOCK;
363     }
364     CONTRACTL_END;
365
366     StackSString messageFromResource;
367     StackSString messageToLog;
368
369     if (!messageFromResource.LoadResource(
370         CCompRC::Debugging,
371         iStringResourceID 
372         ))
373     {
374         // Resource not found; should never happen.
375         return;
376     }
377
378     messageToLog.VPrintf(messageFromResource, insertionArgs);
379
380     AppendSupplementaryInformation(iStringResourceID, &messageToLog);
381
382     // Ouput debug strings for diagnostic messages.
383     WszOutputDebugString(messageToLog);
384 }
385
386 // See code:ProfilingAPIUtility.LogProfEventVA for description of arguments.
387 // static
388 void ProfilingAPIUtility::LogProfError(int iStringResourceID, ...)
389 {
390     CONTRACTL
391 {
392         THROWS;
393         GC_TRIGGERS;
394         MODE_ANY;
395
396         // This loads resource strings, which takes locks.
397         CAN_TAKE_LOCK;
398     }
399     CONTRACTL_END;
400
401     va_list insertionArgs;
402     va_start(insertionArgs, iStringResourceID);
403     LogProfEventVA(
404         iStringResourceID, 
405         EVENTLOG_ERROR_TYPE, 
406         insertionArgs);
407     va_end(insertionArgs);
408 }
409
410 // See code:ProfilingAPIUtility.LogProfEventVA for description of arguments.
411 // static
412 void ProfilingAPIUtility::LogProfInfo(int iStringResourceID, ...)
413 {
414     CONTRACTL
415     {
416         THROWS;
417         GC_TRIGGERS;
418         MODE_ANY;
419
420         // This loads resource strings, which takes locks.
421         CAN_TAKE_LOCK;
422     }
423     CONTRACTL_END;
424
425     va_list insertionArgs;
426     va_start(insertionArgs, iStringResourceID);
427     LogProfEventVA(
428         iStringResourceID, 
429         EVENTLOG_INFORMATION_TYPE, 
430         insertionArgs);
431     va_end(insertionArgs);
432 }
433
434 #ifdef PROF_TEST_ONLY_FORCE_ELT
435 // Special forward-declarations of the profiling API's slow-path enter/leave/tailcall
436 // hooks. These need to be forward-declared here so that they may be referenced in
437 // InitializeProfiling() below solely for the debug-only, test-only code to allow
438 // enter/leave/tailcall to be turned on at startup without a profiler. See
439 // code:ProfControlBlock#TestOnlyELT
440 EXTERN_C void STDMETHODCALLTYPE ProfileEnterNaked(UINT_PTR clientData);
441 EXTERN_C void STDMETHODCALLTYPE ProfileLeaveNaked(UINT_PTR clientData);
442 EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(UINT_PTR clientData);
443 #endif //PROF_TEST_ONLY_FORCE_ELT
444
445 // ----------------------------------------------------------------------------
446 // ProfilingAPIUtility::InitializeProfiling
447 //
448 // This is the top-most level of profiling API initialization, and is called directly by
449 // EEStartupHelper() (in ceemain.cpp).  This initializes internal structures relating to the
450 // Profiling API.  This also orchestrates loading the profiler and initializing it (if
451 // its GUID is specified in the environment).
452 //
453 // Return Value:
454 //    HRESULT indicating success or failure.  This is generally very lenient about internal
455 //    failures, as we don't want them to prevent the startup of the app:
456 //    S_OK = Environment didn't request a profiler, or
457 //           Environment did request a profiler, and it was loaded successfully
458 //    S_FALSE = There was a problem loading the profiler, but that shouldn't prevent the app
459 //              from starting up
460 //    else (failure) = There was a serious problem that should be dealt with by the caller
461 //
462 // Notes:
463 //     This function (or one of its callees) will log an error to the event log
464 //     if there is a failure
465 //
466 // Assumptions:
467 //    InitializeProfiling is called during startup, AFTER the host has initialized its
468 //    settings and the config variables have been read, but BEFORE the finalizer thread
469 //    has entered its first wait state.  ASSERTs are placed in
470 //    code:ProfilingAPIAttachDetach::Initialize (which is called by this function, and
471 //    which depends on these assumptions) to verify.
472
473 // static
474 HRESULT ProfilingAPIUtility::InitializeProfiling()
475 {
476     CONTRACTL
477     {
478         THROWS;
479         GC_TRIGGERS;
480
481         // This causes events to be logged, which loads resource strings,
482         // which takes locks.
483         CAN_TAKE_LOCK;
484
485         MODE_PREEMPTIVE;
486     } 
487     CONTRACTL_END;
488
489     InitializeLogging();
490
491     // NULL out / initialize members of the global profapi structure
492     g_profControlBlock.Init();
493
494     if (IsCompilationProcess())
495     {
496         LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling disabled for ngen process.\n"));
497         return S_OK;
498     }
499
500     AttemptLoadProfilerForStartup();
501     // For now, the return value from AttemptLoadProfilerForStartup is of no use to us. 
502     // Any event has been logged already by AttemptLoadProfilerForStartup, and
503     // regardless of whether a profiler got loaded, we still need to continue.
504
505
506 #ifdef PROF_TEST_ONLY_FORCE_ELT
507     // Test-only, debug-only code to enable ELT on startup regardless of whether a
508     // startup profiler is loaded.  See code:ProfControlBlock#TestOnlyELT.
509     DWORD dwEnableSlowELTHooks = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TestOnlyEnableSlowELTHooks);
510     if (dwEnableSlowELTHooks != 0)
511     {
512         (&g_profControlBlock)->fTestOnlyForceEnterLeave = TRUE;
513         SetJitHelperFunction(CORINFO_HELP_PROF_FCN_ENTER, (void *) ProfileEnterNaked);
514         SetJitHelperFunction(CORINFO_HELP_PROF_FCN_LEAVE, (void *) ProfileLeaveNaked);
515         SetJitHelperFunction(CORINFO_HELP_PROF_FCN_TAILCALL, (void *) ProfileTailcallNaked);
516         LOG((LF_CORPROF, LL_INFO10, "**PROF: Enabled test-only slow ELT hooks.\n"));
517     }
518 #endif //PROF_TEST_ONLY_FORCE_ELT
519
520 #ifdef PROF_TEST_ONLY_FORCE_OBJECT_ALLOCATED
521     // Test-only, debug-only code to enable ObjectAllocated callbacks on startup regardless of whether a
522     // startup profiler is loaded.  See code:ProfControlBlock#TestOnlyObjectAllocated.
523     DWORD dwEnableObjectAllocated = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TestOnlyEnableObjectAllocatedHook);
524     if (dwEnableObjectAllocated != 0)
525     {
526         (&g_profControlBlock)->fTestOnlyForceObjectAllocated = TRUE;
527         LOG((LF_CORPROF, LL_INFO10, "**PROF: Enabled test-only object ObjectAllocated hooks.\n"));
528     }
529 #endif //PROF_TEST_ONLY_FORCE_ELT
530
531
532 #ifdef _DEBUG
533     // Test-only, debug-only code to allow attaching profilers to call ICorProfilerInfo inteface, 
534     // which would otherwise be disallowed for attaching profilers
535     DWORD dwTestOnlyEnableICorProfilerInfo = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TestOnlyEnableICorProfilerInfo);
536     if (dwTestOnlyEnableICorProfilerInfo != 0)
537     {
538         (&g_profControlBlock)->fTestOnlyEnableICorProfilerInfo = TRUE;
539     }
540 #endif // _DEBUG
541
542     return S_OK;
543 }
544
545
546 // ----------------------------------------------------------------------------
547 // ProfilingAPIUtility::ProfilerCLSIDFromString
548 // 
549 // Description:
550 //    Takes a string form of a CLSID (or progid, believe it or not), and returns the
551 //    corresponding CLSID structure.
552 //    
553 // Arguments:
554 //    * wszClsid - [in / out] CLSID string to convert. This may also be a progid. This
555 //        ensures our behavior is backward-compatible with previous CLR versions. I don't
556 //        know why previous versions allowed the user to set a progid in the environment,
557 //        but well whatever. On [out], this string is normalized in-place (e.g.,
558 //        double-quotes around progid are removed).
559 //    * pClsid - [out] CLSID structure corresponding to wszClsid
560 //
561 // Return Value:
562 //    HRESULT indicating success or failure.
563 //    
564 // Notes:
565 //    * An event is logged if there is a failure.
566 //        
567
568 // static
569 HRESULT ProfilingAPIUtility::ProfilerCLSIDFromString(
570     __inout_z LPWSTR wszClsid, 
571     CLSID * pClsid)
572 {
573     CONTRACTL
574     {
575         THROWS;
576         GC_TRIGGERS;
577
578         // This causes events to be logged, which loads resource strings,
579         // which takes locks.
580         CAN_TAKE_LOCK;
581
582         MODE_PREEMPTIVE;
583     } 
584     CONTRACTL_END;
585
586     _ASSERTE(wszClsid != NULL);
587     _ASSERTE(pClsid != NULL);
588
589     HRESULT hr;
590
591     // Translate the string into a CLSID
592     if (*wszClsid == W('{'))
593     {
594         hr = IIDFromString(wszClsid, pClsid);
595     }
596     else
597     {
598 #ifndef FEATURE_PAL
599         WCHAR *szFrom, *szTo;
600
601 #ifdef _PREFAST_
602 #pragma warning(push)
603 #pragma warning(disable:26000) // "espX thinks there is an overflow here, but there isn't any"
604 #endif
605         for (szFrom=szTo=wszClsid;  *szFrom;  )
606         {
607             if (*szFrom == W('"'))
608             {
609                 ++szFrom;
610                 continue;
611             }
612             *szTo++ = *szFrom++;
613         }
614         *szTo = 0;
615         hr = CLSIDFromProgID(wszClsid, pClsid);
616 #ifdef _PREFAST_
617 #pragma warning(pop)
618 #endif /*_PREFAST_*/
619
620 #else // !FEATURE_PAL
621         // ProgID not supported on FEATURE_PAL
622         hr = E_INVALIDARG;
623 #endif // !FEATURE_PAL
624     }
625
626     if (FAILED(hr))
627     {
628         LOG((
629             LF_CORPROF, 
630             LL_INFO10, 
631             "**PROF: Invalid CLSID or ProgID (%S).  hr=0x%x.\n",
632             wszClsid,
633             hr));
634         ProfilingAPIUtility::LogProfError(IDS_E_PROF_BAD_CLSID, wszClsid, hr);
635         return hr;
636     }
637
638     return S_OK;
639 }
640
641 // ----------------------------------------------------------------------------
642 // ProfilingAPIUtility::AttemptLoadProfilerForStartup
643 // 
644 // Description:
645 //    Checks environment or registry to see if the app is configured to run with a
646 //    profiler loaded on startup. If so, this calls LoadProfiler() to load it up.
647 //    
648 // Arguments:
649 //
650 // Return Value:
651 //    * S_OK: Startup-profiler has been loaded
652 //    * S_FALSE: No profiler is configured for startup load
653 //    * else, HRESULT indicating failure that occurred
654 //        
655 // Assumptions:
656 //    * This should be called on startup, after g_profControlBlock is initialized, but
657 //        before any attach infrastructure is initialized. This ensures we don't receive
658 //        an attach request while startup-loading a profiler.
659 //        
660 // Notes:
661 //    * This or its callees will ensure an event is logged on failure (though will be
662 //        silent if no profiler is configured for startup load (which causes S_FALSE to
663 //        be returned)
664 //        
665
666 // static
667 HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup()
668 {
669     CONTRACTL
670     {
671         THROWS;
672         GC_TRIGGERS;
673
674         // This causes events to be logged, which loads resource strings,
675         // which takes locks.
676         CAN_TAKE_LOCK;
677
678         MODE_PREEMPTIVE;
679     } 
680     CONTRACTL_END;
681
682     HRESULT hr;
683
684     // Find out if profiling is enabled
685     DWORD fProfEnabled = 0;
686
687     fProfEnabled = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_ENABLE_PROFILING);
688
689     // If profiling is not enabled, return.
690     if (fProfEnabled == 0)
691     {
692         LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling not enabled.\n"));
693         return S_FALSE;
694     }
695
696     LOG((LF_CORPROF, LL_INFO10, "**PROF: Initializing Profiling Services.\n"));
697
698     // Get the CLSID of the profiler to CoCreate
699     NewArrayHolder<WCHAR> wszClsid(NULL);
700     NewArrayHolder<WCHAR> wszProfilerDLL(NULL);
701
702     IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid));
703
704 #if defined(_TARGET_X86_)
705     IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL));
706 #elif defined(_TARGET_AMD64_)
707     IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL));
708 #endif
709     if(wszProfilerDLL == NULL)
710     {
711         IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH, &wszProfilerDLL));
712     }
713     
714     // If the environment variable doesn't exist, profiling is not enabled.
715     if (wszClsid == NULL)
716     {
717         LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
718              "environment variable does not exist.\n"));
719
720         LogProfError(IDS_E_PROF_NO_CLSID);
721
722         return S_FALSE;
723     }
724
725     if ((wszProfilerDLL != NULL) && (wcslen(wszProfilerDLL) >= MAX_LONGPATH))
726     {
727         LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but COR_PROFILER_PATH was not set properly.\n"));
728
729         LogProfError(IDS_E_PROF_BAD_PATH);
730
731         return S_FALSE;
732     }
733     
734 #ifdef FEATURE_PAL
735     // If the environment variable doesn't exist, profiling is not enabled.
736     if (wszProfilerDLL == NULL)
737     {
738         LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required "
739              "environment variable does not exist.\n"));
740
741         LogProfError(IDS_E_PROF_BAD_PATH);
742
743         return S_FALSE;
744     }
745 #endif // FEATURE_PAL
746     
747     CLSID clsid;
748     hr = ProfilingAPIUtility::ProfilerCLSIDFromString(wszClsid, &clsid);
749     if (FAILED(hr))
750     {
751         // ProfilerCLSIDFromString already logged an event if there was a failure
752         return hr;
753     }
754
755     hr = LoadProfiler(
756         kStartupLoad,
757         &clsid,
758         wszClsid,
759         wszProfilerDLL,
760         NULL,               // No client data for startup load
761         0);                 // No client data for startup load
762     if (FAILED(hr))
763     {
764         // A failure in either the CLR or the profiler prevented it from
765         // loading.  Event has been logged.  Propagate hr
766         return hr;
767     }
768
769     return S_OK;
770 }
771
772
773 //---------------------------------------------------------------------------------------
774 //
775 // Performs lazy initialization that need not occur on startup, but does need to occur
776 // before trying to load a profiler.
777 //
778 // Return Value:
779 //    HRESULT indicating success or failure.
780 //
781
782 HRESULT ProfilingAPIUtility::PerformDeferredInit()
783 {
784     CONTRACTL
785     {
786         THROWS;
787         GC_TRIGGERS;
788         CAN_TAKE_LOCK;
789         MODE_ANY;
790     }
791     CONTRACTL_END;
792
793 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
794     // Initialize internal resources for detaching
795     HRESULT hr = ProfilingAPIDetach::Initialize();
796     if (FAILED(hr))
797     {
798         LOG((
799             LF_CORPROF, 
800             LL_ERROR, 
801             "**PROF: Unable to initialize resources for detaching. hr=0x%x.\n",
802             hr));
803         return hr;
804     }
805 #endif // FEATURE_PROFAPI_ATTACH_DETACH
806
807     if (s_csStatus == NULL)
808     {
809         s_csStatus = ClrCreateCriticalSection(
810             CrstProfilingAPIStatus, 
811             (CrstFlags) (CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
812         if (s_csStatus == NULL)
813         {
814             return E_OUTOFMEMORY;
815         }
816     }
817
818     return S_OK;
819 }
820
821 // ----------------------------------------------------------------------------
822 // ProfilingAPIUtility::LoadProfiler
823 //
824 // Description: 
825 //    Outermost common code for loading the profiler DLL.  Both startup and attach code
826 //    paths use this.
827 //
828 // Arguments:
829 //    * loadType - Startup load or attach load?
830 //    * pClsid - Profiler's CLSID
831 //    * wszClsid - Profiler's CLSID (or progid) in string form, for event log messages
832 //    * wszProfilerDLL - Profiler's DLL path
833 //    * pvClientData - For attach loads, this is the client data the trigger wants to
834 //        pass to the profiler DLL
835 //    * cbClientData - For attach loads, size of client data in bytes
836 //    * dwConcurrentGCWaitTimeoutInMs - Time out for wait operation on concurrent GC. Attach scenario only
837 //
838 // Return Value:
839 //    HRESULT indicating success or failure of the load
840 //
841 // Notes:
842 //    * On failure, this function or a callee will have logged an event
843 //
844
845 // static
846 HRESULT ProfilingAPIUtility::LoadProfiler(
847         LoadType loadType,
848         const CLSID * pClsid,
849         LPCWSTR wszClsid, 
850         LPCWSTR wszProfilerDLL,
851         LPVOID pvClientData,
852         UINT cbClientData,
853         DWORD dwConcurrentGCWaitTimeoutInMs)
854 {
855     CONTRACTL
856     {
857         THROWS;
858         GC_TRIGGERS;
859
860         // This causes events to be logged, which loads resource strings,
861         // which takes locks.
862         CAN_TAKE_LOCK;
863
864         MODE_ANY;
865     }
866     CONTRACTL_END;
867
868     if (g_fEEShutDown)
869     {
870         return CORPROF_E_RUNTIME_UNINITIALIZED;            
871     }
872     
873     enum ProfilerCompatibilityFlag
874     {
875         // Default: disable V2 profiler
876         kDisableV2Profiler = 0x0,
877
878         // Enable V2 profilers
879         kEnableV2Profiler  = 0x1,
880
881         // Disable Profiling
882         kPreventLoad       = 0x2,
883     };
884
885     ProfilerCompatibilityFlag profilerCompatibilityFlag = kDisableV2Profiler;
886     NewArrayHolder<WCHAR> wszProfilerCompatibilitySetting(NULL);
887
888     if (loadType == kStartupLoad)
889     {
890         CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ProfAPI_ProfilerCompatibilitySetting, &wszProfilerCompatibilitySetting);
891         if (wszProfilerCompatibilitySetting != NULL)
892         {
893             if (SString::_wcsicmp(wszProfilerCompatibilitySetting, W("EnableV2Profiler")) == 0)
894             {
895                 profilerCompatibilityFlag = kEnableV2Profiler;
896             }
897             else if (SString::_wcsicmp(wszProfilerCompatibilitySetting, W("PreventLoad")) == 0)
898             {
899                 profilerCompatibilityFlag = kPreventLoad;
900             }
901         }
902
903         if (profilerCompatibilityFlag == kPreventLoad)
904         {
905             LOG((LF_CORPROF, LL_INFO10, "**PROF: COMPlus_ProfAPI_ProfilerCompatibilitySetting is set to PreventLoad. "
906                  "Profiler will not be loaded.\n"));
907
908             LogProfInfo(IDS_PROF_PROFILER_DISABLED, 
909                         CLRConfig::EXTERNAL_ProfAPI_ProfilerCompatibilitySetting.name,
910                         wszProfilerCompatibilitySetting.GetValue(), 
911                         wszClsid);
912
913             return S_OK;
914         }
915     }
916
917     HRESULT hr;
918
919     hr = PerformDeferredInit();
920     if (FAILED(hr))
921     {
922         LOG((
923             LF_CORPROF, 
924             LL_ERROR, 
925             "**PROF: ProfilingAPIUtility::PerformDeferredInit failed. hr=0x%x.\n",
926             hr));
927         LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, hr);
928         return hr;
929     }
930
931     // Valid loadType?
932     _ASSERTE((loadType == kStartupLoad) || (loadType == kAttachLoad));
933
934     // If a nonzero client data size is reported, there'd better be client data!
935     _ASSERTE((cbClientData == 0) || (pvClientData != NULL));
936
937     // Client data is currently only specified on attach
938     _ASSERTE((pvClientData == NULL) || (loadType == kAttachLoad));
939
940     // Don't be telling me to load a profiler if there already is one.
941     _ASSERTE(g_profControlBlock.curProfStatus.Get() == kProfStatusNone);
942
943     // Create the ProfToEE interface to provide to the profiling services
944     NewHolder<ProfToEEInterfaceImpl> pProfEE(new (nothrow) ProfToEEInterfaceImpl());
945     if (pProfEE == NULL)
946     {
947         LOG((LF_CORPROF, LL_ERROR, "**PROF: Unable to allocate ProfToEEInterfaceImpl.\n"));
948         LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_OUTOFMEMORY);
949         return E_OUTOFMEMORY;
950     }
951
952     // Initialize the interface
953     hr = pProfEE->Init();
954     if (FAILED(hr))
955     {
956         LOG((LF_CORPROF, LL_ERROR, "**PROF: ProfToEEInterface::Init failed.\n"));
957         LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, hr);
958         return hr;
959     }
960
961     // Provide the newly created and inited interface
962     LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling code being provided with EE interface.\n"));
963
964     // Create a new EEToProf object
965     NewHolder<EEToProfInterfaceImpl> pEEProf(new (nothrow) EEToProfInterfaceImpl());
966     if (pEEProf == NULL)
967     {
968         LOG((LF_CORPROF, LL_ERROR, "**PROF: Unable to allocate EEToProfInterfaceImpl.\n"));
969         LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_OUTOFMEMORY);
970         return E_OUTOFMEMORY;
971     }
972
973 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
974     // We're about to load the profiler, so first make sure we successfully create the
975     // DetachThread and abort the load of the profiler if we can't. This ensures we don't
976     // load a profiler unless we're prepared to detach it later.
977     hr = ProfilingAPIDetach::CreateDetachThread();
978     if (FAILED(hr))
979     {
980         LOG((
981             LF_CORPROF, 
982             LL_ERROR, 
983             "**PROF: Unable to create DetachThread. hr=0x%x.\n",
984             hr));
985         ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, hr);
986         return hr;
987     }
988 #endif // FEATURE_PROFAPI_ATTACH_DETACH
989
990     // Initialize internal state of our EEToProfInterfaceImpl.  This also loads the
991     // profiler itself, but does not yet call its Initalize() callback
992     hr = pEEProf->Init(pProfEE, pClsid, wszClsid, wszProfilerDLL, (loadType == kAttachLoad), dwConcurrentGCWaitTimeoutInMs);
993     if (FAILED(hr))
994     {
995         LOG((LF_CORPROF, LL_ERROR, "**PROF: EEToProfInterfaceImpl::Init failed.\n"));
996         // EEToProfInterfaceImpl::Init logs an event log error on failure
997         return hr;
998     }
999
1000     // EEToProfInterfaceImpl::Init takes over the ownership of pProfEE when Init succeeds, and 
1001     // EEToProfInterfaceImpl::~EEToProfInterfaceImpl is responsible for releasing the resource pointed
1002     // by pProfEE.  Calling SuppressRelease here is necessary to avoid double release that 
1003     // the resource pointed by pProfEE are released by both pProfEE and pEEProf's destructor.
1004     pProfEE.SuppressRelease();
1005     pProfEE = NULL;
1006
1007     if (loadType == kAttachLoad)  // V4 profiler from attach
1008     {
1009         // Profiler must support ICorProfilerCallback3 to be attachable
1010         if (!pEEProf->IsCallback3Supported())
1011         {
1012             LogProfError(IDS_E_PROF_NOT_ATTACHABLE, wszClsid);
1013             return CORPROF_E_PROFILER_NOT_ATTACHABLE;
1014         }
1015     }
1016     else if (!pEEProf->IsCallback3Supported()) // V2 profiler from startup 
1017     {
1018         if (profilerCompatibilityFlag == kDisableV2Profiler)
1019         {
1020             LOG((LF_CORPROF, LL_INFO10, "**PROF: COMPlus_ProfAPI_ProfilerCompatibilitySetting is set to DisableV2Profiler (the default). "
1021                  "V2 profilers are not allowed, so that the configured V2 profiler is going to be unloaded.\n"));
1022
1023             LogProfInfo(IDS_PROF_V2PROFILER_DISABLED, wszClsid);
1024             return S_OK;
1025         }
1026
1027         _ASSERTE(profilerCompatibilityFlag == kEnableV2Profiler);
1028
1029         LOG((LF_CORPROF, LL_INFO10, "**PROF: COMPlus_ProfAPI_ProfilerCompatibilitySetting is set to EnableV2Profiler. "
1030              "The configured V2 profiler is going to be initialized.\n"));
1031
1032         LogProfInfo(IDS_PROF_V2PROFILER_ENABLED,
1033                     CLRConfig::EXTERNAL_ProfAPI_ProfilerCompatibilitySetting.name,
1034                     wszProfilerCompatibilitySetting.GetValue(), 
1035                     wszClsid);
1036     }
1037
1038     _ASSERTE(s_csStatus != NULL);
1039     {
1040         // All modification of the profiler's status and
1041         // g_profControlBlock.pProfInterface need to be serialized against each other,
1042         // in particular, this code should be serialized against detach and unloading
1043         // code.
1044         CRITSEC_Holder csh(s_csStatus);
1045
1046         // We've successfully allocated and initialized the callback wrapper object and the
1047         // Info interface implementation objects.  The profiler DLL is therefore also
1048         // successfully loaded (but not yet Initialized).  Transfer ownership of the 
1049         // callback wrapper object to globals (thus suppress a release when the local 
1050         // vars go out of scope).
1051         //
1052         // Setting this state now enables us to call into the profiler's Initialize()
1053         // callback (which we do immediately below), and have it successfully call
1054         // back into us via the Info interface (ProfToEEInterfaceImpl) to perform its
1055         // initialization.
1056         g_profControlBlock.pProfInterface = pEEProf.GetValue();
1057         pEEProf.SuppressRelease();
1058         pEEProf = NULL;
1059
1060         // Set global status to reflect the proper type of Init we're doing (attach vs
1061         // startup)
1062         g_profControlBlock.curProfStatus.Set(
1063             (loadType == kStartupLoad) ?
1064                 kProfStatusInitializingForStartupLoad :
1065                 kProfStatusInitializingForAttachLoad);
1066     }
1067
1068     // Now that the profiler is officially loaded and in Init status, call into the
1069     // profiler's appropriate Initialize() callback. Note that if the profiler fails this
1070     // call, we should abort the rest of the profiler loading, and reset our state so we
1071     // appear as if we never attempted to load the profiler.
1072
1073     if (loadType == kStartupLoad) 
1074     {
1075         hr = g_profControlBlock.pProfInterface->Initialize();
1076     }
1077     else
1078     {
1079         _ASSERTE(loadType == kAttachLoad);
1080         _ASSERTE(g_profControlBlock.pProfInterface->IsCallback3Supported());
1081         hr = g_profControlBlock.pProfInterface->InitializeForAttach(pvClientData, cbClientData);
1082     }
1083
1084     if (FAILED(hr))
1085     {
1086         LOG((
1087             LF_CORPROF, 
1088             LL_INFO10, 
1089             "**PROF: Profiler failed its Initialize callback.  hr=0x%x.\n",
1090             hr));
1091
1092         // If we timed out due to waiting on concurrent GC to finish, it is very likely this is 
1093         // the reason InitializeForAttach callback failed even though we cannot be sure and we cannot 
1094         // cannot assume hr is going to be CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC. 
1095         // The best we can do in this case is to report this failure anyway.
1096         if (g_profControlBlock.pProfInterface->HasTimedOutWaitingForConcurrentGC())
1097         {            
1098             ProfilingAPIUtility::LogProfError(IDS_E_PROF_TIMEOUT_WAITING_FOR_CONCURRENT_GC, dwConcurrentGCWaitTimeoutInMs, wszClsid);
1099         }
1100         
1101         // Check for known failure types, to customize the event we log
1102         if ((loadType == kAttachLoad) && 
1103             ((hr == CORPROF_E_PROFILER_NOT_ATTACHABLE) || (hr == E_NOTIMPL)))
1104         {
1105             _ASSERTE(g_profControlBlock.pProfInterface->IsCallback3Supported());
1106
1107             // Profiler supports ICorProfilerCallback3, but explicitly doesn't support
1108             // Attach loading.  So log specialized event
1109             LogProfError(IDS_E_PROF_NOT_ATTACHABLE, wszClsid);
1110
1111             // Normalize (CORPROF_E_PROFILER_NOT_ATTACHABLE || E_NOTIMPL) down to
1112             // CORPROF_E_PROFILER_NOT_ATTACHABLE
1113             hr = CORPROF_E_PROFILER_NOT_ATTACHABLE;
1114         }
1115         else if (hr == CORPROF_E_PROFILER_CANCEL_ACTIVATION)
1116         {
1117             // Profiler didn't encounter a bad error, but is voluntarily choosing not to
1118             // profile this runtime.  Profilers that need to set system environment
1119             // variables to be able to profile services may use this HRESULT to avoid
1120             // profiling all the other managed apps on the box.
1121             LogProfInfo(IDS_PROF_CANCEL_ACTIVATION, wszClsid);
1122         }
1123         else
1124         {
1125             LogProfError(IDS_E_PROF_INIT_CALLBACK_FAILED, wszClsid, hr);
1126         }
1127
1128         // Profiler failed; reset everything. This will automatically reset
1129         // g_profControlBlock and will unload the profiler's DLL.
1130         TerminateProfiling();
1131         return hr;
1132     }
1133
1134 #ifdef FEATURE_MULTICOREJIT
1135
1136     // Disable multicore JIT when profiling is enabled
1137     if (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_JIT_COMPILATION)
1138     {
1139         MulticoreJitManager::DisableMulticoreJit();
1140     }
1141
1142 #endif
1143
1144     // Indicate that profiling is properly initialized.  On an attach-load, this will
1145     // force a FlushStoreBuffers(), which is important for catch-up synchronization (see
1146     // code:#ProfCatchUpSynchronization)
1147     g_profControlBlock.curProfStatus.Set(kProfStatusActive);
1148
1149     LOG((
1150         LF_CORPROF, 
1151         LL_INFO10, 
1152         "**PROF: Profiler successfully loaded and initialized.\n"));
1153
1154     LogProfInfo(IDS_PROF_LOAD_COMPLETE, wszClsid);
1155
1156     LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiler created and enabled.\n"));
1157
1158     if (loadType == kStartupLoad)
1159     {
1160         // For startup profilers only: If the profiler is interested in tracking GC
1161         // events, then we must disable concurrent GC since concurrent GC can allocate
1162         // and kill objects without relocating and thus not doing a heap walk.
1163         if (CORProfilerTrackGC())
1164         {
1165             LOG((LF_CORPROF, LL_INFO10, "**PROF: Turning off concurrent GC at startup.\n"));
1166             // Previously we would use SetGCConcurrent(0) to indicate to the GC that it shouldn't even
1167             // attempt to use concurrent GC. The standalone GC feature create a cycle during startup,
1168             // where the profiler couldn't set startup flags for the GC. To overcome this, we call
1169             // TempraryDisableConcurrentGC and never enable it again. This has a perf cost, since the
1170             // GC will create concurrent GC data structures, but it is acceptable in the context of
1171             // this kind of profiling.
1172             GCHeapUtilities::GetGCHeap()->TemporaryDisableConcurrentGC();
1173             LOG((LF_CORPROF, LL_INFO10, "**PROF: Concurrent GC has been turned off at startup.\n"));
1174         }
1175     }
1176
1177     if (loadType == kAttachLoad)
1178     {
1179         // #ProfCatchUpSynchronization
1180         // 
1181         // Now that callbacks are enabled (and all threads are aware), tell an attaching
1182         // profiler that it's safe to request catchup information.
1183         //
1184         // There's a race we're preventing that's worthwhile to spell out. An attaching
1185         // profiler should be able to get a COMPLETE set of data through the use of
1186         // callbacks unioned with the use of catch-up enumeration Info functions. To
1187         // achieve this, we must ensure that there is no "hole"--any new data the
1188         // profiler seeks must be available from a callback or a catch-up info function
1189         // (or both, as dupes are ok). That means that:
1190         // 
1191         // * callbacks must be enabled on other threads NO LATER THAN the profiler begins
1192         //     requesting catch-up information on this thread
1193         //     * Abbreviate: callbacks <= catch-up.
1194         //         
1195         // Otherwise, if catch-up < callbacks, then it would be possible to have this:
1196         // 
1197         // * catch-up < new data arrives < callbacks.
1198         //     
1199         // In this nightmare scenario, the new data would not be accessible from the
1200         // catch-up calls made by the profiler (cuz the profiler made the calls too
1201         // early) or the callbacks made into the profiler (cuz the callbacks were enabled
1202         // too late). That's a hole, and that's bad. So we ensure callbacks <= catch-up
1203         // by the following order of operations:
1204         // 
1205         // * This thread:
1206         //     * a: Set (volatile) currentProfStatus = kProfStatusActive (done above) and
1207         //         event mask bits (profiler did this in Initialize() callback above,
1208         //         when it called SetEventMask)
1209         //     * b: Flush CPU buffers (done automatically when we set status to
1210         //         kProfStatusActive)
1211         //     * c: CLR->Profiler call: ProfilerAttachComplete() (below). Inside this
1212         //         call:
1213         //         * Profiler->CLR calls: Catch-up Info functions
1214         // * Other threads:
1215         //     * a: New data (thread, JIT info, etc.) is created
1216         //     * b: This new data is now available to a catch-up Info call
1217         //     * c: currentProfStatus & event mask bits are accurately visible to thread
1218         //         in determining whether to make a callback
1219         //     * d: Read currentProfStatus & event mask bits and make callback
1220         //         (CLR->Profiler) if necessary
1221         //         
1222         // So as long as OtherThreads.c <= ThisThread.c we're ok. This means other
1223         // threads must be able to get a clean read of the (volatile) currentProfStatus &
1224         // event mask bits BEFORE this thread calls ProfilerAttachComplete(). Use of the
1225         // "volatile" keyword ensures that compiler optimizations and (w/ VC2005+
1226         // compilers) the CPU's instruction reordering optimizations at runtime are
1227         // disabled enough such that they do not hinder the order above. Use of
1228         // FlushStoreBuffers() ensures that multiple caches on multiple CPUs do not
1229         // hinder the order above (by causing other threads to get stale reads of the
1230         // volatiles).
1231         // 
1232         // For more information about catch-up enumerations and exactly which entities,
1233         // and which stage of loading, are permitted to appear in the enumerations, see
1234         // code:ProfilerFunctionEnum::Init#ProfilerEnumGeneral
1235
1236         {
1237             BEGIN_PIN_PROFILER(CORProfilerPresent());
1238             g_profControlBlock.pProfInterface->ProfilerAttachComplete();
1239             END_PIN_PROFILER();
1240         }
1241     }
1242     return S_OK;
1243 }
1244
1245
1246 //---------------------------------------------------------------------------------------
1247 //
1248 // Performs the evacuation checks by grabbing the thread store lock, iterating through
1249 // all EE Threads, and querying each one's evacuation counter.  If they're all 0, the
1250 // profiler is ready to be unloaded.
1251 //
1252 // Return Value:
1253 //    Nonzero iff the profiler is fully evacuated and ready to be unloaded.
1254 //
1255
1256 // static
1257 BOOL ProfilingAPIUtility::IsProfilerEvacuated()
1258 {
1259     CONTRACTL
1260     {
1261         NOTHROW;
1262         GC_TRIGGERS;
1263         MODE_ANY;
1264         CAN_TAKE_LOCK;
1265     }
1266     CONTRACTL_END;
1267
1268     _ASSERTE(g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching);
1269
1270     // Check evacuation counters on all the threads (see
1271     // code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
1272     // for details). Doing this under the thread store lock not only ensures we can
1273     // iterate through the Thread objects safely, but also forces us to serialize with
1274     // the GC. The latter is important, as server GC enters the profiler on non-EE
1275     // Threads, and so no evacuation counters might be incremented during server GC even
1276     // though control could be entering the profiler.
1277     {
1278         ThreadStoreLockHolder TSLockHolder;
1279
1280         Thread * pThread = ThreadStore::GetAllThreadList(
1281             NULL,   // cursor thread; always NULL to begin with
1282             0,      // mask to AND with Thread::m_State to filter returned threads 
1283             0);     // bits to match the result of the above AND.  (m_State & 0 == 0,
1284                     // so we won't filter out any threads)
1285
1286         // Note that, by not filtering out any of the threads, we're intentionally including
1287         // stuff like TS_Dead or TS_Unstarted.  But that keeps us on the safe
1288         // side.  If an EE Thread object exists, we want to check its counters to be
1289         // absolutely certain it isn't executing in a profiler.
1290
1291         while (pThread != NULL)
1292         {
1293             // Note that pThread is still in motion as we check its evacuation counter.
1294             // This is ok, because we've already changed the profiler status to
1295             // kProfStatusDetaching and flushed CPU buffers. So at this point the counter
1296             // will typically only go down to 0 (and not increment anymore), with one
1297             // small exception (below). So if we get a read of 0 below, the counter will
1298             // typically stay there. Specifically:
1299             //     * pThread is most likely not about to increment its evacuation counter
1300             //         from 0 to 1 because pThread sees that the status is
1301             //         kProfStatusDetaching.
1302             //     * Note that there is a small race where pThread might actually
1303             //         increment its evac counter from 0 to 1 (if it dirty-read the
1304             //         profiler status a tad too early), but that implies that when
1305             //         pThread rechecks the profiler status (clean read) then pThread
1306             //         will immediately decrement the evac counter back to 0 and avoid
1307             //         calling into the EEToProfInterfaceImpl pointer.
1308             // 
1309             // (see
1310             // code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
1311             // for details)
1312             DWORD dwEvacCounter = pThread->GetProfilerEvacuationCounter();
1313             if (dwEvacCounter != 0)
1314             {
1315                 LOG((
1316                     LF_CORPROF,
1317                     LL_INFO100,
1318                     "**PROF: Profiler not yet evacuated because OS Thread ID 0x%x has evac counter of %d (decimal).\n",
1319                     pThread->GetOSThreadId(),
1320                     dwEvacCounter));
1321                 return FALSE;
1322             }
1323
1324             pThread = ThreadStore::GetAllThreadList(pThread, 0, 0);
1325         }
1326     }
1327
1328     // FUTURE: When rejit feature crew complete, add code to verify all rejitted
1329     // functions are fully reverted and off of all stacks.  If this is very easy to
1330     // verify (e.g., checking a single value), consider putting it above the loop
1331     // above so we can early-out quicker if rejitted code is still around.
1332
1333     // We got this far without returning, so the profiler is fully evacuated
1334     return TRUE;
1335 }
1336
1337 //---------------------------------------------------------------------------------------
1338 //
1339 // This is the top-most level of profiling API teardown, and is called directly by
1340 // EEShutDownHelper() (in ceemain.cpp). This cleans up internal structures relating to
1341 // the Profiling API. If we're not in process teardown, then this also releases the
1342 // profiler COM object and frees the profiler DLL
1343 //
1344
1345 // static
1346 void ProfilingAPIUtility::TerminateProfiling()
1347 {
1348     CONTRACTL
1349     {
1350         NOTHROW;
1351         GC_TRIGGERS;
1352         MODE_ANY;
1353         CAN_TAKE_LOCK;
1354     }
1355     CONTRACTL_END;
1356
1357     if (IsAtProcessExit())
1358     {
1359         // We're tearing down the process so don't bother trying to clean everything up.
1360         // There's no reliable way to verify other threads won't be trying to re-enter
1361         // the profiler anyway, so cleaning up here could cause AVs.
1362         return;
1363     }
1364
1365     _ASSERTE(s_csStatus != NULL);
1366     {
1367         // We're modifying status and possibly unloading the profiler DLL below, so
1368         // serialize this code with any other loading / unloading / detaching code.
1369         CRITSEC_Holder csh(s_csStatus);
1370
1371
1372 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
1373         if (ProfilingAPIDetach::GetEEToProfPtr() != NULL)
1374         {
1375             // The profiler is still being referenced by
1376             // ProfilingAPIDetach::s_profilerDetachInfo, so don't try to release and
1377             // unload it. This can happen if Shutdown and Detach race, and Shutdown wins.
1378             // For example, we could be called as part of Shutdown, but the profiler
1379             // called RequestProfilerDetach near shutdown time as well (or even earlier
1380             // but remains un-evacuated as shutdown begins). Whatever the cause, just
1381             // don't unload the profiler here (as part of shutdown), and let the Detach
1382             // Thread deal with it (if it gets the chance).
1383             // 
1384             // Note: Since this check occurs inside s_csStatus, we don't have to worry
1385             // that ProfilingAPIDetach::GetEEToProfPtr() will suddenly change during the
1386             // code below.
1387             // 
1388             // FUTURE: For reattach-with-neutered-profilers feature crew, change the
1389             // above to scan through list of detaching profilers to make sure none of
1390             // them give a GetEEToProfPtr() equal to g_profControlBlock.pProfInterface.
1391             return;
1392         }
1393 #endif // FEATURE_PROFAPI_ATTACH_DETACH
1394
1395         if (g_profControlBlock.curProfStatus.Get() == kProfStatusActive)
1396         {
1397             g_profControlBlock.curProfStatus.Set(kProfStatusDetaching);
1398
1399             // Profiler was active when TerminateProfiling() was called, so we're unloading
1400             // it due to shutdown. But other threads may still be trying to enter profiler
1401             // callbacks (e.g., ClassUnloadStarted() can get called during shutdown). Now
1402             // that the status has been changed to kProfStatusDetaching, no new threads will
1403             // attempt to enter the profiler. But use the detach evacuation counters to see
1404             // if other threads already began to enter the profiler.
1405             if (!ProfilingAPIUtility::IsProfilerEvacuated())
1406             {
1407                 // Other threads might be entering the profiler, so just skip cleanup
1408                 return;
1409             }
1410         }
1411
1412
1413         // If we have a profiler callback wrapper and / or info implementation
1414         // active, then terminate them.
1415
1416         if (g_profControlBlock.pProfInterface.Load() != NULL)
1417         {
1418             // This destructor takes care of releasing the profiler's ICorProfilerCallback*
1419             // interface, and unloading the DLL when we're not in process teardown.
1420             delete g_profControlBlock.pProfInterface;
1421             g_profControlBlock.pProfInterface.Store(NULL);
1422         }
1423
1424         // NOTE: Intentionally not deleting s_pSidBuffer. Doing so can cause annoying races
1425         // with other threads that lazily create and initialize it when needed. (Example:
1426         // it's used to fill out the "User" field of profiler event log entries.) Keeping
1427         // s_pSidBuffer around after a profiler detaches and before a new one attaches
1428         // consumes a bit more memory unnecessarily, but it'll get paged out if another
1429         // profiler doesn't attach.
1430
1431         // NOTE: Similarly, intentionally not destroying / NULLing s_csStatus. If
1432         // s_csStatus is already initialized, we can reuse it each time we do another
1433         // attach / detach, so no need to destroy it.
1434
1435         // If we disabled concurrent GC and somehow failed later during the initialization
1436         if (g_profControlBlock.fConcurrentGCDisabledForAttach)
1437         {
1438             // We know for sure GC has been fully initialized as we've turned off concurrent GC before
1439             _ASSERTE(IsGarbageCollectorFullyInitialized());
1440             GCHeapUtilities::GetGCHeap()->TemporaryEnableConcurrentGC();
1441             g_profControlBlock.fConcurrentGCDisabledForAttach = FALSE;
1442         }
1443
1444         // #ProfileResetSessionStatus Reset all the status variables that are for the current 
1445         // profiling attach session.
1446         // When you are adding new status in g_profControlBlock, you need to think about whether
1447         // your new status is per-session, or consistent across sessions
1448         g_profControlBlock.ResetPerSessionStatus();
1449
1450         g_profControlBlock.curProfStatus.Set(kProfStatusNone);
1451     }
1452 }
1453
1454 #ifndef FEATURE_PAL
1455
1456 // ----------------------------------------------------------------------------
1457 // ProfilingAPIUtility::GetCurrentProcessUserSid
1458 // 
1459 // Description:
1460 //    Generates a SID of the current user from the current process's token. SID is
1461 //    returned in an [out] param, and is also cached for future use. The SID is used for
1462 //    two purposes: event log entries (for filling out the User field) and the ACL used
1463 //    on the globally named pipe object for attaching profilers.
1464 //    
1465 // Arguments:
1466 //    * ppsid - [out] Generated (or cached) SID
1467 //        
1468 // Return Value:
1469 //    HRESULT indicating success or failure.
1470 //    
1471
1472 // static
1473 HRESULT ProfilingAPIUtility::GetCurrentProcessUserSid(PSID * ppsid)
1474 {
1475     CONTRACTL
1476     {
1477         NOTHROW;
1478         GC_NOTRIGGER;
1479         MODE_ANY;
1480     }
1481     CONTRACTL_END;
1482
1483     if (s_pSidBuffer == NULL)
1484     {
1485         HRESULT hr;
1486         NewHolder<SidBuffer> pSidBuffer(new (nothrow) SidBuffer);
1487         if (pSidBuffer == NULL)
1488         {
1489             return E_OUTOFMEMORY;
1490         }
1491
1492         // This gets the SID of the user from the process token
1493         hr = pSidBuffer->InitFromProcessUserNoThrow(GetCurrentProcessId());
1494         if (FAILED(hr))
1495         {
1496             return hr;
1497         }
1498
1499         if (FastInterlockCompareExchangePointer(
1500             &s_pSidBuffer, 
1501             pSidBuffer.GetValue(), 
1502             NULL) == NULL)
1503         {
1504             // Lifetime successfully transferred to s_pSidBuffer, so don't delete it here
1505             pSidBuffer.SuppressRelease();
1506         }
1507     }
1508
1509     _ASSERTE(s_pSidBuffer != NULL);
1510     _ASSERTE(s_pSidBuffer->GetSid().RawSid() != NULL);
1511     *ppsid = s_pSidBuffer->GetSid().RawSid();
1512     return S_OK;
1513 }
1514
1515 #endif // !FEATURE_PAL
1516
1517 #endif // PROFILING_SUPPORTED