sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // A helper test driver for testing Kernel Performance Logger implementation. sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: */ sl@0: sl@0: sl@0: #include "d_perflogger_ldd.h" sl@0: #include sl@0: sl@0: _LIT(KDFCThreadName,"D_PL_DFC_THREAD"); sl@0: const TInt KDFCThreadPriority=27; sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: sl@0: DKPLoggerTestHelperLDD* DKPLoggerTestHelperLDD::pSelf = NULL; //-- static pointer to the single instance of the logical channel class sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: DLogTicker::DLogTicker() : iTimer(LogTimerCallback,this) //-- initialize log events generator sl@0: { sl@0: iLogDFC = NULL; sl@0: iRequest = NULL; sl@0: iUserThreadContext = NULL; sl@0: } sl@0: sl@0: DLogTicker::~DLogTicker() sl@0: { sl@0: Cancel(); //-- cancel user request, DFC, timers etc. sl@0: Kern::DestroyClientRequest(iRequest); sl@0: delete iLogDFC; sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Construct ticker object. Creates appropriate TDfc object for dealing with IDFC or DFC sl@0: sl@0: @param apUserThreadContext pointer to the user thread context where the request will be completed in sl@0: @param apDfcQ pointer to the DFC queue this object will be using. sl@0: @param aLogContext specfies the context (ISR, DFC or IDFC) the logging will be made from. Can be NKern::EIDFC, NKern::EThread, NKern::EInterrupt sl@0: */ sl@0: void DLogTicker::Construct(DThread* aUserThreadContext, TDfcQue* aDfcQ, NKern::TContext aLogContext) sl@0: { sl@0: __NK_ASSERT_DEBUG(aUserThreadContext && aDfcQ); sl@0: sl@0: iLogContext = aLogContext; sl@0: if(aLogContext == NKern::EIDFC) sl@0: {//-- we will deal with IDFC, create appropriate DFC object sl@0: iLogDFC = new TDfc(LogDFC, this); sl@0: } sl@0: else sl@0: { sl@0: if(aLogContext == NKern::EThread || aLogContext == NKern::EInterrupt) sl@0: {//-- we will deal with DFC or ISR sl@0: iLogDFC = new TDfc(LogDFC, this, aDfcQ, 0); sl@0: } sl@0: else sl@0: {//-- wrong value sl@0: __PRINT("#KPLogTest:DLogTicker::Construct() wrong context request !"); sl@0: __NK_ASSERT_DEBUG(0); sl@0: } sl@0: } sl@0: sl@0: __NK_ASSERT_ALWAYS(iLogDFC); sl@0: sl@0: TInt r = Kern::CreateClientRequest(iRequest); sl@0: __NK_ASSERT_ALWAYS(r == KErrNone); sl@0: sl@0: iUserThreadContext = aUserThreadContext; //-- store user thread context co complete requests correctly sl@0: // iLogDFC->SetDfcQ(aDfcQ); //-- attach to the given DFC queue. !!!!DON'T DO THIS FOR IDFC!!!!! sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Start the state machine by scheduling a DFC (or IDFC) sl@0: sl@0: @param apLogControl log parameters structure sl@0: @param apRqStat pointer to the user request staus object that will be completed when all loggings done. sl@0: */ sl@0: void DLogTicker::Start(const TTestLogCtrl* aLogControl, TRequestStatus* aRqStat) sl@0: { sl@0: __NK_ASSERT_DEBUG(aLogControl && aRqStat && iLogDFC); sl@0: kumemget32(&iLogControl, aLogControl, sizeof(TTestLogCtrl)); //-- copy control structure from the user side sl@0: sl@0: __NK_ASSERT_DEBUG(iLogControl.iLogsNum>=0); sl@0: __PRINT1("#KPLogTest:DLogTicker::Start() for %d loggings",iLogControl.iLogsNum); sl@0: sl@0: if (iRequest->SetStatus(aRqStat) != KErrNone) sl@0: {//-- current request is pending, panic client thread sl@0: __PRINT("#KPLogTest:DLogTicker::Start() request is already pending !"); sl@0: Kern::PanicCurrentThread(KPLoggerHelperTestDrv, EReqAlreadyPending); sl@0: } sl@0: sl@0: if(iLogContext == NKern::EIDFC) sl@0: {//-- DLogTicker::LogDFC() will be called as IDFC sl@0: NKern::Lock(); sl@0: iLogDFC->Add(); //-- start sl@0: NKern::Unlock(); sl@0: } sl@0: else sl@0: {//-- DLogTicker::LogDFC() will be called as DFC sl@0: iLogDFC->Enque(); //-- start sl@0: } sl@0: sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Complete the user request when all logging done. sl@0: This can be called from 2 concurrent places - DFC & NTimer callback, either of them can complete the request sl@0: sl@0: @param aCompletionCode request completion code sl@0: */ sl@0: void DLogTicker::CompleteRequest(TInt aCompletionCode/*=KErrNone*/) sl@0: { sl@0: Kern::QueueRequestComplete(iUserThreadContext, iRequest, aCompletionCode); sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Cancel everything sl@0: */ sl@0: void DLogTicker::Cancel(void) sl@0: { sl@0: CompleteRequest(KErrCancel); //-- cancel user request sl@0: iLogControl.iLogsNum = 0; // Prevent DFC from restarting the timer sl@0: iTimer.Cancel(); //-- cancel Timer sl@0: iLogDFC->Cancel(); //-- cancel DFC sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Ticker timer callback. Can be called in ISR or DFC context. sl@0: If called in ISR context, makes logging, and schedules a DFC to complete the request if needed. sl@0: If called in DFC context, makes logging for DFC (not for IDFC) mode and completes the request if needed. sl@0: sl@0: @param apSelf pointer to the DLogTicker object sl@0: */ sl@0: void DLogTicker::LogTimerCallback(TAny* aSelf) sl@0: { sl@0: DLogTicker *pSelf = (DLogTicker*)aSelf; sl@0: __NK_ASSERT_DEBUG(pSelf); sl@0: sl@0: TTestLogCtrl& logClontrol = pSelf->iLogControl; sl@0: __NK_ASSERT_DEBUG(logClontrol.iLogsNum >=0); sl@0: sl@0: TInt context = NKern::CurrentContext(); sl@0: if(context == NKern::EInterrupt) sl@0: {//-- This callback is from ISR sl@0: sl@0: //-- make logging from ISR context, category field is ignored, it will be FastTrace::EKernPerfLog sl@0: PERF_LOG(logClontrol.iSubCategory, logClontrol.iUserData, logClontrol.iUserData2); sl@0: sl@0: //-- kick DFC, it will probaly complete the request. sl@0: pSelf->iLogDFC->Add(); sl@0: } sl@0: else sl@0: {//-- this is a DFC callback, but the DFC object could also have been ceated as IDFC sl@0: //-- complete user request here if necessarily. sl@0: if(pSelf->iLogDFC->IsIDFC()) sl@0: {//-- the logging will be made in IDFC function. sl@0: if(pSelf->iLogControl.iLogsNum == 0) sl@0: {//-- all done, complete the request here, because we can't do in in IDFC sl@0: pSelf->CompleteRequest(); sl@0: } sl@0: else sl@0: {//-- this callback came from IDFC object, kick IDFC in a special way. sl@0: NKern::Lock(); sl@0: pSelf->iLogDFC->Add(); sl@0: NKern::Unlock(); sl@0: } sl@0: } sl@0: else sl@0: {//-- this callback came from IDFC object, make logging from DFC context sl@0: //-- category field is ignored, it will be FastTrace::EKernPerfLog sl@0: PERF_LOG(logClontrol.iSubCategory, logClontrol.iUserData, logClontrol.iUserData2); sl@0: sl@0: pSelf->iLogDFC->Enque(); //-- kick DFC sl@0: } sl@0: sl@0: } sl@0: sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Ticker DFC or IDFC function. Kicks the timer; sl@0: If is called as IDFC, makes logging in this context and schedules a timer callback in DFC context to complete the request. sl@0: If is called as DFC, schedules timer callback in DFC or ISR context. sl@0: sl@0: @param apSelf pointer to the DLogTicker object sl@0: */ sl@0: void DLogTicker::LogDFC(TAny* aSelf) sl@0: { sl@0: DLogTicker *pSelf = (DLogTicker*)aSelf; sl@0: __NK_ASSERT_DEBUG(pSelf); sl@0: sl@0: TInt context = NKern::CurrentContext(); sl@0: (void)context; //-- avoid warning in release mode sl@0: sl@0: if(pSelf->iLogControl.iLogsNum <= 0) sl@0: {//-- complete user request, all done. The request can also be completed in LogTimerCallback() sl@0: //-- in case if this is a IDFC and callback is a DFC sl@0: pSelf->CompleteRequest(); sl@0: } sl@0: else sl@0: { sl@0: TTestLogCtrl& logClontrol = pSelf->iLogControl; sl@0: logClontrol.iLogsNum--; //-- decrease remaining number of loggings sl@0: sl@0: if(pSelf->iLogDFC->IsIDFC()) sl@0: {//-- we are in IDFC context, make logging from here, timer callback won't be IDFC sl@0: __NK_ASSERT_DEBUG(context == NKern::EIDFC); sl@0: sl@0: //-- category field is ignored, it will be FastTrace::EKernPerfLog sl@0: PERF_LOG(logClontrol.iSubCategory, logClontrol.iUserData, logClontrol.iUserData2); sl@0: sl@0: //-- kick the timer to have a callback in a specified time in DFC context sl@0: //-- timer's DFC will complete the request if necessarily. sl@0: pSelf->iTimer.OneShot(logClontrol.iLogPeriodTick, ETrue); sl@0: } sl@0: else sl@0: {//-- we are in DFC context, kick the timer to have a callback in a specified time in ISR or DFC context sl@0: pSelf->iTimer.OneShot(logClontrol.iLogPeriodTick, !(pSelf->iLogContext == NKern::EInterrupt)); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: sl@0: //################################################################################### sl@0: //# DKPLoggerTestHelperLDD class implementation sl@0: //################################################################################### sl@0: sl@0: DKPLoggerTestHelperLDD::DKPLoggerTestHelperLDD() sl@0: sl@0: { sl@0: //-- store the pointer to the current thread for request completion from ISR->DFC sl@0: iClientThread = &Kern::CurrentThread(); sl@0: sl@0: __NK_ASSERT_DEBUG(iClientThread); sl@0: sl@0: //-- Open client's user thread, incrementing ref. counter sl@0: TInt nRes = iClientThread->Open(); sl@0: __NK_ASSERT_DEBUG(nRes == KErrNone); sl@0: (void)nRes;//-- avoid warning in release mode sl@0: sl@0: sl@0: //-- initialize DFC machinery sl@0: //iDfcQ = Kern::DfcQue0(); //-- attach to the low priority DFC queue sl@0: if (!iDfcQ) sl@0: { sl@0: TInt r = Kern::DynamicDfcQCreate(iDfcQ, KDFCThreadPriority, KDFCThreadName); sl@0: if (r!= KErrNone) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: #ifdef CPU_AFFINITY_ANY sl@0: NKern::ThreadSetCpuAffinity((NThread*)(iDfcQ->iThread), KCpuAffinityAny); sl@0: #endif sl@0: } sl@0: sl@0: iIsrLogTicker.Construct (iClientThread, iDfcQ, NKern::EInterrupt);//-- construct ISR log ticker sl@0: iDfcLogTicker.Construct (iClientThread, iDfcQ, NKern::EThread); //-- construct DFC log ticker sl@0: iIDfcLogTicker.Construct(iClientThread, iDfcQ, NKern::EIDFC); //-- construct IDFC log ticker sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: DKPLoggerTestHelperLDD::~DKPLoggerTestHelperLDD() sl@0: { sl@0: __PRINT("#KPLogTest:~DKPLoggerTestHelperLDD()"); sl@0: sl@0: iClientThread->Close(NULL); sl@0: sl@0: if (iDfcQ) sl@0: iDfcQ->Destroy(); sl@0: sl@0: pSelf = NULL; //-- clear the pointer to this class instance sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: static factory function for the LDD. sl@0: sl@0: @return pointer to the created (or existing) instance of the class sl@0: */ sl@0: DKPLoggerTestHelperLDD* DKPLoggerTestHelperLDD::CreateInstance() sl@0: { sl@0: __PRINT("#KPLogTest:DKPLoggerTestHelperLDD::CreateInstance()"); sl@0: sl@0: //-- create LDD channel instance sl@0: if(pSelf) sl@0: {//-- this is a singleton, can't have more than one instance sl@0: __PRINT("#DKPLoggerTestHelperLDD::CreateInstance(): Attempt to create a second instance of a singleton!"); sl@0: return pSelf; sl@0: } sl@0: sl@0: pSelf = new DKPLoggerTestHelperLDD; sl@0: sl@0: if(!pSelf) sl@0: {//-- OOM sl@0: __PRINT("#KPLogTest:DKPLoggerTestHelperLDD::CreateInstance(): Unable to create class instance !"); sl@0: } sl@0: sl@0: return pSelf; sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: LDD second stage constructor sl@0: */ sl@0: TInt DKPLoggerTestHelperLDD::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer) sl@0: { sl@0: //-- check if the version aVer is supported sl@0: if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer)) sl@0: return KErrNotSupported; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Requests processing function. sl@0: @return request processing error code. sl@0: */ sl@0: TInt DKPLoggerTestHelperLDD::Request(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: TInt nRes = KErrNone; sl@0: sl@0: if (aFunction == KMaxTInt) sl@0: {//-- this is DoCancel() sl@0: sl@0: TUint reqMask = (TUint)a1; sl@0: DoCancel(reqMask); sl@0: return KErrNone; sl@0: } sl@0: sl@0: if(aFunction < 0) sl@0: {//-- This is DoRequest() sl@0: sl@0: //-- extract request parameters sl@0: TRequestStatus* pRqStat=(TRequestStatus*)a1; sl@0: sl@0: TAny* params[2]; sl@0: kumemget32(params, a2, sizeof(params)); sl@0: sl@0: nRes = DoRequest(~aFunction, pRqStat, params[0], params[1]); sl@0: } sl@0: else sl@0: {//-- This is DoControl() sl@0: nRes = DoControl(aFunction, a1, a2); sl@0: } sl@0: sl@0: sl@0: return nRes; sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Cancel outstanding request(s) sl@0: @param aReqNumber request number to cancel sl@0: */ sl@0: void DKPLoggerTestHelperLDD::DoCancel(TUint aReqNumber) sl@0: { sl@0: sl@0: switch (aReqNumber) sl@0: { sl@0: //-- cancel logging from ISR. sl@0: case RKPLoggerTestHelper::EDoLogFromISR: sl@0: iIsrLogTicker.Cancel(); sl@0: break; sl@0: sl@0: //-- cancel logging from IDFC. sl@0: case RKPLoggerTestHelper::EDoLogFromIDFC: sl@0: iIDfcLogTicker.Cancel(); sl@0: break; sl@0: sl@0: //-- cancel logging from DFC. sl@0: case RKPLoggerTestHelper::EDoLogFromDFC: sl@0: iDfcLogTicker.Cancel(); sl@0: break; sl@0: sl@0: default: sl@0: __PRINT1("#KPLogTest:DKPLoggerTestHelperLDD::DoCancel Cancelling a wrong request number:%d!", aReqMask); sl@0: Kern::PanicCurrentThread(KPLoggerHelperTestDrv, EWrongRequest); sl@0: break; sl@0: sl@0: } sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Asynchronous request processing. sl@0: sl@0: @param aFunction request function number, see RKPLoggerTestHelper::TControl sl@0: sl@0: @param apRqStat pointer to the user's request status object. sl@0: @param apArg1 pointer to the 1st parameter in RKPLoggerTestHelper::DoRequest sl@0: @param apArg2 pointer to the 2nd parameter in RKPLoggerTestHelper::DoRequest sl@0: sl@0: @return request scheduling result, system-wide error code. sl@0: sl@0: */ sl@0: TInt DKPLoggerTestHelperLDD::DoRequest(TInt aReqNumber, TRequestStatus* aRqStat, TAny* aArg1, TAny* /*apArg2*/) sl@0: { sl@0: switch (aReqNumber) sl@0: { sl@0: //-- make logging from ISR. sl@0: case RKPLoggerTestHelper::EDoLogFromISR: sl@0: { sl@0: __PRINT("#KPLogTest: making loggings from ISR context"); sl@0: iIsrLogTicker.Start((const TTestLogCtrl*)aArg1, aRqStat); sl@0: } sl@0: break; sl@0: sl@0: //-- make logging from IDFC. sl@0: case RKPLoggerTestHelper::EDoLogFromIDFC: sl@0: { sl@0: __PRINT("#KPLogTest: making loggings from IDFC context"); sl@0: iIDfcLogTicker.Start((const TTestLogCtrl*)aArg1, aRqStat); sl@0: } sl@0: break; sl@0: sl@0: //-- make logging from DFC. sl@0: case RKPLoggerTestHelper::EDoLogFromDFC: sl@0: { sl@0: __PRINT("#KPLogTest: making loggings from DFC context"); sl@0: iDfcLogTicker.Start((const TTestLogCtrl*)aArg1, aRqStat); sl@0: } sl@0: break; sl@0: sl@0: sl@0: default: sl@0: __PRINT1("#KPLogTest:DKPLoggerTestHelperLDD::DoRequest() Wrong request number:%d!", aReqNumber); sl@0: Kern::PanicCurrentThread(KPLoggerHelperTestDrv, EWrongRequest); sl@0: break; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------- sl@0: sl@0: /** sl@0: Synchronous requests processing. sl@0: sl@0: @param aFunction request function number, see RKernPerfLogger::TControl sl@0: @param apArg1 pointer to the 1st parameter in RKernPerfLogger::DoControl sl@0: @param apArg2 pointer to the 2n parameter in RKernPerfLogger::DoControl sl@0: sl@0: @return request processing result sl@0: */ sl@0: TInt DKPLoggerTestHelperLDD::DoControl(TInt aFunction, TAny* aArg1, TAny* /*apArg2*/) sl@0: { sl@0: sl@0: switch (aFunction) sl@0: { sl@0: //-- make test logging from the user thread sl@0: case RKPLoggerTestHelper::EDoLogFromUserThread: sl@0: { sl@0: kumemget32(&iLogControlUserThread, aArg1, sizeof(iLogControlUserThread)); //-- copy control structure from the user side sl@0: __PRINT1("#KPLogTest: making %d loggings from a user-thread context", iLogControlUserThread.iLogsNum); sl@0: __NK_ASSERT_DEBUG(iLogControlUserThread.iLogsNum >=0 ); sl@0: sl@0: //-- This context is actually, a user thread. Make logging from here sl@0: for(TInt i=0; i=0 ); sl@0: sl@0: for(TInt i=0; i