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