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 | #include "common.h" |
6 | #include "eventpipe.h" |
7 | #include "eventpipeconfiguration.h" |
8 | #include "eventpipeevent.h" |
9 | #include "eventpipeprovider.h" |
10 | #include "sha1.h" |
11 | |
12 | #ifdef FEATURE_PERFTRACING |
13 | |
14 | EventPipeProvider::EventPipeProvider(EventPipeConfiguration *pConfig, const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData) |
15 | { |
16 | CONTRACTL |
17 | { |
18 | THROWS; |
19 | GC_NOTRIGGER; |
20 | MODE_ANY; |
21 | PRECONDITION(pConfig != NULL); |
22 | } |
23 | CONTRACTL_END; |
24 | |
25 | m_providerName = providerName; |
26 | m_enabled = false; |
27 | m_deleteDeferred = false; |
28 | m_keywords = 0; |
29 | m_providerLevel = EventPipeEventLevel::Critical; |
30 | m_pEventList = new SList<SListElem<EventPipeEvent*>>(); |
31 | m_pCallbackFunction = pCallbackFunction; |
32 | m_pCallbackData = pCallbackData; |
33 | m_pConfig = pConfig; |
34 | m_deleteDeferred = false; |
35 | } |
36 | |
37 | EventPipeProvider::~EventPipeProvider() |
38 | { |
39 | CONTRACTL |
40 | { |
41 | NOTHROW; |
42 | GC_TRIGGERS; |
43 | MODE_ANY; |
44 | } |
45 | CONTRACTL_END; |
46 | |
47 | // Free all of the events. |
48 | if(m_pEventList != NULL) |
49 | { |
50 | // We swallow exceptions here because the HOST_BREAKABLE |
51 | // lock may throw and this destructor gets called in throw |
52 | // intolerant places. If that happens the event list will leak |
53 | EX_TRY |
54 | { |
55 | // Take the lock before manipulating the list. |
56 | CrstHolder _crst(EventPipe::GetLock()); |
57 | |
58 | SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead(); |
59 | while(pElem != NULL) |
60 | { |
61 | EventPipeEvent *pEvent = pElem->GetValue(); |
62 | delete pEvent; |
63 | |
64 | SListElem<EventPipeEvent*> *pCurElem = pElem; |
65 | pElem = m_pEventList->GetNext(pElem); |
66 | delete pCurElem; |
67 | } |
68 | |
69 | delete m_pEventList; |
70 | } |
71 | EX_CATCH { } |
72 | EX_END_CATCH(SwallowAllExceptions); |
73 | |
74 | m_pEventList = NULL; |
75 | } |
76 | } |
77 | |
78 | const SString& EventPipeProvider::GetProviderName() const |
79 | { |
80 | LIMITED_METHOD_CONTRACT; |
81 | |
82 | return m_providerName; |
83 | } |
84 | |
85 | bool EventPipeProvider::Enabled() const |
86 | { |
87 | LIMITED_METHOD_CONTRACT; |
88 | |
89 | return (m_pConfig->Enabled() && m_enabled); |
90 | } |
91 | |
92 | bool EventPipeProvider::EventEnabled(INT64 keywords) const |
93 | { |
94 | LIMITED_METHOD_CONTRACT; |
95 | |
96 | // The event is enabled if: |
97 | // - The provider is enabled. |
98 | // - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0. |
99 | return (Enabled() && ((keywords == 0) || ((m_keywords & keywords) != 0))); |
100 | } |
101 | |
102 | bool EventPipeProvider::EventEnabled(INT64 keywords, EventPipeEventLevel eventLevel) const |
103 | { |
104 | LIMITED_METHOD_CONTRACT; |
105 | |
106 | // The event is enabled if: |
107 | // - The provider is enabled. |
108 | // - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0. |
109 | // - The event level is LogAlways or the provider's verbosity level is set to greater than the event's verbosity level in the manifest. |
110 | return (EventEnabled(keywords) && |
111 | ((eventLevel == EventPipeEventLevel::LogAlways) || (m_providerLevel >= eventLevel))); |
112 | } |
113 | |
114 | void EventPipeProvider::SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel, LPCWSTR pFilterData) |
115 | { |
116 | CONTRACTL |
117 | { |
118 | THROWS; |
119 | GC_TRIGGERS; |
120 | MODE_ANY; |
121 | PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread()); |
122 | } |
123 | CONTRACTL_END; |
124 | |
125 | m_enabled = providerEnabled; |
126 | m_keywords = keywords; |
127 | m_providerLevel = providerLevel; |
128 | |
129 | RefreshAllEvents(); |
130 | InvokeCallback(pFilterData); |
131 | } |
132 | |
133 | EventPipeEvent* EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, BYTE *pMetadata, unsigned int metadataLength) |
134 | { |
135 | CONTRACTL |
136 | { |
137 | THROWS; |
138 | GC_NOTRIGGER; |
139 | MODE_ANY; |
140 | } |
141 | CONTRACTL_END; |
142 | |
143 | return AddEvent(eventID, keywords, eventVersion, level, true /* needStack */, pMetadata, metadataLength); |
144 | } |
145 | |
146 | EventPipeEvent* EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata, unsigned int metadataLength) |
147 | { |
148 | CONTRACTL |
149 | { |
150 | THROWS; |
151 | GC_NOTRIGGER; |
152 | MODE_ANY; |
153 | } |
154 | CONTRACTL_END; |
155 | |
156 | // Create the event. |
157 | EventPipeEvent *pEvent = new EventPipeEvent( |
158 | *this, |
159 | keywords, |
160 | eventID, |
161 | eventVersion, |
162 | level, |
163 | needStack, |
164 | pMetadata, |
165 | metadataLength); |
166 | |
167 | // Add it to the list of events. |
168 | AddEvent(*pEvent); |
169 | return pEvent; |
170 | } |
171 | |
172 | void EventPipeProvider::AddEvent(EventPipeEvent &event) |
173 | { |
174 | CONTRACTL |
175 | { |
176 | THROWS; |
177 | GC_NOTRIGGER; |
178 | MODE_ANY; |
179 | } |
180 | CONTRACTL_END; |
181 | |
182 | // Take the config lock before inserting a new event. |
183 | CrstHolder _crst(EventPipe::GetLock()); |
184 | |
185 | m_pEventList->InsertTail(new SListElem<EventPipeEvent*>(&event)); |
186 | event.RefreshState(); |
187 | } |
188 | |
189 | void EventPipeProvider::InvokeCallback(LPCWSTR pFilterData) |
190 | { |
191 | CONTRACTL |
192 | { |
193 | THROWS; |
194 | GC_TRIGGERS; |
195 | MODE_ANY; |
196 | PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread()); |
197 | } |
198 | CONTRACTL_END; |
199 | |
200 | |
201 | bool isEventFilterDescriptorInitialized = false; |
202 | EventFilterDescriptor eventFilterDescriptor{}; |
203 | CQuickArrayBase<char> buffer; |
204 | buffer.Init(); |
205 | |
206 | if (pFilterData != NULL) |
207 | { |
208 | // The callback is expecting that filter data to be a concatenated list |
209 | // of pairs of null terminated strings. The first member of the pair is |
210 | // the key and the second is the value. |
211 | // To convert to this format we need to convert all '=' and ';' |
212 | // characters to '\0'. |
213 | SString dstBuffer; |
214 | SString(pFilterData).ConvertToUTF8(dstBuffer); |
215 | |
216 | const COUNT_T BUFFER_SIZE = dstBuffer.GetCount() + 1; |
217 | buffer.AllocThrows(BUFFER_SIZE); |
218 | for (COUNT_T i = 0; i < BUFFER_SIZE; ++i) |
219 | buffer[i] = (dstBuffer[i] == '=' || dstBuffer[i] == ';') ? '\0' : dstBuffer[i]; |
220 | |
221 | eventFilterDescriptor.Ptr = reinterpret_cast<ULONGLONG>(buffer.Ptr()); |
222 | eventFilterDescriptor.Size = static_cast<ULONG>(BUFFER_SIZE); |
223 | eventFilterDescriptor.Type = 0; // EventProvider.cs: `internal enum ControllerCommand.Update` |
224 | isEventFilterDescriptorInitialized = true; |
225 | } |
226 | |
227 | if(m_pCallbackFunction != NULL && !g_fEEShutDown) |
228 | { |
229 | (*m_pCallbackFunction)( |
230 | NULL, /* providerId */ |
231 | m_enabled, |
232 | (UCHAR) m_providerLevel, |
233 | m_keywords, |
234 | 0 /* matchAllKeywords */, |
235 | isEventFilterDescriptorInitialized ? &eventFilterDescriptor : NULL, |
236 | m_pCallbackData /* CallbackContext */); |
237 | } |
238 | |
239 | buffer.Destroy(); |
240 | } |
241 | |
242 | bool EventPipeProvider::GetDeleteDeferred() const |
243 | { |
244 | LIMITED_METHOD_CONTRACT; |
245 | return m_deleteDeferred; |
246 | } |
247 | |
248 | void EventPipeProvider::SetDeleteDeferred() |
249 | { |
250 | LIMITED_METHOD_CONTRACT; |
251 | m_deleteDeferred = true; |
252 | } |
253 | |
254 | void EventPipeProvider::RefreshAllEvents() |
255 | { |
256 | CONTRACTL |
257 | { |
258 | THROWS; |
259 | GC_NOTRIGGER; |
260 | MODE_ANY; |
261 | PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread()); |
262 | } |
263 | CONTRACTL_END; |
264 | |
265 | SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead(); |
266 | while(pElem != NULL) |
267 | { |
268 | EventPipeEvent *pEvent = pElem->GetValue(); |
269 | pEvent->RefreshState(); |
270 | |
271 | pElem = m_pEventList->GetNext(pElem); |
272 | } |
273 | } |
274 | |
275 | #endif // FEATURE_PERFTRACING |
276 | |