127 |
155 |
128 // Return the action associated with this event |
156 // Return the action associated with this event |
129 return iEventActions[aEvent]; |
157 return iEventActions[aEvent]; |
130 } |
158 } |
131 |
159 |
132 // Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo |
160 /** Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo |
133 // If there is no event in the queue for this process+agent combination, store the details |
161 * If there is no event in the queue for this process+agent combination, store the details |
134 // so that it can be notified later when an event actually occurs. |
162 * so that it can be notified later when an event actually occurs. |
135 // |
163 * |
136 // @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory |
164 * @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory |
137 // @param aEventInfo - Address of TEventInfo structure to place event data when available |
165 * @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS. |
138 // @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS. |
166 */ |
139 void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, TEventInfo* aEventInfo, DThread* aClientThread) |
167 void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, DThread* aClientThread) |
140 { |
168 { |
|
169 LockEventQueue(); |
|
170 |
|
171 iRequestGetEventStatus->Reset(); |
|
172 TInt err = iRequestGetEventStatus->SetStatus( aAsyncGetValueRequest->StatusPtr() ); |
|
173 if (err != KErrNone) |
|
174 { |
|
175 LOG_MSG2("Error :iRequestGetEventStatus->SetStatus ret %d", err); |
|
176 return; |
|
177 } |
|
178 |
|
179 iRequestGetEventStatus->SetDestPtr( aAsyncGetValueRequest->DestPtr() ); |
|
180 |
|
181 iEventBalance++; |
|
182 |
|
183 LOG_MSG4("DDebugAgent::GetEvent: this=0x%08x, iRequestGetEventStatus=0x%08x, iEventBalance=%d", |
|
184 this, iRequestGetEventStatus, iEventBalance ); |
|
185 |
141 iClientThread = aClientThread; |
186 iClientThread = aClientThread; |
142 |
187 |
143 if (BufferEmpty()) |
188 if (BufferEmpty()) |
144 { |
189 { |
145 LOG_MSG("no events available"); |
190 LOG_MSG2("Event buffer empty, iEventBalance=%d", iEventBalance); |
146 |
191 UnlockEventQueue(); |
147 // store the pointer so we can modify it later |
|
148 iEventInfo = (TEventInfo *)aEventInfo; |
|
149 iRequestGetEventStatus = aAsyncGetValueRequest; |
|
150 return; |
192 return; |
151 } |
193 } |
152 |
194 |
153 LOG_MSG("Event available"); |
195 LOG_MSG2("Event already available at queue pos=%d", iTail); |
154 |
196 |
155 // returning the event to the client |
197 // returning the event to the client |
156 TInt err = iEventQueue[iTail].WriteEventToClientThread(aAsyncGetValueRequest,iClientThread); |
198 err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread); |
157 if (KErrNone != err) |
199 if (err != KErrNone) |
158 { |
200 { |
159 LOG_MSG2("Error writing event info: %d", err); |
201 LOG_MSG2("Error writing event info: %d", err); |
|
202 UnlockEventQueue(); |
160 return; |
203 return; |
161 } |
204 } |
162 |
205 |
163 // signal the DSS thread |
206 // signal the DSS thread |
164 Kern::QueueRequestComplete(iClientThread, aAsyncGetValueRequest, KErrNone); |
207 Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone); |
|
208 iEventBalance--; |
165 |
209 |
166 iEventQueue[iTail].Reset(); |
210 iEventQueue[iTail].Reset(); |
167 |
211 |
168 // move to the next slot |
212 // move to the next slot |
169 IncrementPosition(iTail); |
213 IncrementTailPosition(); |
170 } |
214 |
171 |
215 UnlockEventQueue(); |
172 // Stop waiting for an event to occur. This means events will be placed in the iEventQueue |
216 } |
173 // until GetEvent is called. |
217 |
|
218 /** |
|
219 * Stop waiting for an event to occur. This means events will be placed |
|
220 * in the iEventQueue (by setting iEventBalance to 0) until GetEvent is called. |
|
221 */ |
174 TInt DDebugAgent::CancelGetEvent(void) |
222 TInt DDebugAgent::CancelGetEvent(void) |
175 { |
223 { |
|
224 LOG_MSG2("DDebugAgent::CancelGetEvent. iEventBalance=%d. > QueueRequestComplete", iEventBalance); |
176 Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel); |
225 Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel); |
177 iEventInfo = NULL; |
226 iEventBalance=0; |
178 iRequestGetEventStatus = 0; |
|
179 iClientThread = 0; |
227 iClientThread = 0; |
180 |
|
181 return KErrNone; |
228 return KErrNone; |
182 } |
229 } |
183 |
230 |
184 // Signal a kernel event to the user-side DSS when it occurs, or queue it for later |
231 /** Signal a kernel event to the user-side DSS when it occurs, or queue it for later |
185 // if the user-side has not called GetEvent (see above). |
232 * if the user-side has not called GetEvent (see above). |
186 // |
233 * |
187 // @param aEventInfo - the details of the event to queue. |
234 * @param aEventInfo - the details of the event to queue. |
|
235 */ |
188 void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo) |
236 void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo) |
189 { |
237 { |
190 LOG_MSG("DDebugAgent::NotifyEvent()"); |
|
191 // Action depends on the TKernelEvent type in aEventInfo.iType |
|
192 |
|
193 // Added to fix the pass by value issue seen in Coverity. |
|
194 // Function is changed to pass by reference but temp object is explicitly created. |
|
195 TDriverEventInfo eventInfo = aEventInfo; |
|
196 |
238 |
197 if(aEventInfo.iEventType >= EEventsLast) |
239 if(aEventInfo.iEventType >= EEventsLast) |
198 { |
240 { |
199 // unknown event type so return |
241 LOG_MSG3("DDebugAgent::NotifyEvent(),iEventType %d, this=0x%x. Ignoring since > EEventsLast", aEventInfo.iEventType, this); |
200 return; |
242 return; |
201 } |
243 } |
202 |
244 |
203 TKernelEventAction action = iEventActions[eventInfo.iEventType]; |
245 LockEventQueue(); |
|
246 |
|
247 DThread* currentThread = &Kern::CurrentThread(); |
|
248 |
|
249 LOG_MSG5("DDebugAgent::NotifyEvent(), iEventType %d, this=0x%x currThrd=0x%08x, iEventBalance=%d", |
|
250 aEventInfo.iEventType, this, currentThread, iEventBalance ); |
|
251 TKernelEventAction action = iEventActions[aEventInfo.iEventType]; |
204 |
252 |
205 switch (action) |
253 switch (action) |
206 { |
254 { |
207 case EActionSuspend: |
255 case EActionSuspend: |
208 { |
256 { |
209 LOG_MSG("DDebugAgent::NotifyEvent() Suspend thread"); |
257 LOG_MSG("DDebugAgent::NotifyEvent() Suspend thread"); |
210 DThread* currentThread = &Kern::CurrentThread(); |
258 |
211 switch(eventInfo.iEventType) |
259 switch(aEventInfo.iEventType) |
212 { |
260 { |
213 case EEventsAddLibrary: |
261 case EEventsAddLibrary: |
214 case EEventsRemoveLibrary: |
262 case EEventsRemoveLibrary: |
215 currentThread = DebugUtils::OpenThreadHandle(eventInfo.iThreadId); |
263 currentThread = DebugUtils::OpenThreadHandle(aEventInfo.iThreadId); |
216 if(currentThread) |
264 if(currentThread) |
217 { |
265 { |
218 currentThread->Close(NULL); |
266 currentThread->Close(NULL); |
219 } |
267 } |
220 break; |
268 break; |
221 default: |
269 default: |
222 break; |
270 break; |
223 } |
271 } |
224 TInt err = TheDProcessTracker.SuspendThread(currentThread, eventInfo.FreezeOnSuspend()); |
272 TInt err = TheDProcessTracker.SuspendThread(currentThread, aEventInfo.FreezeOnSuspend()); |
225 if(!( (err == KErrNone) || (err == KErrAlreadyExists) )) |
273 if((err != KErrNone) && (err != KErrAlreadyExists)) |
226 { |
274 { |
227 // Is there anything we can do in the future to deal with this error having happened? |
275 // Is there anything we can do in the future to deal with this error having happened? |
228 LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err); |
276 LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err); |
229 } |
277 } |
230 |
278 |
231 // now drop through to the continue case, which typically notifies |
279 // now drop through to the continue case, which typically notifies |
232 // the debug agent of the event |
280 // the debug agent of the event |
233 } |
281 } |
234 case EActionContinue: |
282 case EActionContinue: |
235 LOG_MSG("DDebugAgent::NotifyEvent() Continue"); |
|
236 |
|
237 // Tell the user about this event |
|
238 if (iEventInfo && iClientThread) |
|
239 { |
283 { |
240 LOG_MSG("Completing event\r\n"); |
284 // Queue this event |
241 |
285 QueueEvent(aEventInfo); |
242 // returning the event to the client |
286 |
243 TInt err = eventInfo.WriteEventToClientThread(iRequestGetEventStatus,iClientThread); |
287 // Tell the user about the oldest event in the queue |
244 if (KErrNone != err) |
288 if ( iClientThread ) |
245 { |
289 { |
246 LOG_MSG2("Error writing event info: %d", err); |
290 if( iRequestGetEventStatus && (iEventBalance > 0) ) |
247 } |
291 { |
248 |
292 // Fill the event data |
249 // clear this since we've completed the request |
293 TInt err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread); |
250 iEventInfo = NULL; |
294 if (err != KErrNone) |
251 |
295 { |
252 // signal the debugger thread |
296 LOG_MSG2("Error writing event info: %d", err); |
253 Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone); |
297 } |
|
298 |
|
299 // signal the debugger thread |
|
300 LOG_MSG4("> QueueRequestComplete iRequestGetEventStatus=0x%08x, iEventBalance=%d, iTail=%d", |
|
301 iRequestGetEventStatus->iStatus, iEventBalance, iTail ); |
|
302 Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone); |
|
303 |
|
304 iEventBalance--; |
|
305 |
|
306 iEventQueue[iTail].Reset(); |
|
307 |
|
308 // move to the next slot |
|
309 IncrementTailPosition(); |
|
310 } |
|
311 else |
|
312 { |
|
313 if( !iRequestGetEventStatus ) |
|
314 { |
|
315 LOG_MSG("iRequestGetEventStatus is NULL so not signalling client" ); |
|
316 } |
|
317 else |
|
318 { |
|
319 LOG_MSG2("Queued event. iEventBalance=%d (unbalanced event requests vs notifications)", |
|
320 iEventBalance ); |
|
321 } |
|
322 } |
|
323 } |
|
324 else |
|
325 { |
|
326 LOG_MSG("DDebugAgent::NotifyEvent() : Not informing client since its thread is NULL"); |
|
327 } |
|
328 break; |
254 } |
329 } |
255 else |
|
256 { |
|
257 LOG_MSG("Queuing event\r\n"); |
|
258 |
|
259 QueueEvent(eventInfo); |
|
260 |
|
261 } |
|
262 break; |
|
263 |
|
264 case EActionIgnore: |
330 case EActionIgnore: |
265 default: |
331 default: |
266 LOG_MSG("DDebugAgent::NotifyEvent() fallen through to default case"); |
332 LOG_EVENT_MSG("DDebugAgent::NotifyEvent() fallen through to default case"); |
267 // Ignore everything we don't understand. |
333 // Ignore everything we don't understand. |
268 return; |
334 |
269 } |
335 } |
|
336 |
|
337 UnlockEventQueue(); |
270 |
338 |
271 } |
339 } |
272 |
340 |
273 // Used to identify which Debug Agent this DDebugAgent is associated with. |
341 // Used to identify which Debug Agent this DDebugAgent is associated with. |
274 TUint64 DDebugAgent::Id(void) |
342 TUint64 DDebugAgent::Id(void) |
275 { |
343 { |
276 return iId; |
344 return iId; |
277 } |
345 } |
278 |
346 |
279 // Used to add an event to the event queue for this debug agent |
347 /** |
280 void DDebugAgent::QueueEvent(TDriverEventInfo& aEventInfo) |
348 * Used to add an event to the event queue for this debug agent if event |
|
349 * queue is not at critical level. If it is at critical and it is trace event, |
|
350 * we start ignoring trace events and insert a lost trace event. |
|
351 * If the buffer cannot store an event, only insert a buffer full event. |
|
352 * @see EEventsBufferFull |
|
353 * @see EEventsUserTracesLost |
|
354 * @see TDriverEventInfo |
|
355 * @see iEventQueue |
|
356 */ |
|
357 void DDebugAgent::QueueEvent(const TDriverEventInfo& aEventInfo) |
281 { |
358 { |
282 // Have we caught the tail? |
359 // Have we caught the tail? |
283 if(BufferFull()) |
360 if(BufferFull()) |
284 { |
361 { |
|
362 LOG_MSG("DDebugAgent::QueueEvent : BufferFull. Not queueing"); |
285 return; |
363 return; |
286 } |
364 } |
287 |
365 |
288 //check to see if we wish to ignore this event - we dump trace events as they are lower priority than the other events |
366 // Assert if we think there is space but the slot is not marked empty |
289 if(BufferAtCriticalLevel()) |
367 __NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown); |
290 { |
368 |
|
369 const TBool bufferAtCritical = BufferAtCriticalLevel(); |
|
370 |
|
371 if(!bufferAtCritical) |
|
372 { |
|
373 //reset the iIgnoringTrace flag as we are not at |
|
374 //critical level and can store event |
|
375 iIgnoringTrace = EFalse; |
|
376 |
|
377 // Insert the event into the ring buffer at iHead |
|
378 iEventQueue[iHead] = aEventInfo; |
|
379 IncrementHeadPosition(); |
|
380 } |
|
381 else if(bufferAtCritical && BufferCanStoreEvent()) |
|
382 { |
|
383 LOG_MSG("DDebugAgent::QueueEvent : BufferCritical"); |
291 if(aEventInfo.iEventType == EEventsUserTrace) |
384 if(aEventInfo.iEventType == EEventsUserTrace) |
292 { |
385 { |
293 if(!iIgnoringTrace) |
386 if(!iIgnoringTrace) |
294 { |
387 { |
295 //if this is the first time we are ignoring trace events, we need to issue a EEventsUserTracesLost event |
388 //if this is the first time we are ignoring trace events, |
296 aEventInfo.Reset(); |
389 //we need to issue a EEventsUserTracesLost event |
297 aEventInfo.iEventType = EEventsUserTracesLost; |
390 iEventQueue[iHead].Reset(); |
298 |
391 iEventQueue[iHead].iEventType = EEventsUserTracesLost; |
|
392 IncrementHeadPosition(); |
|
393 |
299 iIgnoringTrace = ETrue; |
394 iIgnoringTrace = ETrue; |
300 } |
395 } |
301 else |
396 else |
302 { |
397 { |
303 //otherwise, ignore this event |
398 //otherwise, ignore this event |
304 return; |
399 LOG_MSG("DDebugAgent::QueueEvent : Ignore EEventsUserTrace event"); |
305 } |
400 } |
306 } |
401 } |
|
402 else |
|
403 { |
|
404 // Store the event since its not a trace event |
|
405 iEventQueue[iHead] = aEventInfo; |
|
406 IncrementHeadPosition(); |
|
407 } |
307 } |
408 } |
308 else |
409 else |
309 { |
410 { |
310 //reset the iIgnoringTrace flag as we are not at critical level |
411 //At critical level and cannot store new events, so |
311 iIgnoringTrace = EFalse; |
412 //only one space left. Store a EEventsBufferFull event |
312 } |
413 LOG_MSG("DDebugAgent::QueueEvent : Event Buffer Full, ignoring event"); |
313 |
414 iEventQueue[iHead].Reset(); |
314 // only one space left so store a EEventsBufferFull event |
415 iEventQueue[iHead].iEventType = EEventsBufferFull; |
315 if(!BufferCanStoreEvent()) |
416 IncrementHeadPosition(); |
316 { |
417 } |
317 aEventInfo.Reset(); |
418 } |
318 aEventInfo.iEventType = EEventsBufferFull; |
419 |
319 } |
420 // End of file - d_debug_agent.cpp |
320 |
|
321 __NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown); // we think there is space but the slot is not marked empty |
|
322 |
|
323 // Insert the event into the ring buffer at iHead |
|
324 iEventQueue[iHead] = aEventInfo; |
|
325 IncrementPosition(iHead); |
|
326 } |
|
327 |
|
328 // Checks whether the event queue is empty |
|
329 TBool DDebugAgent::BufferEmpty() const |
|
330 { |
|
331 return (NumberOfEmptySlots() == NUMBER_OF_EVENTS_TO_QUEUE); |
|
332 } |
|
333 |
|
334 // Checks whether the event queue is full |
|
335 TBool DDebugAgent::BufferFull() const |
|
336 { |
|
337 return (NumberOfEmptySlots() == 0); |
|
338 } |
|
339 |
|
340 // Checks whether there is room in the event queue to store an event (i.e. at least two free slots) |
|
341 TBool DDebugAgent::BufferCanStoreEvent() const |
|
342 { |
|
343 return (NumberOfEmptySlots() > 1); |
|
344 } |
|
345 |
|
346 //This looks to see if the buffer is close to being full and should only accept higher priority debug events (user trace is the only low priority event) |
|
347 TBool DDebugAgent::BufferAtCriticalLevel() const |
|
348 { |
|
349 return (NumberOfEmptySlots() < NUMBER_OF_EVENTS_TO_QUEUE - CRITICAL_BUFFER_SIZE); |
|
350 } |
|
351 |
|
352 // increments aPosition, wrapping at NUMBER_OF_EVENTS_TO_QUEUE if necessary |
|
353 void DDebugAgent::IncrementPosition(TInt& aPosition) |
|
354 { |
|
355 aPosition = (aPosition + 1) % NUMBER_OF_EVENTS_TO_QUEUE; |
|
356 } |
|
357 |
|
358 // finds the number of empty slots in the event queue |
|
359 TInt DDebugAgent::NumberOfEmptySlots() const |
|
360 { |
|
361 if(iHead < iTail) |
|
362 { |
|
363 return (iTail - iHead) - 1; |
|
364 } |
|
365 // iHead >= iTail |
|
366 return NUMBER_OF_EVENTS_TO_QUEUE - (iHead - iTail); |
|
367 } |
|
368 |
|