summaryrefslogtreecommitdiff
path: root/src/vm/profilinghelper.h
blob: ee5f60a247bb2c35607997561e7ac80c1122b509 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//
// ProfilingHelper.h
// 

//
// Declaration of helper classes used for miscellaneous purposes within the
// profiling API
//

// ======================================================================================

#ifndef __PROFILING_HELPER_H__
#define __PROFILING_HELPER_H__

#ifndef PROFILING_SUPPORTED
#error PROFILING_SUPPORTED is not set. Do not include ProfilingHelper.h.
#endif

#include <windows.h>

#include "corprof.h"
#include "eeprofinterfaces.h"

#define COM_METHOD HRESULT STDMETHODCALLTYPE

#ifdef _DEBUG
// On DEBUG builds, setting the COMPlus_ProfAPIFault to a bitmask of the flags
// below forces the Profiling API to return failures at various points.
// Useful for event log testing.  Also see code:ProfilingAPIUtility.ShouldInjectProfAPIFault
enum ProfAPIFaultFlags
{
    // Forces the startup path to log an IDS_E_PROF_INTERNAL_INIT error
    kProfAPIFault_StartupInternal   = 0x00001,
};
#endif // _DEBUG

class SidBuffer;

//---------------------------------------------------------------------------------------
// Static-only class to coordinate initialization of the various profiling API
// structures, plus other utility stuff.
//
class ProfilingAPIUtility
{
private:    
    enum ProfilerCompatibilityFlag
    {
        // Default: disable V2 profiler
        kDisableV2Profiler = 0x0,

        // Enable V2 profilers
        kEnableV2Profiler  = 0x1,

        // Disable Profiling
        kPreventLoad       = 0x2,
    };

public:
    static HRESULT InitializeProfiling();
    static HRESULT LoadProfilerForAttach(
        const CLSID * pClsid,
        LPCWSTR wszProfilerDLL,
        LPVOID pvClientData,
        UINT cbClientData,
        DWORD dwConcurrentGCWaitTimeoutInMs);

    static BOOL IsProfilerEvacuated();
    static void TerminateProfiling();
    static void LogProfError(int iStringResourceID, ...);
    static void LogProfInfo(int iStringResourceID, ...);
    static void LogNoInterfaceError(REFIID iidRequested, LPCWSTR wszClsid);
    INDEBUG(static BOOL ShouldInjectProfAPIFault(ProfAPIFaultFlags faultFlag);)
#ifndef FEATURE_PAL
    static HRESULT GetCurrentProcessUserSid(PSID * ppsid);
#endif // !FEATURE_PAL

#ifdef FEATURE_PROFAPI_ATTACH_DETACH
    // ----------------------------------------------------------------------------
    // ProfilingAPIUtility::IncEvacuationCounter
    //
    // Description: 
    //    Simple helper to increase the evacuation counter inside an EE thread by one
    //
    // Arguments:
    //    * pThread - pointer to an EE Thread
    //
    template<typename ThreadType>
    static FORCEINLINE void IncEvacuationCounter(ThreadType * pThread) 
    {
        LIMITED_METHOD_CONTRACT;

        if (pThread) 
            pThread->IncProfilerEvacuationCounter();
    }

    // ----------------------------------------------------------------------------
    // ProfilingAPIUtility::DecEvacuationCounter
    //
    // Description: 
    //    Simple helper to decrease the evacuation counter inside an EE thread by one
    //    
    // Arguments:
    //    * pThread - pointer to an EE Thread
    //
    template<typename ThreadType>
    static FORCEINLINE void DecEvacuationCounter(ThreadType * pThread) 
    {
        LIMITED_METHOD_CONTRACT;

        if (pThread) 
            pThread->DecProfilerEvacuationCounter();
    }

#endif // FEATURE_PROFAPI_ATTACH_DETACH

    // See code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
    static CRITSEC_COOKIE GetStatusCrst();

private:
    // ---------------------------------------------------------------------------------------
    // Enum used in LoadProfiler() to differentiate whether we're loading the profiler
    // for startup or for attach
    enum LoadType
    {
        kStartupLoad,
        kAttachLoad,
    };

    // Allocated lazily the first time it's needed, and then remains allocated until the
    // process exits.
    static SidBuffer * s_pSidBuffer;

    // See code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
    static CRITSEC_COOKIE s_csStatus;

    // Static-only class.  Private constructor enforces you don't try to make an instance
    ProfilingAPIUtility() {}

    static HRESULT PerformDeferredInit();
    static HRESULT DoPreInitialization(
        EEToProfInterfaceImpl *pEEProf,
        const CLSID *pClsid, 
        LPCWSTR wszClsid, 
        LPCWSTR wszProfilerDLL, 
        LoadType loadType, 
        DWORD dwConcurrentGCWaitTimeoutInMs);
    static HRESULT LoadProfiler(
        LoadType loadType,
        const CLSID * pClsid,
        LPCWSTR wszClsid,
        LPCWSTR wszProfilerDLL,
        LPVOID pvClientData,
        UINT cbClientData,
        DWORD dwConcurrentGCWaitTimeoutInMs = INFINITE);
    static HRESULT ProfilerCLSIDFromString(__inout_z LPWSTR wszClsid, CLSID * pClsid);
    static HRESULT AttemptLoadProfilerForStartup();

    static void AppendSupplementaryInformation(int iStringResource, SString * pString);

    static void LogProfEventVA(
        int iStringResourceID, 
        WORD wEventType,
        va_list insertionArgs);
};


//---------------------------------------------------------------------------------------
// When we call into profiler code, we push one of these babies onto the stack to
// remember on the Thread how the profiler was called.  If the profiler calls back into us,
// we use the flags that this set to authorize.
//
class SetCallbackStateFlagsHolder
{
public:
    SetCallbackStateFlagsHolder(DWORD dwFlags);
    ~SetCallbackStateFlagsHolder();
    
private:
    Thread *   m_pThread;
    DWORD      m_dwOriginalFullState;
};

#endif //__PROFILING_HELPER_H__