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
14EventPipeProvider::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
37EventPipeProvider::~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
78const SString& EventPipeProvider::GetProviderName() const
79{
80 LIMITED_METHOD_CONTRACT;
81
82 return m_providerName;
83}
84
85bool EventPipeProvider::Enabled() const
86{
87 LIMITED_METHOD_CONTRACT;
88
89 return (m_pConfig->Enabled() && m_enabled);
90}
91
92bool 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
102bool 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
114void 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
133EventPipeEvent* 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
146EventPipeEvent* 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
172void 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
189void 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
242bool EventPipeProvider::GetDeleteDeferred() const
243{
244 LIMITED_METHOD_CONTRACT;
245 return m_deleteDeferred;
246}
247
248void EventPipeProvider::SetDeleteDeferred()
249{
250 LIMITED_METHOD_CONTRACT;
251 m_deleteDeferred = true;
252}
253
254void 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