os/kernelhwsrv/kerneltest/e32test/active/t_act.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\active\t_act.cpp
    15 // Overview:
    16 // Test CTimer based timers and error handling in active objects and 
    17 // active scheduler
    18 // API Information:
    19 // CTimer, CActiveScheduler
    20 // Details:
    21 // - Create and install the active scheduler
    22 // - Create a timer, add it to the active scheduler and start the timer
    23 // - Verify RunL is run when the timer fires off and test dequeuing itself from 
    24 // the active scheduler
    25 // - Test that when a leave in RunL occurs, the active object gets the chance to 
    26 // handle it before the active scheduler
    27 // - Test that leaves in RunL can be handled successfully in the active object
    28 // - Test the active object can propagate the leave to the active scheduler
    29 // - Test that leaves in RunL can be handled successfully in the active scheduler
    30 // Platforms/Drives/Compatibility:
    31 // All.
    32 // Assumptions/Requirement/Pre-requisites:
    33 // Failures and causes:
    34 // Base Port information:
    35 // 
    36 //
    37 
    38 #include <e32test.h>
    39 #include <e32panic.h>
    40 
    41 class CMyRequestManager : public CActiveScheduler
    42 	{
    43 public:
    44 	enum TMode
    45 		{
    46 		EExpectError,
    47 		EGenerateException,
    48 		EPanic
    49 	} iMode;
    50 public:
    51 	virtual void Error(TInt anError) const;
    52 	void SetMode(TMode aExpect);
    53 
    54 private:
    55 	TBool iExpectError;
    56 	};
    57 
    58 class CMyTimer : public CTimer
    59 	{
    60 public:
    61 	static CMyTimer* New();
    62 	void Start();
    63 	virtual void RunL();
    64 	void StartLeave(TBool aHandleLocally, TBool aLeaveInOOM, CMyRequestManager::TMode aMode);
    65 	virtual TInt RunError(TInt aError);
    66 	void StopLeave();
    67 	void StartImbalance();
    68 	virtual ~CMyTimer();
    69 protected:
    70 	CMyTimer(TInt aPriority);
    71 private:
    72 	enum {EMaxCount=10,ETimeReq=100000};
    73 	CBase* iDummy;
    74 	TInt iCount;
    75 	TBool iConstructed;
    76 	TBool iLeave;
    77 	TBool iHandleLocally;
    78 	TBool iLeaveInOOM;
    79 	TBool iImbalance;
    80 	TBool iStopping;
    81 	};
    82 
    83 LOCAL_D RTest test(_L("T_ACT"));
    84 
    85 void CMyRequestManager::Error(TInt anError) const
    86 //
    87 // Called if any Run() method leaves.
    88 //
    89 	{
    90 	switch (iMode)
    91 		{
    92 		case EExpectError:
    93 			{
    94 			_LIT(KExpectError,"CMyRequestManager::Error handling error %d\n");
    95 			test.Printf(KExpectError,anError);
    96 			Stop();
    97 			return;
    98 			}
    99 		case EGenerateException:
   100 			{
   101 
   102 			_LIT(KExpectError,"CMyRequestManager::Error about to generate exception...\n");
   103 			test.Printf(KExpectError,anError);
   104 
   105 			__UHEAP_FAILNEXT(1);
   106 			TRAPD(ret,User::Leave(KErrArgument));
   107 			__UHEAP_RESET;
   108 	   		if (ret != KErrArgument) 
   109 	   			{
   110 				_LIT(KDoNotExpectError,"CMyRequestManager::Error unexpected");
   111 				test.Panic(anError,KDoNotExpectError);
   112 	   			}
   113 			Stop();
   114 			return;	
   115 			}
   116 		case EPanic:
   117 		default:
   118 			{
   119 			_LIT(KDoNotExpectError,"CMyRequestManager::Error unexpected");
   120 			test.Panic(anError,KDoNotExpectError);
   121 			}
   122 		}
   123 	}
   124 
   125 
   126 void CMyRequestManager::SetMode(TMode aMode)
   127 	{
   128 	iMode = aMode;
   129 	}
   130 
   131 CMyTimer* CMyTimer::New()
   132 //
   133 // Create a new CMyTimer.
   134 //
   135 	{
   136 
   137 	return(new CMyTimer(0));
   138 	}
   139 
   140 CMyTimer::CMyTimer(TInt aPriority)
   141 //
   142 // Constructor
   143 //
   144 	: CTimer(aPriority),iCount(0), iImbalance(EFalse), iStopping(EFalse)
   145 	{}
   146 
   147 CMyTimer::~CMyTimer()
   148 	{
   149 	delete iDummy;
   150 	}
   151 
   152 void CMyTimer::Start()
   153 //
   154 // Start the timer
   155 //
   156 	{
   157 	if (!iConstructed)
   158 		{
   159 		TRAPD(r, ConstructL());
   160 		test(r==KErrNone);
   161 		iConstructed = ETrue;
   162 		iDummy = new(ELeave)CBase();
   163 		}
   164 	CActiveScheduler::Add(this); // Previously caused panic in UREL after Deque()
   165 	SetPriority(1);
   166 	After(ETimeReq);
   167 	}
   168 
   169 void CMyTimer::StartLeave(TBool aHandleLocally, TBool aLeaveInOOM, CMyRequestManager::TMode aMode)
   170 //
   171 // Start the timer
   172 //
   173 	{
   174 	CActiveScheduler::Add(this); 
   175 	SetPriority(1);
   176 	After(ETimeReq);
   177 	iLeave = ETrue;
   178 	iHandleLocally = aHandleLocally;
   179 	iLeaveInOOM = aLeaveInOOM;
   180 	//	STATIC_CAST(CMyRequestManager*,CActiveScheduler::Current())->ExpectError(!aHandleLocally);
   181 	STATIC_CAST(CMyRequestManager*,CActiveScheduler::Current())->SetMode(aMode);
   182 	}
   183 
   184 void CMyTimer::StopLeave()
   185 	{
   186 	iLeave=EFalse;
   187 	}
   188 
   189 void CMyTimer::StartImbalance()
   190 	{
   191 	iImbalance=ETrue;
   192 	}
   193 
   194 void CMyTimer::RunL()
   195 //
   196 // The timer has completed.
   197 //
   198 	{
   199 	if (iLeave) 
   200 		{
   201 		Deque(); // Test removal from scheduler
   202 		if (iLeaveInOOM)
   203 			{
   204 			__UHEAP_FAILNEXT(1);
   205 			}
   206 		User::Leave(KErrGeneral);
   207 		}
   208 	
   209 	// This switch is used when testing for imbalance in the cleanupstack
   210 	if(iImbalance)
   211 		{
   212 		if(iStopping)
   213 			{
   214 			
   215 			iStopping=EFalse;
   216 			//CleanupStack::PopAndDestroy(iDummy);
   217 			CActiveScheduler::Stop();
   218 			return;
   219 			}
   220 		else 
   221 			{
   222 			// Push something onto the stack, but dont take it off 
   223 			//- deal in CActiveScheduler::DoRunL
   224 			CleanupStack::PushL(iDummy);
   225 			iStopping=ETrue; //Stop the scheduler the next time
   226 			iCount=EMaxCount; 
   227 //			CActiveScheduler::Stop();
   228 			After(ETimeReq);
   229 			return;
   230 			}
   231 		}
   232 
   233 	iCount++;
   234 	SetPriority(iCount);
   235 	test.Printf(_L("\r%03d"),iCount);
   236 
   237 	if (iCount<EMaxCount)
   238 		After(ETimeReq);
   239 	else
   240 		{
   241 		test.Printf(_L("\n"));
   242 		CActiveScheduler::Stop();
   243 		Deque(); // Test removal from scheduler
   244 		iCount = 0;
   245 		}
   246 	}
   247 
   248 TInt CMyTimer::RunError(TInt aError)
   249 //
   250 // Handle leave from RunL
   251 //
   252 	{
   253 	if (iHandleLocally)
   254 		{
   255 		_LIT(KExpectError,"CMyTimer::RunError handling error %d\n");
   256 		test.Printf(KExpectError,aError);
   257 		CActiveScheduler::Stop();
   258 		return KErrNone;
   259 		}
   260 	else 
   261 		return aError; // Let the scheduler handle this error
   262 	}
   263 
   264 
   265 TInt DoImbalanceTest(TAny* /*aAny*/)
   266 // This function is the first executing fuction of the cleanupstack imbalace
   267 // testing thread - RunLCleanupImbalance
   268 // see ImbalanceTest()
   269 	{
   270 	// Set up cleanup stack & scheduler
   271 	RTest test(_L("Thread:RunLCleanupImbalance - DoImbalanceTest()"));
   272 	test.Start(_L("DoImbalanceTest()"));
   273 
   274 	//Create a cleanup stack and scheduler
   275 	CTrapCleanup::New();
   276 	CActiveScheduler* cas = new(ELeave) CActiveScheduler();
   277 	CActiveScheduler::Install(cas);
   278 
   279 	// Create a new AO.
   280 	CMyTimer* myTimer = CMyTimer::New();
   281 	myTimer->StopLeave();
   282 	myTimer->StartImbalance(); 
   283 	// Start the AO
   284 	test.Next(_L("Start Imblance Test"));
   285 	myTimer->Start();
   286 	
   287 	test.Next(_L("Start Scheduler"));
   288 	// The following is expected to panic (with EUSER-CBase 90 EClnCheckFailed)
   289 	cas->Start(); 
   290 	
   291 	delete myTimer;
   292 	delete cas;
   293 	test.End();
   294 	return 0;
   295 	}
   296 
   297 #ifdef _DEBUG
   298 LOCAL_C void ImbalanceTest()
   299 // this test will test whether the cleanup stack is imbalanced after
   300 // a runL of an Active object.
   301 	{
   302 	TBool imbalanced = ETrue;
   303 	User::SetJustInTime(EFalse);
   304 	RThread t;
   305 	TRequestStatus s;
   306 	test.Next(_L("Create a thread (RunLCleanupImbalance)"));
   307 	TInt r=t.Create(_L("RunLCleanupImbalance"),DoImbalanceTest,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,&imbalanced);
   308 	test(r==KErrNone);
   309 	t.Logon(s);
   310 	test.Next(_L("Resume and wait for panic (E32USER-CBase 90 EClnCheckFailed) due to imbalance"));
   311 	t.Resume();
   312 	User::WaitForRequest(s);
   313 	
   314 	test.Printf(_L("Exit Type %d\r\n"),(TInt)t.ExitType());
   315 	test.Printf(_L("Exit Reason %d\r\n"),(TInt)t.ExitReason());
   316 	
   317 	test(t.ExitReason()==EClnCheckFailed);
   318 	
   319 	CLOSE_AND_WAIT(t);
   320 
   321 	}
   322 #endif
   323 
   324 GLDEF_C TInt E32Main()
   325 //
   326 // Test timers.
   327 //
   328     {
   329  	test.Title();
   330 	test.Start(_L("Creating CActiveScheduler"));
   331 	CMyRequestManager* pR=new CMyRequestManager;
   332 	test(pR!=NULL);
   333 	CActiveScheduler::Install(pR);
   334 //
   335 	test.Next(_L("Testing relative timers"));
   336 	CMyTimer* pT=CMyTimer::New();
   337 	test(pT!=NULL);
   338 //
   339 	test.Next(_L("Start timer"));
   340 	pT->Start();
   341 //
   342 	test.Next(_L("Start CMyRequestManager"));
   343 	CActiveScheduler::Start();
   344 //
   345 	test.Next(_L("Start timer again"));
   346 	pT->Start();
   347 //
   348 	test.Next(_L("Start CMyRequestManager"));
   349 	CActiveScheduler::Start();
   350 //
   351 	test.Next(_L("Start timer, leave in RunL, handle in scheduler"));
   352 	pT->StartLeave(EFalse, EFalse, CMyRequestManager::EExpectError );
   353 //
   354 	test.Next(_L("Start CMyRequestManager"));
   355 	CActiveScheduler::Start();
   356 #ifdef _DEBUG
   357 //
   358 	test.Next(_L("Start timer, leave in RunL, generate nested exception under OOM condition"));
   359 	pT->StartLeave(EFalse, ETrue, CMyRequestManager::EGenerateException);
   360 //
   361 	test.Next(_L("Start CMyRequestManager"));
   362 	CActiveScheduler::Start();
   363 	__UHEAP_RESET;
   364 #endif
   365 	//
   366 	test.Next(_L("Start timer, leave in RunL, handle in object"));
   367 	pT->StartLeave(ETrue, EFalse, CMyRequestManager::EPanic);
   368 //
   369 	test.Next(_L("Start CMyRequestManager"));
   370 	CActiveScheduler::Start();
   371 //
   372 #ifdef _DEBUG
   373 // Test the cleanupstack imbalances
   374 	test.Next(_L("Test : Check Cleanupstack imbalance in RunL, handle(panic) in scheduler"));
   375 	ImbalanceTest();
   376 #endif
   377 //
   378 	test.End();
   379 	return(0); 
   380     }