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
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 //*****************************************************************************
21 //---------------------------------------------------------------------------------------
22 // Need virtual dtor since this is a base class.
23 // Derived classes will do real work
24 //---------------------------------------------------------------------------------------
25 ManagedEvent::~ManagedEvent()
30 //---------------------------------------------------------------------------------------
31 // For debugging, get a pointer value that can identify the type of this event.
34 // persistent pointer value that can be used as cookie to identify this event type.
35 //---------------------------------------------------------------------------------------
36 void * ManagedEvent::GetDebugCookie()
38 // Return vtable, first void* in the structure.
39 return *(reinterpret_cast<void**> (this));
43 //---------------------------------------------------------------------------------------
44 // Ctor for DispatchArgs
47 // pCallback1 - 1st callback, for debug events in V1.0, V1.1
48 // pCallback2 - 2nd callback, for debug events added in V2
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)
56 m_pCallback1 = pCallback1;
57 m_pCallback2 = pCallback2;
58 m_pCallback3 = pCallback3;
62 // trivial accessor to get Callback 1
63 ICorDebugManagedCallback * ManagedEvent::DispatchArgs::GetCallback1()
68 // trivial accessor to get callback 2
69 ICorDebugManagedCallback2 * ManagedEvent::DispatchArgs::GetCallback2()
74 // trivial accessor to get callback 3
75 ICorDebugManagedCallback3 * ManagedEvent::DispatchArgs::GetCallback3()
80 // Returns OS Thread Id that this event occurred on, 0 if no thread affinity.
81 DWORD ManagedEvent::GetOSTid()
86 //---------------------------------------------------------------------------------------
87 // Constructore for events with thread affinity
90 // pThread - thread that this event is associated with.
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)
101 pThread->GetID(&m_dwThreadId);
107 //---------------------------------------------------------------------------------------
108 // Constructor for events with no thread affinity
109 //---------------------------------------------------------------------------------------
110 ManagedEvent::ManagedEvent()
122 ManagedEventQueue::ManagedEventQueue()
124 m_pFirstEvent = NULL;
129 //---------------------------------------------------------------------------------------
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
137 // Event queue locks itself using this lock.
138 // Only call this once.
139 //---------------------------------------------------------------------------------------
140 void ManagedEventQueue::Init(RSLock * pLock)
142 _ASSERTE(m_pLock == NULL);
146 //---------------------------------------------------------------------------------------
147 // Remove event from the top.
150 // Event that was just dequeued.
153 // Caller then takes ownership of Event and will call Delete on it.
154 // If IsEmpty() function returns NULL.
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()
166 RSLockHolder lockHolder(m_pLock);
167 if (m_pFirstEvent == NULL)
172 ManagedEvent * pEvent = m_pFirstEvent;
173 m_pFirstEvent = m_pFirstEvent->m_pNext;
174 if (m_pFirstEvent == NULL)
179 pEvent->m_pNext = NULL;
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).
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).
191 // pEvent - event to queue.
193 //---------------------------------------------------------------------------------------
194 void ManagedEventQueue::QueueEvent(ManagedEvent * pEvent)
196 RSLockHolder lockHolder(m_pLock);
197 _ASSERTE(pEvent != NULL);
198 _ASSERTE(pEvent->m_pNext == NULL);
200 if (m_pLastEvent == NULL)
202 _ASSERTE(m_pFirstEvent == NULL);
203 m_pFirstEvent = m_pLastEvent = pEvent;
207 m_pLastEvent->m_pNext = pEvent;
208 m_pLastEvent = pEvent;
213 //---------------------------------------------------------------------------------------
214 // Returns true iff the event queue is empty (including any suspended queue elements)
215 //---------------------------------------------------------------------------------------
216 bool ManagedEventQueue::IsEmpty()
218 RSLockHolder lockHolder(m_pLock);
219 if (m_pFirstEvent != NULL)
221 _ASSERTE(m_pLastEvent != NULL);
225 _ASSERTE(m_pLastEvent == NULL);
230 //---------------------------------------------------------------------------------------
231 // Delete all events and empty the queue (including any suspended queue elements)
234 // This is like calling { while(!IsEmpty()) delete Dequeue(); }
235 //---------------------------------------------------------------------------------------
236 void ManagedEventQueue::DeleteAll()
238 RSLockHolder lockHolder(m_pLock);
240 while (m_pFirstEvent != NULL)
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 );
245 ManagedEvent * pNext = m_pFirstEvent->m_pNext;
246 delete m_pFirstEvent;
247 m_pFirstEvent = pNext;
254 //---------------------------------------------------------------------------------------
255 // Worker to implement ICorDebugProcess::HasQueuedCallbacks for shim
256 //---------------------------------------------------------------------------------------
257 BOOL ManagedEventQueue::HasQueuedCallbacks(ICorDebugThread * pThread)
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.
263 // No thread - look process wide.
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));
275 // Don't take lock until after we don't call any ICorDebug APIs.
276 RSLockHolder lockHolder(m_pLock);
278 ManagedEvent * pCurrent = m_pFirstEvent;
279 while (pCurrent != NULL)
281 if (pCurrent->GetOSTid() == dwThreadID)
285 pCurrent = pCurrent->m_pNext;