Update contrib.
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // Purpose: Kernel-side tracking of debug agent information associated
15 // with each process being debugged.
20 #include <e32def_private.h>
22 #include <e32cmn_private.h>
23 #include <kernel/kernel.h>
24 #include <kernel/kern_priv.h>
28 #include "d_process_tracker.h"
29 #include "debug_logging.h"
31 #include "d_debug_agent.h"
32 #include "debug_utils.h"
34 using namespace Debug;
36 #define NUMBER_OF_EVENTS_TO_QUEUE 100
37 #define CRITICAL_BUFFER_SIZE (NUMBER_OF_EVENTS_TO_QUEUE - 50)
40 DDebugAgent::DDebugAgent(TUint64 aId)
43 iEventQueue(NUMBER_OF_EVENTS_TO_QUEUE, 0),
44 iRequestGetEventStatus(NULL),
48 iIgnoringTrace(EFalse)
50 LOG_MSG("DDebugAgent::DDebugAgent() ");
52 // Initialize all the Event Actions to Ignore
53 for(TInt i=0; i<EEventsLast; i++)
55 iEventActions[i] = EActionIgnore;
59 DDebugAgent* DDebugAgent::New(TUint64 aId)
61 LOG_MSG("DDebugAgent::New()");
62 DDebugAgent* agent = new DDebugAgent(aId);
67 if(KErrNone != agent->Construct())
75 TInt DDebugAgent::Construct()
77 // Empty the event queue
78 LOG_MSG("DDebugAgent::Construct()");
79 TDriverEventInfo emptyEvent;
81 for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++)
83 TInt err = iEventQueue.Append(emptyEvent);
86 LOG_MSG("Error appending blank event entry");
95 DDebugAgent::~DDebugAgent()
100 // Associate an action with a particular kernel event
101 TInt DDebugAgent::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction)
104 if (aEvent >= EEventsLast)
106 LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
110 iEventActions[aEvent] = aEventAction;
115 /* Get the aEventAction associated with aEvent
117 * Returns : aEventAction (always +ve), or KErrArgument.
119 TInt DDebugAgent::EventAction(TEventType aEvent)
121 // Validate the Event id
122 if (aEvent >= EEventsLast)
124 LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
128 // Return the action associated with this event
129 return iEventActions[aEvent];
132 // 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
134 // so that it can be notified later when an event actually occurs.
136 // @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory
137 // @param aEventInfo - Address of TEventInfo structure to place event data when available
138 // @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS.
139 void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, TEventInfo* aEventInfo, DThread* aClientThread)
141 iClientThread = aClientThread;
145 LOG_MSG("no events available");
147 // store the pointer so we can modify it later
148 iEventInfo = (TEventInfo *)aEventInfo;
149 iRequestGetEventStatus = aAsyncGetValueRequest;
153 LOG_MSG("Event available");
155 // returning the event to the client
156 TInt err = iEventQueue[iTail].WriteEventToClientThread(aAsyncGetValueRequest,iClientThread);
159 LOG_MSG2("Error writing event info: %d", err);
163 // signal the DSS thread
164 Kern::QueueRequestComplete(iClientThread, aAsyncGetValueRequest, KErrNone);
166 iEventQueue[iTail].Reset();
168 // move to the next slot
169 IncrementPosition(iTail);
172 // Stop waiting for an event to occur. This means events will be placed in the iEventQueue
173 // until GetEvent is called.
174 TInt DDebugAgent::CancelGetEvent(void)
176 Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel);
178 iRequestGetEventStatus = 0;
184 // 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).
187 // @param aEventInfo - the details of the event to queue.
188 void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo)
190 LOG_MSG("DDebugAgent::NotifyEvent()");
191 // Action depends on the TKernelEvent type in aEventInfo.iType
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;
197 if(aEventInfo.iEventType >= EEventsLast)
199 // unknown event type so return
203 TKernelEventAction action = iEventActions[eventInfo.iEventType];
209 LOG_MSG("DDebugAgent::NotifyEvent() Suspend thread");
210 DThread* currentThread = &Kern::CurrentThread();
211 switch(eventInfo.iEventType)
213 case EEventsAddLibrary:
214 case EEventsRemoveLibrary:
215 currentThread = DebugUtils::OpenThreadHandle(eventInfo.iThreadId);
218 currentThread->Close(NULL);
224 TInt err = TheDProcessTracker.SuspendThread(currentThread, eventInfo.FreezeOnSuspend());
225 if(!( (err == KErrNone) || (err == KErrAlreadyExists) ))
227 // 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);
231 // now drop through to the continue case, which typically notifies
232 // the debug agent of the event
234 case EActionContinue:
235 LOG_MSG("DDebugAgent::NotifyEvent() Continue");
237 // Tell the user about this event
238 if (iEventInfo && iClientThread)
240 LOG_MSG("Completing event\r\n");
242 // returning the event to the client
243 TInt err = eventInfo.WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
246 LOG_MSG2("Error writing event info: %d", err);
249 // clear this since we've completed the request
252 // signal the debugger thread
253 Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
257 LOG_MSG("Queuing event\r\n");
259 QueueEvent(eventInfo);
266 LOG_MSG("DDebugAgent::NotifyEvent() fallen through to default case");
267 // Ignore everything we don't understand.
273 // Used to identify which Debug Agent this DDebugAgent is associated with.
274 TUint64 DDebugAgent::Id(void)
279 // Used to add an event to the event queue for this debug agent
280 void DDebugAgent::QueueEvent(TDriverEventInfo& aEventInfo)
282 // Have we caught the tail?
288 //check to see if we wish to ignore this event - we dump trace events as they are lower priority than the other events
289 if(BufferAtCriticalLevel())
291 if(aEventInfo.iEventType == EEventsUserTrace)
295 //if this is the first time we are ignoring trace events, we need to issue a EEventsUserTracesLost event
297 aEventInfo.iEventType = EEventsUserTracesLost;
299 iIgnoringTrace = ETrue;
303 //otherwise, ignore this event
310 //reset the iIgnoringTrace flag as we are not at critical level
311 iIgnoringTrace = EFalse;
314 // only one space left so store a EEventsBufferFull event
315 if(!BufferCanStoreEvent())
318 aEventInfo.iEventType = EEventsBufferFull;
321 __NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown); // we think there is space but the slot is not marked empty
323 // Insert the event into the ring buffer at iHead
324 iEventQueue[iHead] = aEventInfo;
325 IncrementPosition(iHead);
328 // Checks whether the event queue is empty
329 TBool DDebugAgent::BufferEmpty() const
331 return (NumberOfEmptySlots() == NUMBER_OF_EVENTS_TO_QUEUE);
334 // Checks whether the event queue is full
335 TBool DDebugAgent::BufferFull() const
337 return (NumberOfEmptySlots() == 0);
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
343 return (NumberOfEmptySlots() > 1);
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
349 return (NumberOfEmptySlots() < NUMBER_OF_EVENTS_TO_QUEUE - CRITICAL_BUFFER_SIZE);
352 // increments aPosition, wrapping at NUMBER_OF_EVENTS_TO_QUEUE if necessary
353 void DDebugAgent::IncrementPosition(TInt& aPosition)
355 aPosition = (aPosition + 1) % NUMBER_OF_EVENTS_TO_QUEUE;
358 // finds the number of empty slots in the event queue
359 TInt DDebugAgent::NumberOfEmptySlots() const
363 return (iTail - iHead) - 1;
366 return NUMBER_OF_EVENTS_TO_QUEUE - (iHead - iTail);