diff -r 000000000000 -r a41df078684a kerneltest/e32test/active/t_act.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/active/t_act.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,380 @@ +// Copyright (c) 1995-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\active\t_act.cpp +// Overview: +// Test CTimer based timers and error handling in active objects and +// active scheduler +// API Information: +// CTimer, CActiveScheduler +// Details: +// - Create and install the active scheduler +// - Create a timer, add it to the active scheduler and start the timer +// - Verify RunL is run when the timer fires off and test dequeuing itself from +// the active scheduler +// - Test that when a leave in RunL occurs, the active object gets the chance to +// handle it before the active scheduler +// - Test that leaves in RunL can be handled successfully in the active object +// - Test the active object can propagate the leave to the active scheduler +// - Test that leaves in RunL can be handled successfully in the active scheduler +// Platforms/Drives/Compatibility: +// All. +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// Base Port information: +// +// + +#include +#include + +class CMyRequestManager : public CActiveScheduler + { +public: + enum TMode + { + EExpectError, + EGenerateException, + EPanic + } iMode; +public: + virtual void Error(TInt anError) const; + void SetMode(TMode aExpect); + +private: + TBool iExpectError; + }; + +class CMyTimer : public CTimer + { +public: + static CMyTimer* New(); + void Start(); + virtual void RunL(); + void StartLeave(TBool aHandleLocally, TBool aLeaveInOOM, CMyRequestManager::TMode aMode); + virtual TInt RunError(TInt aError); + void StopLeave(); + void StartImbalance(); + virtual ~CMyTimer(); +protected: + CMyTimer(TInt aPriority); +private: + enum {EMaxCount=10,ETimeReq=100000}; + CBase* iDummy; + TInt iCount; + TBool iConstructed; + TBool iLeave; + TBool iHandleLocally; + TBool iLeaveInOOM; + TBool iImbalance; + TBool iStopping; + }; + +LOCAL_D RTest test(_L("T_ACT")); + +void CMyRequestManager::Error(TInt anError) const +// +// Called if any Run() method leaves. +// + { + switch (iMode) + { + case EExpectError: + { + _LIT(KExpectError,"CMyRequestManager::Error handling error %d\n"); + test.Printf(KExpectError,anError); + Stop(); + return; + } + case EGenerateException: + { + + _LIT(KExpectError,"CMyRequestManager::Error about to generate exception...\n"); + test.Printf(KExpectError,anError); + + __UHEAP_FAILNEXT(1); + TRAPD(ret,User::Leave(KErrArgument)); + __UHEAP_RESET; + if (ret != KErrArgument) + { + _LIT(KDoNotExpectError,"CMyRequestManager::Error unexpected"); + test.Panic(anError,KDoNotExpectError); + } + Stop(); + return; + } + case EPanic: + default: + { + _LIT(KDoNotExpectError,"CMyRequestManager::Error unexpected"); + test.Panic(anError,KDoNotExpectError); + } + } + } + + +void CMyRequestManager::SetMode(TMode aMode) + { + iMode = aMode; + } + +CMyTimer* CMyTimer::New() +// +// Create a new CMyTimer. +// + { + + return(new CMyTimer(0)); + } + +CMyTimer::CMyTimer(TInt aPriority) +// +// Constructor +// + : CTimer(aPriority),iCount(0), iImbalance(EFalse), iStopping(EFalse) + {} + +CMyTimer::~CMyTimer() + { + delete iDummy; + } + +void CMyTimer::Start() +// +// Start the timer +// + { + if (!iConstructed) + { + TRAPD(r, ConstructL()); + test(r==KErrNone); + iConstructed = ETrue; + iDummy = new(ELeave)CBase(); + } + CActiveScheduler::Add(this); // Previously caused panic in UREL after Deque() + SetPriority(1); + After(ETimeReq); + } + +void CMyTimer::StartLeave(TBool aHandleLocally, TBool aLeaveInOOM, CMyRequestManager::TMode aMode) +// +// Start the timer +// + { + CActiveScheduler::Add(this); + SetPriority(1); + After(ETimeReq); + iLeave = ETrue; + iHandleLocally = aHandleLocally; + iLeaveInOOM = aLeaveInOOM; + // STATIC_CAST(CMyRequestManager*,CActiveScheduler::Current())->ExpectError(!aHandleLocally); + STATIC_CAST(CMyRequestManager*,CActiveScheduler::Current())->SetMode(aMode); + } + +void CMyTimer::StopLeave() + { + iLeave=EFalse; + } + +void CMyTimer::StartImbalance() + { + iImbalance=ETrue; + } + +void CMyTimer::RunL() +// +// The timer has completed. +// + { + if (iLeave) + { + Deque(); // Test removal from scheduler + if (iLeaveInOOM) + { + __UHEAP_FAILNEXT(1); + } + User::Leave(KErrGeneral); + } + + // This switch is used when testing for imbalance in the cleanupstack + if(iImbalance) + { + if(iStopping) + { + + iStopping=EFalse; + //CleanupStack::PopAndDestroy(iDummy); + CActiveScheduler::Stop(); + return; + } + else + { + // Push something onto the stack, but dont take it off + //- deal in CActiveScheduler::DoRunL + CleanupStack::PushL(iDummy); + iStopping=ETrue; //Stop the scheduler the next time + iCount=EMaxCount; +// CActiveScheduler::Stop(); + After(ETimeReq); + return; + } + } + + iCount++; + SetPriority(iCount); + test.Printf(_L("\r%03d"),iCount); + + if (iCountStopLeave(); + myTimer->StartImbalance(); + // Start the AO + test.Next(_L("Start Imblance Test")); + myTimer->Start(); + + test.Next(_L("Start Scheduler")); + // The following is expected to panic (with EUSER-CBase 90 EClnCheckFailed) + cas->Start(); + + delete myTimer; + delete cas; + test.End(); + return 0; + } + +#ifdef _DEBUG +LOCAL_C void ImbalanceTest() +// this test will test whether the cleanup stack is imbalanced after +// a runL of an Active object. + { + TBool imbalanced = ETrue; + User::SetJustInTime(EFalse); + RThread t; + TRequestStatus s; + test.Next(_L("Create a thread (RunLCleanupImbalance)")); + TInt r=t.Create(_L("RunLCleanupImbalance"),DoImbalanceTest,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,&imbalanced); + test(r==KErrNone); + t.Logon(s); + test.Next(_L("Resume and wait for panic (E32USER-CBase 90 EClnCheckFailed) due to imbalance")); + t.Resume(); + User::WaitForRequest(s); + + test.Printf(_L("Exit Type %d\r\n"),(TInt)t.ExitType()); + test.Printf(_L("Exit Reason %d\r\n"),(TInt)t.ExitReason()); + + test(t.ExitReason()==EClnCheckFailed); + + CLOSE_AND_WAIT(t); + + } +#endif + +GLDEF_C TInt E32Main() +// +// Test timers. +// + { + test.Title(); + test.Start(_L("Creating CActiveScheduler")); + CMyRequestManager* pR=new CMyRequestManager; + test(pR!=NULL); + CActiveScheduler::Install(pR); +// + test.Next(_L("Testing relative timers")); + CMyTimer* pT=CMyTimer::New(); + test(pT!=NULL); +// + test.Next(_L("Start timer")); + pT->Start(); +// + test.Next(_L("Start CMyRequestManager")); + CActiveScheduler::Start(); +// + test.Next(_L("Start timer again")); + pT->Start(); +// + test.Next(_L("Start CMyRequestManager")); + CActiveScheduler::Start(); +// + test.Next(_L("Start timer, leave in RunL, handle in scheduler")); + pT->StartLeave(EFalse, EFalse, CMyRequestManager::EExpectError ); +// + test.Next(_L("Start CMyRequestManager")); + CActiveScheduler::Start(); +#ifdef _DEBUG +// + test.Next(_L("Start timer, leave in RunL, generate nested exception under OOM condition")); + pT->StartLeave(EFalse, ETrue, CMyRequestManager::EGenerateException); +// + test.Next(_L("Start CMyRequestManager")); + CActiveScheduler::Start(); + __UHEAP_RESET; +#endif + // + test.Next(_L("Start timer, leave in RunL, handle in object")); + pT->StartLeave(ETrue, EFalse, CMyRequestManager::EPanic); +// + test.Next(_L("Start CMyRequestManager")); + CActiveScheduler::Start(); +// +#ifdef _DEBUG +// Test the cleanupstack imbalances + test.Next(_L("Test : Check Cleanupstack imbalance in RunL, handle(panic) in scheduler")); + ImbalanceTest(); +#endif +// + test.End(); + return(0); + }