1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/active/t_act.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,380 @@
1.4 +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\active\t_act.cpp
1.18 +// Overview:
1.19 +// Test CTimer based timers and error handling in active objects and
1.20 +// active scheduler
1.21 +// API Information:
1.22 +// CTimer, CActiveScheduler
1.23 +// Details:
1.24 +// - Create and install the active scheduler
1.25 +// - Create a timer, add it to the active scheduler and start the timer
1.26 +// - Verify RunL is run when the timer fires off and test dequeuing itself from
1.27 +// the active scheduler
1.28 +// - Test that when a leave in RunL occurs, the active object gets the chance to
1.29 +// handle it before the active scheduler
1.30 +// - Test that leaves in RunL can be handled successfully in the active object
1.31 +// - Test the active object can propagate the leave to the active scheduler
1.32 +// - Test that leaves in RunL can be handled successfully in the active scheduler
1.33 +// Platforms/Drives/Compatibility:
1.34 +// All.
1.35 +// Assumptions/Requirement/Pre-requisites:
1.36 +// Failures and causes:
1.37 +// Base Port information:
1.38 +//
1.39 +//
1.40 +
1.41 +#include <e32test.h>
1.42 +#include <e32panic.h>
1.43 +
1.44 +class CMyRequestManager : public CActiveScheduler
1.45 + {
1.46 +public:
1.47 + enum TMode
1.48 + {
1.49 + EExpectError,
1.50 + EGenerateException,
1.51 + EPanic
1.52 + } iMode;
1.53 +public:
1.54 + virtual void Error(TInt anError) const;
1.55 + void SetMode(TMode aExpect);
1.56 +
1.57 +private:
1.58 + TBool iExpectError;
1.59 + };
1.60 +
1.61 +class CMyTimer : public CTimer
1.62 + {
1.63 +public:
1.64 + static CMyTimer* New();
1.65 + void Start();
1.66 + virtual void RunL();
1.67 + void StartLeave(TBool aHandleLocally, TBool aLeaveInOOM, CMyRequestManager::TMode aMode);
1.68 + virtual TInt RunError(TInt aError);
1.69 + void StopLeave();
1.70 + void StartImbalance();
1.71 + virtual ~CMyTimer();
1.72 +protected:
1.73 + CMyTimer(TInt aPriority);
1.74 +private:
1.75 + enum {EMaxCount=10,ETimeReq=100000};
1.76 + CBase* iDummy;
1.77 + TInt iCount;
1.78 + TBool iConstructed;
1.79 + TBool iLeave;
1.80 + TBool iHandleLocally;
1.81 + TBool iLeaveInOOM;
1.82 + TBool iImbalance;
1.83 + TBool iStopping;
1.84 + };
1.85 +
1.86 +LOCAL_D RTest test(_L("T_ACT"));
1.87 +
1.88 +void CMyRequestManager::Error(TInt anError) const
1.89 +//
1.90 +// Called if any Run() method leaves.
1.91 +//
1.92 + {
1.93 + switch (iMode)
1.94 + {
1.95 + case EExpectError:
1.96 + {
1.97 + _LIT(KExpectError,"CMyRequestManager::Error handling error %d\n");
1.98 + test.Printf(KExpectError,anError);
1.99 + Stop();
1.100 + return;
1.101 + }
1.102 + case EGenerateException:
1.103 + {
1.104 +
1.105 + _LIT(KExpectError,"CMyRequestManager::Error about to generate exception...\n");
1.106 + test.Printf(KExpectError,anError);
1.107 +
1.108 + __UHEAP_FAILNEXT(1);
1.109 + TRAPD(ret,User::Leave(KErrArgument));
1.110 + __UHEAP_RESET;
1.111 + if (ret != KErrArgument)
1.112 + {
1.113 + _LIT(KDoNotExpectError,"CMyRequestManager::Error unexpected");
1.114 + test.Panic(anError,KDoNotExpectError);
1.115 + }
1.116 + Stop();
1.117 + return;
1.118 + }
1.119 + case EPanic:
1.120 + default:
1.121 + {
1.122 + _LIT(KDoNotExpectError,"CMyRequestManager::Error unexpected");
1.123 + test.Panic(anError,KDoNotExpectError);
1.124 + }
1.125 + }
1.126 + }
1.127 +
1.128 +
1.129 +void CMyRequestManager::SetMode(TMode aMode)
1.130 + {
1.131 + iMode = aMode;
1.132 + }
1.133 +
1.134 +CMyTimer* CMyTimer::New()
1.135 +//
1.136 +// Create a new CMyTimer.
1.137 +//
1.138 + {
1.139 +
1.140 + return(new CMyTimer(0));
1.141 + }
1.142 +
1.143 +CMyTimer::CMyTimer(TInt aPriority)
1.144 +//
1.145 +// Constructor
1.146 +//
1.147 + : CTimer(aPriority),iCount(0), iImbalance(EFalse), iStopping(EFalse)
1.148 + {}
1.149 +
1.150 +CMyTimer::~CMyTimer()
1.151 + {
1.152 + delete iDummy;
1.153 + }
1.154 +
1.155 +void CMyTimer::Start()
1.156 +//
1.157 +// Start the timer
1.158 +//
1.159 + {
1.160 + if (!iConstructed)
1.161 + {
1.162 + TRAPD(r, ConstructL());
1.163 + test(r==KErrNone);
1.164 + iConstructed = ETrue;
1.165 + iDummy = new(ELeave)CBase();
1.166 + }
1.167 + CActiveScheduler::Add(this); // Previously caused panic in UREL after Deque()
1.168 + SetPriority(1);
1.169 + After(ETimeReq);
1.170 + }
1.171 +
1.172 +void CMyTimer::StartLeave(TBool aHandleLocally, TBool aLeaveInOOM, CMyRequestManager::TMode aMode)
1.173 +//
1.174 +// Start the timer
1.175 +//
1.176 + {
1.177 + CActiveScheduler::Add(this);
1.178 + SetPriority(1);
1.179 + After(ETimeReq);
1.180 + iLeave = ETrue;
1.181 + iHandleLocally = aHandleLocally;
1.182 + iLeaveInOOM = aLeaveInOOM;
1.183 + // STATIC_CAST(CMyRequestManager*,CActiveScheduler::Current())->ExpectError(!aHandleLocally);
1.184 + STATIC_CAST(CMyRequestManager*,CActiveScheduler::Current())->SetMode(aMode);
1.185 + }
1.186 +
1.187 +void CMyTimer::StopLeave()
1.188 + {
1.189 + iLeave=EFalse;
1.190 + }
1.191 +
1.192 +void CMyTimer::StartImbalance()
1.193 + {
1.194 + iImbalance=ETrue;
1.195 + }
1.196 +
1.197 +void CMyTimer::RunL()
1.198 +//
1.199 +// The timer has completed.
1.200 +//
1.201 + {
1.202 + if (iLeave)
1.203 + {
1.204 + Deque(); // Test removal from scheduler
1.205 + if (iLeaveInOOM)
1.206 + {
1.207 + __UHEAP_FAILNEXT(1);
1.208 + }
1.209 + User::Leave(KErrGeneral);
1.210 + }
1.211 +
1.212 + // This switch is used when testing for imbalance in the cleanupstack
1.213 + if(iImbalance)
1.214 + {
1.215 + if(iStopping)
1.216 + {
1.217 +
1.218 + iStopping=EFalse;
1.219 + //CleanupStack::PopAndDestroy(iDummy);
1.220 + CActiveScheduler::Stop();
1.221 + return;
1.222 + }
1.223 + else
1.224 + {
1.225 + // Push something onto the stack, but dont take it off
1.226 + //- deal in CActiveScheduler::DoRunL
1.227 + CleanupStack::PushL(iDummy);
1.228 + iStopping=ETrue; //Stop the scheduler the next time
1.229 + iCount=EMaxCount;
1.230 +// CActiveScheduler::Stop();
1.231 + After(ETimeReq);
1.232 + return;
1.233 + }
1.234 + }
1.235 +
1.236 + iCount++;
1.237 + SetPriority(iCount);
1.238 + test.Printf(_L("\r%03d"),iCount);
1.239 +
1.240 + if (iCount<EMaxCount)
1.241 + After(ETimeReq);
1.242 + else
1.243 + {
1.244 + test.Printf(_L("\n"));
1.245 + CActiveScheduler::Stop();
1.246 + Deque(); // Test removal from scheduler
1.247 + iCount = 0;
1.248 + }
1.249 + }
1.250 +
1.251 +TInt CMyTimer::RunError(TInt aError)
1.252 +//
1.253 +// Handle leave from RunL
1.254 +//
1.255 + {
1.256 + if (iHandleLocally)
1.257 + {
1.258 + _LIT(KExpectError,"CMyTimer::RunError handling error %d\n");
1.259 + test.Printf(KExpectError,aError);
1.260 + CActiveScheduler::Stop();
1.261 + return KErrNone;
1.262 + }
1.263 + else
1.264 + return aError; // Let the scheduler handle this error
1.265 + }
1.266 +
1.267 +
1.268 +TInt DoImbalanceTest(TAny* /*aAny*/)
1.269 +// This function is the first executing fuction of the cleanupstack imbalace
1.270 +// testing thread - RunLCleanupImbalance
1.271 +// see ImbalanceTest()
1.272 + {
1.273 + // Set up cleanup stack & scheduler
1.274 + RTest test(_L("Thread:RunLCleanupImbalance - DoImbalanceTest()"));
1.275 + test.Start(_L("DoImbalanceTest()"));
1.276 +
1.277 + //Create a cleanup stack and scheduler
1.278 + CTrapCleanup::New();
1.279 + CActiveScheduler* cas = new(ELeave) CActiveScheduler();
1.280 + CActiveScheduler::Install(cas);
1.281 +
1.282 + // Create a new AO.
1.283 + CMyTimer* myTimer = CMyTimer::New();
1.284 + myTimer->StopLeave();
1.285 + myTimer->StartImbalance();
1.286 + // Start the AO
1.287 + test.Next(_L("Start Imblance Test"));
1.288 + myTimer->Start();
1.289 +
1.290 + test.Next(_L("Start Scheduler"));
1.291 + // The following is expected to panic (with EUSER-CBase 90 EClnCheckFailed)
1.292 + cas->Start();
1.293 +
1.294 + delete myTimer;
1.295 + delete cas;
1.296 + test.End();
1.297 + return 0;
1.298 + }
1.299 +
1.300 +#ifdef _DEBUG
1.301 +LOCAL_C void ImbalanceTest()
1.302 +// this test will test whether the cleanup stack is imbalanced after
1.303 +// a runL of an Active object.
1.304 + {
1.305 + TBool imbalanced = ETrue;
1.306 + User::SetJustInTime(EFalse);
1.307 + RThread t;
1.308 + TRequestStatus s;
1.309 + test.Next(_L("Create a thread (RunLCleanupImbalance)"));
1.310 + TInt r=t.Create(_L("RunLCleanupImbalance"),DoImbalanceTest,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,&imbalanced);
1.311 + test(r==KErrNone);
1.312 + t.Logon(s);
1.313 + test.Next(_L("Resume and wait for panic (E32USER-CBase 90 EClnCheckFailed) due to imbalance"));
1.314 + t.Resume();
1.315 + User::WaitForRequest(s);
1.316 +
1.317 + test.Printf(_L("Exit Type %d\r\n"),(TInt)t.ExitType());
1.318 + test.Printf(_L("Exit Reason %d\r\n"),(TInt)t.ExitReason());
1.319 +
1.320 + test(t.ExitReason()==EClnCheckFailed);
1.321 +
1.322 + CLOSE_AND_WAIT(t);
1.323 +
1.324 + }
1.325 +#endif
1.326 +
1.327 +GLDEF_C TInt E32Main()
1.328 +//
1.329 +// Test timers.
1.330 +//
1.331 + {
1.332 + test.Title();
1.333 + test.Start(_L("Creating CActiveScheduler"));
1.334 + CMyRequestManager* pR=new CMyRequestManager;
1.335 + test(pR!=NULL);
1.336 + CActiveScheduler::Install(pR);
1.337 +//
1.338 + test.Next(_L("Testing relative timers"));
1.339 + CMyTimer* pT=CMyTimer::New();
1.340 + test(pT!=NULL);
1.341 +//
1.342 + test.Next(_L("Start timer"));
1.343 + pT->Start();
1.344 +//
1.345 + test.Next(_L("Start CMyRequestManager"));
1.346 + CActiveScheduler::Start();
1.347 +//
1.348 + test.Next(_L("Start timer again"));
1.349 + pT->Start();
1.350 +//
1.351 + test.Next(_L("Start CMyRequestManager"));
1.352 + CActiveScheduler::Start();
1.353 +//
1.354 + test.Next(_L("Start timer, leave in RunL, handle in scheduler"));
1.355 + pT->StartLeave(EFalse, EFalse, CMyRequestManager::EExpectError );
1.356 +//
1.357 + test.Next(_L("Start CMyRequestManager"));
1.358 + CActiveScheduler::Start();
1.359 +#ifdef _DEBUG
1.360 +//
1.361 + test.Next(_L("Start timer, leave in RunL, generate nested exception under OOM condition"));
1.362 + pT->StartLeave(EFalse, ETrue, CMyRequestManager::EGenerateException);
1.363 +//
1.364 + test.Next(_L("Start CMyRequestManager"));
1.365 + CActiveScheduler::Start();
1.366 + __UHEAP_RESET;
1.367 +#endif
1.368 + //
1.369 + test.Next(_L("Start timer, leave in RunL, handle in object"));
1.370 + pT->StartLeave(ETrue, EFalse, CMyRequestManager::EPanic);
1.371 +//
1.372 + test.Next(_L("Start CMyRequestManager"));
1.373 + CActiveScheduler::Start();
1.374 +//
1.375 +#ifdef _DEBUG
1.376 +// Test the cleanupstack imbalances
1.377 + test.Next(_L("Test : Check Cleanupstack imbalance in RunL, handle(panic) in scheduler"));
1.378 + ImbalanceTest();
1.379 +#endif
1.380 +//
1.381 + test.End();
1.382 + return(0);
1.383 + }