diff -r 000000000000 -r a41df078684a kerneltest/e32test/debug/d_schedhook.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/debug/d_schedhook.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,470 @@ +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\debug\d_schedhook.cpp +// +// + +#include +#include +#include "platform.h" +#include +#include +#include "d_schedhook.h" + +_LIT(KLddName,"D_SCHEDHOOK"); + +NThread* TestThread; +TInt TestCount; + +const TInt KMajorVersionNumber = 0; +const TInt KMinorVersionNumber = 1; +const TInt KBuildVersionNumber = 1; + +class DSchedhookTest; + +class DSchedhookTestFactory : public DLogicalDevice + { +public: + DSchedhookTestFactory(); + virtual TInt Install(); + virtual void GetCaps(TDes8& aDes) const; + virtual TInt Create(DLogicalChannelBase*& aChannel); + }; + +class DHwExcHandler : public DKernelEventHandler + { +public: + DHwExcHandler() : DKernelEventHandler(HandleEvent, this) {} +private: + static TUint HandleEvent(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis); + }; + +class DSchedhookTest : public DLogicalChannelBase + { +public: + virtual ~DSchedhookTest(); +protected: + virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); + virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); +public: + DHwExcHandler* iHwExcHandler; + }; + +DECLARE_STANDARD_LDD() + { + return new DSchedhookTestFactory; + } + +// +// DSchedhookTestFactory +// + +DSchedhookTestFactory::DSchedhookTestFactory() + { + iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); + } + +TInt DSchedhookTestFactory::Create(DLogicalChannelBase*& aChannel) +/** + Create a new DSchedhookTest on this logical device +*/ + { + aChannel=new DSchedhookTest; + return aChannel ? KErrNone : KErrNoMemory; + } + +TInt DSchedhookTestFactory::Install() +/** + Install the LDD - overriding pure virtual +*/ + { + return SetName(&KLddName); + } + +void DSchedhookTestFactory::GetCaps(TDes8& aDes) const +/** + Get capabilities - overriding pure virtual +*/ + { + TCapsTestV01 b; + b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); + Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b)); + } + +// +// DHwExcHandler +// + +/** + Handle exceptions on our test thread by suspending it +*/ +TUint DHwExcHandler::HandleEvent(TKernelEvent aEvent, TAny* a1, TAny* /*a2*/, TAny* /*aThis*/) + { + if (aEvent == EEventHwExc) + { + if(&Kern::CurrentThread().iNThread!=TestThread) + return ERunNext; + TArmExcInfo *pR=(TArmExcInfo*)a1; + pR->iR15+=4; + Kern::ThreadSuspend(Kern::CurrentThread(),1); + return (TUint)EExcHandled; + } + return (TUint)ERunNext; + } + +// +// DSchedhookTest +// + +TInt DSchedhookTest::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) +/** + Create channel +*/ + { + if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer)) + return KErrNotSupported; + iHwExcHandler = new DHwExcHandler; + if (! iHwExcHandler) + return KErrNoMemory; + return iHwExcHandler->Add(); + } + +DSchedhookTest::~DSchedhookTest() + { + if (iHwExcHandler) + iHwExcHandler->Close(); + } + + + +// +// Scheduler Hook functions +// + +NThread* CurrentThread=NULL; + +void DisableRescheduleCallback() +/** + Stops the Scheduler calling us on every context switch +*/ + { + // Prevent rescheduling whilst we disable the callback + NKern::Lock(); + // Disable Callback + NKern::SetRescheduleCallback(NULL); + // Invalidate CurrentThread + CurrentThread = NULL; + // Callback now disabled... + NKern::Unlock(); + } + + + +void RemoveSchedulerHooks() +/** + Removes the patches added to the Scheduler code. +*/ + { + // Make sure callback is disabled (required before removing hooks) + DisableRescheduleCallback(); + // Get range of memory used by hooks + TLinAddr start,end; + NKern::Lock(); + NKern::SchedulerHooks(start,end); + NKern::Unlock(); + // Free shadow pages which cover hooks + TUint32 pageSize=Kern::RoundToPageSize(1); + NKern::ThreadEnterCS(); + for(TLinAddr a=start; aSetUserContextType(); +#endif + // Make the newly scheduled thread the CurrentThread + CurrentThread = aNThread; + // Test function + RescheduleTestFunction(); + } + + + +void RescheduleCallbackFirst(NThread* aNThread) +/** + Scheduler callback used once for initialisation. + Called with the Kernel Lock (Preemption Lock) held. +*/ + { + // Initialise CurrentThread + CurrentThread = aNThread; + // Switch future callbacks to the main RescheduleCallback + NKern::SetRescheduleCallback(RescheduleCallback); + // Test function + RescheduleTestFunction(); + } + + + +void EnableRescheduleCallback() +/** + Sets the Scheduler to call us back on every thread reschedule +*/ + { + // Reset the User Context Type for all threads, because these values + // will be out-of-date. (It is our Rescheduler callback which set's them. + // and we're just about enable that.) + + NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex + DObjectCon& threads=*Kern::Containers()[EThread]; // Get containing holding threads + threads.Wait(); // Obtain the container mutex so the list does get changed under us + +#ifndef __SMP__ + // For each thread... + TInt c=threads.Count(); + for (TInt i=0; iiNThread.ResetUserContextType(); +#endif + + threads.Signal(); // Release the container mutex + NKern::ThreadLeaveCS(); // End of critical section + + // Ask for callback + NKern::SetRescheduleCallback(RescheduleCallbackFirst); + } + + + +TInt GetThreadUserContext(NThread* aThread,TArmRegSet& aContext) +/** + Test function to get a threads User Context +*/ + { + // Get the User Context Type which our Reschedule hook set + TInt type = aThread->iSpare3; /*iUserContextType*/ + + // Get the table corresponding to the User Context Type + const TArmContextElement* c = NThread::UserContextTables()[type]; + + // Set the User Context by using the table we got + TUint32* sp = (TUint32*)aThread->iSavedSP; + TUint32* st = (TUint32*)((TUint32)aThread->iStackBase+(TUint32)aThread->iStackSize); + TArmReg* out = (TArmReg*)(&aContext); + TArmReg* end = (TArmReg*)(&aContext+1); + do + { + TInt v = c->iValue; + TInt t = c->iType; + ++c; + if(t==TArmContextElement::EOffsetFromSp) + v = sp[v]; + else if(t==TArmContextElement::EOffsetFromStackTop) + v = st[-v]; + *out++ = v; + } + while(outiNThread,&context1,unused); + TInt r=GetThreadUserContext(&aThread->iNThread,context2); + NKern::Unlock(); + DumpContext(context1,-1); + DumpContext(context2,r); + + TInt len,maxLen; + Kern::KUDesInfo(*aContext,len,maxLen); + if(maxLen>KMaxThreadContext) + maxLen = KMaxThreadContext; + TPtr8 ptr((TUint8*)&context1,maxLen,maxLen); + Kern::KUDesPut(*aContext,ptr); + + for(TUint i=0; iiNThread; + threads.Signal(); // Release the container mutex + NKern::ThreadLeaveCS(); // End of critical section + TestCount = 0; + } + break; + + case RSchedhookTest::EGetThreadContext: + return TestGetThreadContext(ThreadFromId((TUint)a1),(TDes8*)a2); + + case RSchedhookTest::EGetTestCount: + return TestCount; + + default: + r=KErrNotSupported; + break; + } + return r; + } +