kernel/eka/drivers/debug/rmdebug/d_debug_agent.cpp
branchRCL_3
changeset 257 3e88ff8f41d5
child 258 880ff05ad710
equal deleted inserted replaced
256:c1f20ce4abcf 257:3e88ff8f41d5
       
     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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Purpose: Kernel-side tracking of debug agent information associated
       
    15 // with each process being debugged.
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <e32def.h>
       
    20 #include <e32def_private.h>
       
    21 #include <e32cmn.h>
       
    22 #include <e32cmn_private.h>
       
    23 #include <kernel/kernel.h> 
       
    24 #include <kernel/kern_priv.h>
       
    25 #include <nk_trace.h>
       
    26 #include <arm.h>
       
    27 
       
    28 #include "d_process_tracker.h"
       
    29 #include "debug_logging.h"
       
    30 
       
    31 #include "d_debug_agent.h"
       
    32 #include "debug_utils.h"
       
    33 
       
    34 #include "d_debug_agent.inl"
       
    35 
       
    36 using namespace Debug;
       
    37 
       
    38 // ctor
       
    39 DDebugAgent::DDebugAgent(TUint64 aId) :
       
    40 	iId(aId),
       
    41 	iRequestGetEventStatus(NULL),
       
    42 	iClientThread(0),
       
    43 	iEventQueue(KNumberOfEventsToQueue, 0),
       
    44 	iHead(0),
       
    45 	iTail(0),
       
    46 	iEventQueueLock(NULL),
       
    47 	iFreeSlots(KNumberOfEventsToQueue),
       
    48 	iIgnoringTrace(EFalse),
       
    49 	iEventBalance(0)
       
    50 	{
       
    51 	LOG_MSG2("DDebugAgent::DDebugAgent(), this=0x%x ", this);
       
    52 
       
    53 	// Initialize all the Event Actions to Ignore
       
    54 	for(TInt i=0; i<EEventsLast; i++)
       
    55 		{
       
    56 		iEventActions[i] = EActionIgnore;
       
    57 		}
       
    58 	}
       
    59 
       
    60 DDebugAgent* DDebugAgent::New(TUint64 aId)
       
    61 	{
       
    62 	LOG_MSG("DDebugAgent::New()");
       
    63 	DDebugAgent* agent = new DDebugAgent(aId);
       
    64 	if(agent == NULL)
       
    65 		{
       
    66 		return (NULL);
       
    67 		}
       
    68 	if(KErrNone != agent->Construct())
       
    69 		{
       
    70 		delete agent;
       
    71 		return (NULL);
       
    72 		}
       
    73 
       
    74 	// Use a semaphore to serialise access
       
    75 	TInt err = Kern::SemaphoreCreate(agent->iEventQueueLock, _L("RM_DebugAgentQueueLock"), 1 /* Initial count */);
       
    76 	if (err != KErrNone)
       
    77 		return NULL;
       
    78 
       
    79 	return agent;
       
    80 	}
       
    81 
       
    82 /** Standard contructor.
       
    83  * Fills event queue with empty events
       
    84  * @return : standard system error code
       
    85  */
       
    86 TInt DDebugAgent::Construct()
       
    87 	{
       
    88 	// Empty the event queue
       
    89 	LOG_MSG("DDebugAgent::Construct()");
       
    90 	TDriverEventInfo emptyEvent;
       
    91 	TInt err = KErrNone;
       
    92 
       
    93 	for (TInt i=0; i<KNumberOfEventsToQueue; i++)
       
    94 		{
       
    95 		err = iEventQueue.Append(emptyEvent);
       
    96 		if (err != KErrNone)
       
    97 			{
       
    98 			LOG_MSG("Error appending blank event entry");
       
    99 			return err;
       
   100 			}
       
   101 		}
       
   102 
       
   103 	err = Kern::CreateClientDataRequest(iRequestGetEventStatus);
       
   104 	if(err != KErrNone)
       
   105 		{
       
   106 		LOG_MSG("Error creating TClientDataRequest");
       
   107 		return err;
       
   108 		}
       
   109 
       
   110 	LOG_MSG2("DDebugAgent::Construct() iRequestGetEventStatus=0x%08x", iRequestGetEventStatus);
       
   111 
       
   112 	return err;
       
   113 	}
       
   114 
       
   115 // dtor
       
   116 DDebugAgent::~DDebugAgent()
       
   117 	{
       
   118 	iEventQueue.Reset();
       
   119 
       
   120 	if (iEventQueueLock)
       
   121 		iEventQueueLock->Close(NULL);
       
   122 	
       
   123 	if(iRequestGetEventStatus)
       
   124 		Kern::DestroyClientRequest(iRequestGetEventStatus);
       
   125 	
       
   126 	}
       
   127 
       
   128 // Associate an action with a particular kernel event
       
   129 TInt DDebugAgent::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction)
       
   130 	{
       
   131 	// Valid Event?
       
   132 	if (aEvent >= EEventsLast)
       
   133 		{
       
   134 		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
       
   135 		return KErrArgument;
       
   136 		}
       
   137 
       
   138 	iEventActions[aEvent] = aEventAction;
       
   139 
       
   140 	return KErrNone;
       
   141 	}
       
   142 
       
   143 /** Get the aEventAction associated with aEvent
       
   144  *
       
   145  * @return : aEventAction (always +ve), or KErrArgument.
       
   146  */
       
   147 TInt DDebugAgent::EventAction(TEventType aEvent)
       
   148 	{
       
   149 	// Validate the Event id
       
   150 	if (aEvent >= EEventsLast)
       
   151 		{
       
   152 		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
       
   153 		return KErrArgument;
       
   154 		}
       
   155 
       
   156 	// Return the action associated with this event
       
   157 	return iEventActions[aEvent];
       
   158 	}
       
   159 
       
   160 /** Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo
       
   161  * If there is no event in the queue for this process+agent combination, store the details
       
   162  * so that it can be notified later when an event actually occurs.
       
   163  * 
       
   164  * @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory
       
   165  * @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS.
       
   166  */
       
   167 void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, DThread* aClientThread)
       
   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 	
       
   186 	iClientThread = aClientThread;
       
   187 	
       
   188 	if (BufferEmpty())
       
   189 		{
       
   190 		LOG_MSG2("Event buffer empty, iEventBalance=%d", iEventBalance);		
       
   191 		UnlockEventQueue();
       
   192 		return;
       
   193 		}
       
   194 
       
   195 	LOG_MSG2("Event already available at queue pos=%d", iTail);
       
   196 
       
   197 	// returning the event to the client
       
   198 	err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
       
   199 	if (err != KErrNone)
       
   200 		{
       
   201 		LOG_MSG2("Error writing event info: %d", err);
       
   202 		UnlockEventQueue();
       
   203 		return;
       
   204 		}
       
   205 
       
   206 	// signal the DSS thread
       
   207 	Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
       
   208 	iEventBalance--;
       
   209 
       
   210 	iEventQueue[iTail].Reset();
       
   211 
       
   212 	// move to the next slot
       
   213 	IncrementTailPosition();
       
   214 
       
   215 	UnlockEventQueue();
       
   216 	}
       
   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  */ 
       
   222 TInt DDebugAgent::CancelGetEvent(void)
       
   223 	{
       
   224 	LOG_MSG2("DDebugAgent::CancelGetEvent. iEventBalance=%d. > QueueRequestComplete", iEventBalance);
       
   225 	Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel);
       
   226 	iEventBalance=0;
       
   227 	iClientThread = 0;
       
   228 	return KErrNone;
       
   229 	}
       
   230 
       
   231 /** Signal a kernel event to the user-side DSS when it occurs, or queue it for later
       
   232  * if the user-side has not called GetEvent (see above).
       
   233  * 
       
   234  * @param aEventInfo - the details of the event to queue.
       
   235  */
       
   236 void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo)
       
   237 	{
       
   238 
       
   239 	if(aEventInfo.iEventType >= EEventsLast)
       
   240 		{
       
   241 		LOG_MSG3("DDebugAgent::NotifyEvent(),iEventType %d, this=0x%x. Ignoring since > EEventsLast", aEventInfo.iEventType, this);
       
   242 		return;
       
   243 		}
       
   244 
       
   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];
       
   252 
       
   253 	switch (action)
       
   254 		{
       
   255 		case EActionSuspend:
       
   256 			{
       
   257 			LOG_MSG("DDebugAgent::NotifyEvent() Suspend thread");
       
   258 
       
   259 			switch(aEventInfo.iEventType)
       
   260 				{
       
   261 				case EEventsAddLibrary:
       
   262 				case EEventsRemoveLibrary:
       
   263 					currentThread = DebugUtils::OpenThreadHandle(aEventInfo.iThreadId);
       
   264 					if(currentThread)
       
   265 						{
       
   266 						currentThread->Close(NULL);
       
   267 						}
       
   268 					break;
       
   269 				default:
       
   270 					break;
       
   271 				}
       
   272 			TInt err = TheDProcessTracker.SuspendThread(currentThread, aEventInfo.FreezeOnSuspend());
       
   273 			if((err != KErrNone) && (err != KErrAlreadyExists))
       
   274 				{
       
   275 				// Is there anything we can do in the future to deal with this error having happened?
       
   276 				LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err);
       
   277 				}
       
   278 
       
   279 			// now drop through to the continue case, which typically notifies
       
   280 			// the debug agent of the event
       
   281 			}
       
   282 		case EActionContinue:
       
   283 			{
       
   284 			// Queue this event
       
   285 			QueueEvent(aEventInfo);
       
   286 
       
   287 			// Tell the user about the oldest event in the queue
       
   288 			if ( iClientThread )
       
   289 				{
       
   290 				if( iRequestGetEventStatus && (iEventBalance > 0) )
       
   291 					{
       
   292 					// Fill the event data
       
   293 					TInt err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
       
   294 					if (err != KErrNone)
       
   295 						{
       
   296 						LOG_MSG2("Error writing event info: %d", err);
       
   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;
       
   329 			}
       
   330 		case EActionIgnore:
       
   331 		default:
       
   332 			LOG_EVENT_MSG("DDebugAgent::NotifyEvent() fallen through to default case");
       
   333 			// Ignore everything we don't understand.
       
   334 
       
   335 		}
       
   336 
       
   337 	UnlockEventQueue();
       
   338 
       
   339 	}
       
   340 
       
   341 // Used to identify which Debug Agent this DDebugAgent is associated with.
       
   342 TUint64 DDebugAgent::Id(void)
       
   343 	{
       
   344 	return iId;
       
   345 	}
       
   346 
       
   347 /**
       
   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)
       
   358 	{
       
   359 	// Have we caught the tail?
       
   360 	if(BufferFull())
       
   361 		{
       
   362 		LOG_MSG("DDebugAgent::QueueEvent : BufferFull. Not queueing");
       
   363 		return;
       
   364 		}
       
   365 
       
   366 	// Assert if we think there is space but the slot is not marked empty
       
   367 	__NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown);
       
   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");
       
   384 		if(aEventInfo.iEventType == EEventsUserTrace)
       
   385 			{
       
   386 			if(!iIgnoringTrace)
       
   387 				{
       
   388 				//if this is the first time we are ignoring trace events, 
       
   389 				//we need to issue a EEventsUserTracesLost event
       
   390 				iEventQueue[iHead].Reset();
       
   391 				iEventQueue[iHead].iEventType = EEventsUserTracesLost;
       
   392 				IncrementHeadPosition();
       
   393 
       
   394 				iIgnoringTrace = ETrue;
       
   395 				}
       
   396 			else
       
   397 				{
       
   398 				//otherwise, ignore this event
       
   399 				LOG_MSG("DDebugAgent::QueueEvent : Ignore EEventsUserTrace event");
       
   400 				}
       
   401 			}
       
   402 		else
       
   403 			{
       
   404 			// Store the event since its not a trace event
       
   405 			iEventQueue[iHead] = aEventInfo;
       
   406 			IncrementHeadPosition();
       
   407 			}
       
   408 		}
       
   409 	else
       
   410 		{
       
   411 		//At critical level and cannot store new events, so 
       
   412 		//only one space left. Store a EEventsBufferFull event
       
   413 		LOG_MSG("DDebugAgent::QueueEvent : Event Buffer Full, ignoring event");
       
   414 		iEventQueue[iHead].Reset();
       
   415 		iEventQueue[iHead].iEventType = EEventsBufferFull;
       
   416 		IncrementHeadPosition();
       
   417 		}
       
   418 	}
       
   419 
       
   420 // End of file - d_debug_agent.cpp