Merge pull request #17531 from BruceForstall/SpmiProtectJitStartup
[platform/upstream/coreclr.git] / src / debug / di / shimevents.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 // File: ShimEvents.cpp
6 // 
7
8 //
9 // The V3 ICD debugging APIs have a lower abstraction level than V2.
10 // This provides V2 ICD debugging functionality on top of the V3 debugger object.
11 //*****************************************************************************
12
13 #include "stdafx.h"
14
15 #include "safewrap.h"
16 #include "check.h" 
17
18 #include <limits.h>
19 #include "shimpriv.h"
20
21 //---------------------------------------------------------------------------------------
22 // Need virtual dtor since this is a base class.
23 // Derived classes will do real work
24 //---------------------------------------------------------------------------------------
25 ManagedEvent::~ManagedEvent()
26 {
27 }
28
29 #ifdef _DEBUG
30 //---------------------------------------------------------------------------------------
31 // For debugging, get a pointer value that can identify the type of this event.
32 // 
33 // Returns:
34 //    persistent pointer value that can be used as cookie to identify this event type.
35 //---------------------------------------------------------------------------------------
36 void * ManagedEvent::GetDebugCookie()
37 {
38     // Return vtable, first void* in the structure.
39     return *(reinterpret_cast<void**> (this));
40 }
41 #endif
42
43 //---------------------------------------------------------------------------------------
44 // Ctor for DispatchArgs
45 // 
46 // Arguments:
47 //    pCallback1 - 1st callback, for debug events in V1.0, V1.1
48 //    pCallback2 - 2nd callback, for debug events added in V2
49 //
50 // Notes:
51 //    We'll have a lot of derived classes of ManagedEvent, and so encapsulating the arguments
52 //    for the Dispatch() function lets us juggle them around easily without hitting every signature.
53 //---------------------------------------------------------------------------------------
54 ManagedEvent::DispatchArgs::DispatchArgs(ICorDebugManagedCallback * pCallback1, ICorDebugManagedCallback2 * pCallback2, ICorDebugManagedCallback3 * pCallback3)
55 {
56     m_pCallback1 = pCallback1;
57     m_pCallback2 = pCallback2;
58     m_pCallback3 = pCallback3;
59 }
60
61
62 // trivial accessor to get Callback 1
63 ICorDebugManagedCallback * ManagedEvent::DispatchArgs::GetCallback1()
64 {
65     return m_pCallback1;
66 }
67
68 // trivial accessor to get callback 2
69 ICorDebugManagedCallback2 * ManagedEvent::DispatchArgs::GetCallback2()
70 {
71     return m_pCallback2;
72 }
73
74 // trivial accessor to get callback 3
75 ICorDebugManagedCallback3 * ManagedEvent::DispatchArgs::GetCallback3()
76 {
77     return m_pCallback3;
78 }
79
80 // Returns OS Thread Id that this event occurred on, 0 if no thread affinity.
81 DWORD ManagedEvent::GetOSTid()
82 {
83     return m_dwThreadId;
84 }
85
86 //---------------------------------------------------------------------------------------
87 // Constructore for events with thread affinity
88 // 
89 // Arguments:
90 //     pThread -  thread that this event is associated with. 
91 //
92 // Notes:
93 //     Thread affinity is used with code:ManagedEventQueue::HasQueuedCallbacks
94 //     This includes event callbacks that have a thread parameter
95 //---------------------------------------------------------------------------------------
96 ManagedEvent::ManagedEvent(ICorDebugThread * pThread)
97 {
98     m_dwThreadId = 0;
99     if (pThread != NULL)
100     {
101         pThread->GetID(&m_dwThreadId);
102     }        
103     
104     m_pNext = NULL;
105 }
106
107 //---------------------------------------------------------------------------------------
108 // Constructor for events with no thread affinity
109 //---------------------------------------------------------------------------------------
110 ManagedEvent::ManagedEvent()
111 {
112     m_dwThreadId = 0;
113     m_pNext = NULL;
114 }
115
116     
117
118
119
120
121 // Ctor
122 ManagedEventQueue::ManagedEventQueue()
123 {
124     m_pFirstEvent = NULL;
125     m_pLastEvent = NULL;
126     m_pLock = NULL;
127 }
128
129 //---------------------------------------------------------------------------------------
130 // Initialize
131 //
132 // Arguments:
133 //    pLock - lock that protects this event queue. This takes a weak ref to the lock,
134 //            so caller ensures lock stays alive for lifespan of this object
135 // 
136 // Notes:
137 //    Event queue locks itself using this lock.
138 //    Only call this once. 
139 //---------------------------------------------------------------------------------------
140 void ManagedEventQueue::Init(RSLock * pLock)
141 {
142     _ASSERTE(m_pLock == NULL);
143     m_pLock = pLock;
144 }
145
146 //---------------------------------------------------------------------------------------    
147 // Remove event from the top. 
148 //
149 // Returns: 
150 //    Event that was just dequeued. 
151 //
152 // Notes:
153 //    Caller then takes ownership of Event and will call Delete on it.
154 //    If IsEmpty() function returns NULL.
155 //    
156 //    It is an error to call Dequeue when the only elements in the queue are suspended.
157 //    Suspending the queue implies there are going to be new events added which should come before
158 //    the elements that are suspended.  Trying to deqeue when there are only suspended elements
159 //    left is error-prone - if it were allowed, the order may be non-deterministic.
160 //    In practice we could probably ban calling Dequeue at all when any elements are suspended,
161 //    but this seems overly restrictive - there is nothing wrong with allowing these "new"
162 //    events to be dequeued since we know they come first (you can't nest suspensions).
163 //---------------------------------------------------------------------------------------
164 ManagedEvent * ManagedEventQueue::Dequeue()
165 {
166     RSLockHolder lockHolder(m_pLock);
167     if (m_pFirstEvent == NULL)
168     {
169         return NULL;
170     }
171     
172     ManagedEvent * pEvent = m_pFirstEvent;
173     m_pFirstEvent = m_pFirstEvent->m_pNext;
174     if (m_pFirstEvent == NULL)
175     {
176         m_pLastEvent = NULL;
177     }
178
179     pEvent->m_pNext = NULL;
180     return pEvent;
181 }
182
183 //---------------------------------------------------------------------------------------
184 // Append the event to the end of the queue.
185 // Queue owns the event and will delete it (unless it's dequeued first).
186 // 
187 // Note that this can be called when a suspended queue is active.  Events are pushed onto 
188 // the currently active queue (ahead of the suspended queue).
189 //
190 // Arguments:
191 //     pEvent - event to queue.
192 //
193 //---------------------------------------------------------------------------------------
194 void ManagedEventQueue::QueueEvent(ManagedEvent * pEvent)
195 {
196     RSLockHolder lockHolder(m_pLock);
197     _ASSERTE(pEvent != NULL);
198     _ASSERTE(pEvent->m_pNext == NULL);
199     
200     if (m_pLastEvent == NULL)
201     {
202         _ASSERTE(m_pFirstEvent == NULL);
203         m_pFirstEvent = m_pLastEvent = pEvent;
204     }
205     else
206     {
207         m_pLastEvent->m_pNext = pEvent;
208         m_pLastEvent = pEvent;
209     }
210 }
211
212
213 //---------------------------------------------------------------------------------------
214 // Returns true iff the event queue is empty (including any suspended queue elements)
215 //---------------------------------------------------------------------------------------
216 bool ManagedEventQueue::IsEmpty()
217 {
218     RSLockHolder lockHolder(m_pLock);
219     if (m_pFirstEvent != NULL)
220     {
221         _ASSERTE(m_pLastEvent != NULL);
222         return false;
223     }
224
225     _ASSERTE(m_pLastEvent == NULL);
226     return true;
227 }
228
229
230 //---------------------------------------------------------------------------------------
231 // Delete all events and empty the queue (including any suspended queue elements)
232 //
233 // Notes:
234 //    This is like calling { while(!IsEmpty()) delete Dequeue(); }
235 //---------------------------------------------------------------------------------------
236 void ManagedEventQueue::DeleteAll()
237 {
238     RSLockHolder lockHolder(m_pLock);
239
240     while (m_pFirstEvent != NULL)
241     {
242         // verify that the last event in the queue is actually the one stored as the last event
243         _ASSERTE( m_pFirstEvent->m_pNext != NULL || m_pFirstEvent == m_pLastEvent );
244
245         ManagedEvent * pNext = m_pFirstEvent->m_pNext;
246         delete m_pFirstEvent;
247         m_pFirstEvent = pNext;
248     }
249     m_pLastEvent = NULL;
250
251     _ASSERTE(IsEmpty());
252 };
253
254 //---------------------------------------------------------------------------------------
255 // Worker to implement ICorDebugProcess::HasQueuedCallbacks for shim
256 //---------------------------------------------------------------------------------------
257 BOOL ManagedEventQueue::HasQueuedCallbacks(ICorDebugThread * pThread)
258 {
259     // This is from the public paths of ICorDebugProcess::HasQueuedCallbacks.
260     // In V2, this would fail in cases, notably including if the process is not synchronized.
261     // In arrowhead, it always succeeds.
262
263     // No thread - look process wide.
264     if (pThread == NULL)
265     {
266         return !IsEmpty();
267     }
268
269     // If we have a thread, look for events with thread affinity.
270     DWORD dwThreadID = 0;
271     HRESULT hr = pThread->GetID(&dwThreadID);
272     (void)hr; //prevent "unused variable" error from GCC
273     SIMPLIFYING_ASSUMPTION(SUCCEEDED(hr));
274
275     // Don't take lock until after we don't call any ICorDebug APIs.
276     RSLockHolder lockHolder(m_pLock);
277
278     ManagedEvent * pCurrent = m_pFirstEvent;
279     while (pCurrent != NULL)
280     {
281         if (pCurrent->GetOSTid() == dwThreadID)
282         {
283             return true;
284         }
285         pCurrent = pCurrent->m_pNext;
286     }
287     return false;
288 }
289
290
291
292