kerneltest/e32test/active/t_act.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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     }