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: // e32test\emi\d_emitest.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include "d_emitest.h" sl@0: #include "d_emitest_dev.h" sl@0: #include sl@0: sl@0: // sl@0: // DEMITestFactory sl@0: // sl@0: sl@0: /* sl@0: Standard export function for LDDs. This creates a DLogicalDevice derived object, sl@0: in this case, our DEMITestFactory sl@0: */ sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DEMITestFactory; sl@0: } sl@0: sl@0: DEMITestFactory::DEMITestFactory() sl@0: { sl@0: } sl@0: sl@0: DEMITestFactory::~DEMITestFactory() sl@0: { sl@0: } sl@0: sl@0: /* sl@0: Second stage constructor for DEMITestFactory. sl@0: This must at least set a name for the driver object. sl@0: sl@0: @return KErrNone or standard error code. sl@0: */ sl@0: TInt DEMITestFactory::Install() sl@0: { sl@0: return SetName(&KEMITestName); sl@0: } sl@0: sl@0: /* sl@0: Return the drivers capabilities. sl@0: Called in the response to an RDevice::GetCaps() request. sl@0: The thread is in a critical section. sl@0: sl@0: @param aDes Descriptor to write capabilities information into sl@0: */ sl@0: void DEMITestFactory::GetCaps(TDes8&) const sl@0: { sl@0: } sl@0: sl@0: /* sl@0: Called by the kernel's device driver framework to create a Logical Channel. sl@0: This is called in the context of the user thread (client) which requested the creation of a Logical Channel sl@0: (E.g. through a call to RBusLogicalChannel::DoCreate) sl@0: The thread is in a critical section. sl@0: sl@0: @param aChannel Set to point to the created Logical Channel sl@0: sl@0: @return KErrNone or standard error code. sl@0: */ sl@0: TInt DEMITestFactory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: aChannel=new DEMITestChannel; sl@0: if(!aChannel) sl@0: return KErrNoMemory; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // sl@0: // Logical Channel sl@0: // sl@0: sl@0: DEMITestChannel::DEMITestChannel() sl@0: : iTagMaskDFC(TagMaskDFC,NULL,1) sl@0: { sl@0: // Get pointer to client threads DThread object sl@0: iClient=&Kern::CurrentThread(); sl@0: // Open a reference on client thread so it's control block can't dissapear until sl@0: // this driver has finished with it. sl@0: ((DObject*)iClient)->Open(); sl@0: } sl@0: sl@0: DEMITestChannel::~DEMITestChannel() sl@0: { sl@0: // Stop EMI, incase it wannt stopped manually. sl@0: EMI::TaskEventLogging(EFalse,0,NULL,NULL); sl@0: EMI::SetMask(0); sl@0: sl@0: // Close our reference on the client thread sl@0: Kern::SafeClose((DObject*&)iClient,NULL); sl@0: } sl@0: sl@0: /* sl@0: Second stage constructor called by the kernel's device driver framework. sl@0: This is called in the context of the user thread (client) which requested the creation of a Logical Channel sl@0: (E.g. through a call to RBusLogicalChannel::DoCreate) sl@0: The thread is in a critical section. sl@0: sl@0: @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate sl@0: @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate sl@0: @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate sl@0: sl@0: @return KErrNone or standard error code. sl@0: */ sl@0: TInt DEMITestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion&) sl@0: { sl@0: iTagMaskDFC.SetDfcQ(Kern::DfcQue0()); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /* sl@0: Normal test monitors sl@0: */ sl@0: TInt MyThreadStartMonitor(NThread* aNThread) sl@0: { sl@0: TTaskEventRecord rec; sl@0: rec.iType=128; sl@0: rec.iPrevious=((TInt*) aNThread)+1; // This stops the event getting killed on thread exit. sl@0: // This means there is no garantee the thread will still exist when sl@0: // the record is read. This is only safe here as the test code never sl@0: // attempts to derefrance this pointer. sl@0: EMI::AddTaskEvent(rec); sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: void MyThreadExitMonitor(NThread* aNThread) sl@0: { sl@0: TTaskEventRecord rec; sl@0: rec.iType=129; sl@0: rec.iPrevious=aNThread; sl@0: EMI::AddTaskEvent(rec); sl@0: } sl@0: /* sl@0: Stress test monitors sl@0: sl@0: Vems = 1: Passed. sl@0: 0: No monitors called. sl@0: -1: Wrong Exit monitor callled. sl@0: -2: Exit call before StartMonitor sl@0: -3: Jibberish VEMs value. (or anything ending 5-9) sl@0: -4: Exit called multiple times, 1st time ok. sl@0: <-9: Exit called multiple times. See last digit for status 1st time. sl@0: Stops couting after -1000, where its clearly very sick! sl@0: */ sl@0: sl@0: sl@0: TInt SoakStartMonitor1(NThread* aNThread) sl@0: { sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)1000); sl@0: return 0; sl@0: } sl@0: sl@0: TInt SoakStartMonitor2(NThread* aNThread) sl@0: { sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)2000); sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: sl@0: inline void SoakExitMonitor(NThread* aNThread, TInt aOwner) sl@0: { sl@0: TInt val = (TInt) EMI::GetThreadVemsData(aNThread); sl@0: sl@0: if (val>-1) sl@0: { sl@0: TInt notOwner = (aOwner==1000?2000:1000); sl@0: sl@0: if (val==aOwner) sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)1); sl@0: else if (val==notOwner) sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)-1); sl@0: else if (val==0) sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)-2); sl@0: else if (val==1) sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)-4); sl@0: else sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)-3); sl@0: } sl@0: else sl@0: { sl@0: if (val>-1000) sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)(val-10)); sl@0: else sl@0: EMI::SetThreadVemsData(aNThread,(TAny*)val); sl@0: } sl@0: } sl@0: sl@0: void SoakExitMonitor1(NThread* aNThread) sl@0: { sl@0: SoakExitMonitor(aNThread,1000); sl@0: } sl@0: void SoakExitMonitor2(NThread* aNThread) sl@0: { sl@0: SoakExitMonitor(aNThread,2000); sl@0: } sl@0: sl@0: /* sl@0: Process synchronous requests sl@0: */ sl@0: TInt DEMITestChannel::Request(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: TInt r=KErrNotSupported; sl@0: TTaskEventRecord rec; sl@0: sl@0: switch (aFunction) sl@0: { sl@0: case REMITest::ETaskEventLogging: sl@0: { sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: sl@0: TMonitors mon = (TMonitors) ((TInt)a1 >> 1); sl@0: TBool logging = (TBool) ((TInt)a1 & 1); sl@0: sl@0: switch (mon) sl@0: { sl@0: case ENone: r = EMI::TaskEventLogging(logging,(TInt) a2,NULL,NULL); sl@0: break; sl@0: case ENormal: r = EMI::TaskEventLogging(logging,(TInt) a2,&MyThreadStartMonitor,&MyThreadExitMonitor); sl@0: break; sl@0: case EStressFirst:r = EMI::TaskEventLogging(logging,(TInt) a2,SoakStartMonitor1,SoakExitMonitor1); sl@0: break; sl@0: case EStressSecond:r = EMI::TaskEventLogging(logging,(TInt) a2,SoakStartMonitor2,SoakExitMonitor2); sl@0: } sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: case REMITest::EGetTaskEvent: sl@0: r = (TInt) EMI::GetTaskEvent(rec); sl@0: if (r) sl@0: kumemput(a1,&rec,sizeof(TTaskEventRecord)); sl@0: return r; sl@0: case REMITest::EAddTaskEvent: sl@0: kumemget(&rec,a1,sizeof(TTaskEventRecord)); sl@0: return (TInt) EMI::AddTaskEvent(rec); sl@0: case REMITest::EGetIdleThread: sl@0: return (TInt) EMI::GetIdleThread(); sl@0: case REMITest::EGetSigmaThread: sl@0: return (TInt) EMI::GetSigmaThread(); sl@0: case REMITest::ESetVEMSData: sl@0: EMI::SetThreadVemsData((NThread*) a1,a2); sl@0: return KErrNone; sl@0: case REMITest::EGetVEMSData: sl@0: return (TInt) EMI::GetThreadVemsData((NThread*) a1); sl@0: case REMITest::ESetThreadLoggable: sl@0: EMI::SetThreadLoggable((NThread*) a1,(TBool) a2); sl@0: return KErrNone; sl@0: case REMITest::EGetThreadLoggable: sl@0: return (TInt) EMI::GetThreadLoggable((NThread*) a1); sl@0: case REMITest::ESetThreadTag: sl@0: EMI::SetThreadTag((NThread*) a1,(TUint32) a2); sl@0: return KErrNone; sl@0: case REMITest::EGetThreadTag: sl@0: return (TInt) EMI::GetThreadTag((NThread*) a1); sl@0: case REMITest::ESetMask: sl@0: EMI::SetMask((TInt) a1); sl@0: return KErrNone; sl@0: case REMITest::EGetMask: sl@0: return EMI::GetMask(); sl@0: case REMITest::ESetDFC: sl@0: EMI::SetDfc(&iTagMaskDFC, 0); sl@0: return KErrNone; sl@0: case REMITest::ESetState: sl@0: EMI::SetState((TInt) a1); sl@0: return KErrNone; sl@0: case REMITest::EGetState: sl@0: return EMI::GetState(); sl@0: case REMITest::EGetNThread: sl@0: { sl@0: DThread* myThread; sl@0: TInt myNThread; sl@0: NKern::LockSystem(); sl@0: sl@0: myThread = (DThread* ) Kern::CurrentThread().ObjectFromHandle((TInt)a1,EThread); sl@0: myNThread= (TInt) (myThread==NULL?NULL:&myThread->iNThread); sl@0: NKern::UnlockSystem(); sl@0: return myNThread; sl@0: } sl@0: case REMITest::EAfterIdle: sl@0: EMI::AfterIdle((TInt) a1); sl@0: return KErrNone; sl@0: sl@0: default: sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: sl@0: /* sl@0: DFC callback which gets triggered when the EMI tag anded with thread mask is true. sl@0: Sets EMI state to be the value returned from GetDfcTriggerTag. sl@0: */ sl@0: void DEMITestChannel::TagMaskDFC(TAny*) sl@0: { sl@0: EMI::SetState(EMI::GetDfcTriggerTag()); sl@0: EMI::SetMask(0); sl@0: }