os/kernelhwsrv/kerneltest/e32test/system/t_ctrap.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\system\t_ctrap.cpp
    15 // Overview:
    16 // Test the CCleanup, CTrapCleanup and TAutoClose classes
    17 // API Information:
    18 // CCleanup, CTrapCleanup, TAutoClose
    19 // Details:
    20 // - Test cleanup stack reallocation during cleanup.
    21 // - Test cleanup stack modifications during the cleanup operation  
    22 // will cause a panic.
    23 // - Test single-level cleanup of cells, objects, items and a mix: 
    24 // Create a CCleanup object, call a combination of methods, verify 
    25 // the results are as expected and verify the heap has not been 
    26 // corrupted.
    27 // - Test multi-level cleanup of cells, objects, items and a mix: 
    28 // Create a CCleanup object, call a combination of methods, verify 
    29 // the results are as expected and verify the heap has not been 
    30 // corrupted.
    31 // - Test a variety of special case cleanup tasks. Verify that the 
    32 // results are as expected.
    33 // - Test CTrapCleanup cleanup of objects that either exit normally
    34 // or leave. Also test the cleanup of multiple objects that leave.
    35 // Verify results are as expected.
    36 // - Test TAutoClose: create a TAutoClose object, verify that it is 
    37 // closed when it goes out of scope, push it on the cleanup stack,
    38 // verify cleanup results are as expected.
    39 // - Test that the Cleanup stack can go re-entrant.
    40 // - Ensure that the stack is properly balanced with and without
    41 // leaving.
    42 // Platforms/Drives/Compatibility:
    43 // All.
    44 // Assumptions/Requirement/Pre-requisites:
    45 // Failures and causes:
    46 // Base Port information:
    47 // 
    48 //
    49 
    50 #define __E32TEST_EXTENSION__
    51 
    52 #include <e32test.h>
    53 #include <e32panic.h>
    54 #include <e32debug.h>
    55 #include <e32def.h>
    56 #include <e32def_private.h>
    57 
    58 
    59 const TInt KInitialCount=2;
    60 const TInt KInitialCountAll=3;
    61 const TInt KLeaveValue=0x12345678;
    62 const TInt KMaxAlloc=6;	
    63 
    64 static const TInt KHeapSize = 0x2000;
    65 
    66 enum TWhat {EPop,EPopAndDestroy,EMulti,ENull};
    67 
    68 class CTest : public CBase
    69 	{
    70 public:
    71 	void ConstructL();
    72 private:
    73 	TInt iData;
    74 	};
    75 	
    76 class CTest2: public CBase 
    77 	{
    78 public:
    79 	~CTest2();
    80 	};
    81 
    82 class CTest3: public CBase 
    83 	{
    84 public:
    85 	~CTest3();
    86 	};
    87 
    88 class RItem
    89 	{
    90 public:
    91 	RItem() : iOpen(EFalse) {}
    92 	void Open() {iOpen=ETrue;}
    93 	void Close() {iOpen=EFalse;}
    94 	operator TCleanupItem() {return TCleanupItem(Cleanup,this);}
    95 	TBool IsOpen() const {return(iOpen);}
    96 private:
    97 	static void Cleanup(TAny* aPtr);
    98 private:
    99 	TBool iOpen;
   100 	};
   101 
   102 LOCAL_D RTest test(_L("T_CTRAP"));
   103 LOCAL_D TAny* gP1;
   104 LOCAL_D CBufFlat* gP2;
   105 
   106 
   107 LOCAL_C void ReallocateStackL()
   108 	{
   109 	TInt n = 0;
   110 	for(TInt i = 0; i < KMaxAlloc; ++i)
   111 		{
   112 		HBufC *p1 = HBufC::NewLC(4);   //Stack re-allocation will be performed due to the additional objects pushed
   113 									   //into the cleanup stack
   114 		n = p1->Length();			   //include this line to avoid warnigs for unused "p1" variable
   115 		}
   116 	test.Printf(_L("ReallocateStackL(): PopAndDestroy KMaxAlloc pointers\n"));
   117 	CleanupStack::PopAndDestroy(KMaxAlloc);
   118 	}
   119 
   120 CTest2::~CTest2()
   121 	{
   122 	TInt err = KErrNoMemory;
   123 	
   124 	test.Printf(_L("~CTest2(): call ReallocateStackL()\n"));
   125 	
   126 	TRAP(err, ReallocateStackL() );
   127 	}
   128 
   129 CTest3::~CTest3()
   130 	{
   131 	RDebug::Printf("~CTest3(): Modify Cleanup stack by pushing items");
   132 	
   133 	TInt n = 0;
   134 	for(TInt i = 0; i < KMaxAlloc; ++i)
   135 		{
   136 		HBufC *p1 = HBufC::NewLC(4);   //Stack re-allocation will be performed due to the additional objects pushed
   137 									   //into the cleanup stack
   138 		n = p1->Length();			   //include this line to avoid warnigs for unused "p1" variable
   139 		}
   140 	}
   141 
   142 LOCAL_C void ModifyStack()
   143 	{
   144 	CTest3* ptr6 = new(ELeave)CTest3;
   145 	CleanupStack::PushL(ptr6);
   146 
   147 	RDebug::Printf("ModifyStack(): PopAndDestroy ptr6");
   148 	CleanupStack::PopAndDestroy();
   149 	}
   150 
   151 LOCAL_C TInt PanicStackModifiedFn(TAny* aNopFn)
   152 	{
   153 	__UHEAP_MARK;
   154 	CTrapCleanup* cleanup = CTrapCleanup::New();
   155 
   156 	aNopFn = NULL;		//avoid warnings for unused "aNopFn" variable
   157 
   158 	TInt err = KErrNoMemory;
   159 
   160 	RDebug::Printf("PanicStackModifiedFn(): call TRAP(err, ModifyStack())");
   161 
   162 	if(NULL != cleanup)
   163 		{
   164 		TRAP(err, ModifyStack());
   165 		delete cleanup;
   166 		}
   167 	__UHEAP_MARKEND;
   168 	return err;	
   169 	}
   170 
   171 LOCAL_C void PushAndCleanupL()
   172 	{
   173 	CTest2* ptr1 = new(ELeave)CTest2;
   174 	CleanupStack::PushL(ptr1);
   175 	
   176 	CTest2* ptr2 = new(ELeave)CTest2;
   177 	CleanupStack::PushL(ptr2);
   178 	
   179 	CTest2* ptr3 = new(ELeave)CTest2;
   180 	CleanupStack::PushL(ptr3);
   181 
   182 	test.Printf(_L("PushAndCleanupL(): PopAndDestroy ptr3, ptr2 and ptr1\n"));
   183 	CleanupStack::PopAndDestroy(3);
   184 
   185 	CTest2* ptr4 = new(ELeave)CTest2;
   186 	CleanupStack::PushL(ptr4);
   187 	
   188 	CTest2* ptr5 = new(ELeave)CTest2;
   189 	CleanupStack::PushL(ptr5);
   190 
   191 	test.Printf(_L("PushAndCleanupL(): PopAndDestroy ptr5 and ptr4\n"));
   192 	CleanupStack::PopAndDestroy();
   193 	CleanupStack::PopAndDestroy();
   194 	}
   195 
   196 LOCAL_C void testDestructorStackReallocation()
   197 	{
   198 	__UHEAP_MARK;
   199 	CTrapCleanup* cleanup = CTrapCleanup::New();
   200 	
   201 	TInt err = KErrNoMemory;
   202 	
   203 	if(NULL != cleanup)
   204 		{
   205 		TRAP(err, PushAndCleanupL());
   206 		delete cleanup;
   207 		}
   208 	__UHEAP_MARKEND;
   209 
   210 	test_KErrNone(err);
   211 
   212 	test.Printf(_L("Verify cleanup stack modification during cleanup operation causes EClnStackModified panic\n"));
   213 	
   214 	//
   215 	//To verify the above case a new thread is created which does modify the cleanup stack during cleanup.
   216 	//The exit reason is then checked for the appropriate value(EClnStackModified)
   217 	//
   218 
   219 	RThread panicThread;
   220 
   221 	TInt r = panicThread.Create(_L("Panic EClnStackModified Thread"), PanicStackModifiedFn, KDefaultStackSize, KHeapSize, KHeapSize, NULL);
   222 
   223 	test_KErrNone(r);
   224 
   225 	TRequestStatus panicThreadStatus;
   226 	panicThread.Logon(panicThreadStatus);
   227 
   228 	//don't want just in time debugging as we trap panics
   229 	TBool justInTime=User::JustInTime(); 
   230 	User::SetJustInTime(EFalse); 
   231 
   232 	panicThread.Resume();
   233 
   234 	User::WaitForRequest(panicThreadStatus);
   235 
   236 	test_Equal(EExitPanic, panicThread.ExitType());
   237 	test_Equal(EClnStackModified, panicThread.ExitReason());
   238 
   239 	User::SetJustInTime(justInTime);
   240 
   241 	CLOSE_AND_WAIT(panicThread);
   242 	}
   243 	
   244 LOCAL_C void createMultiL()
   245 //
   246 // Create an object on the cleanup list and leave
   247 //
   248 	{
   249 
   250 	CBufFlat* pT=CBufFlat::NewL(8);
   251 	User::LeaveIfNull(pT);
   252 	CleanupStack::PushL(pT);
   253 	__UHEAP_CHECK(3);
   254 	User::Leave(KLeaveValue+1);
   255 	}
   256 
   257 LOCAL_C void createL(TWhat aWhat,TBool aLeave)
   258 //
   259 // Create objects and then either leave or return.
   260 // Optionally pop them again.
   261 //
   262 	{
   263 
   264 	gP1=User::AllocL(0x10);
   265     test.Printf(_L("createL 1"));
   266 	CleanupStack::PushL(gP1);
   267     test.Printf(_L("createL 2"));
   268 	__UHEAP_CHECK(1);
   269     test.Printf(_L("createL 3"));
   270 	gP2=CBufFlat::NewL(8);
   271     test.Printf(_L("createL 4"));
   272 	User::LeaveIfNull(gP2);
   273     test.Printf(_L("createL 5"));
   274 	CleanupStack::PushL(gP2);
   275     test.Printf(_L("createL 6"));
   276 	__UHEAP_CHECK(2);
   277     test.Printf(_L("createL 7"));
   278 	if (aWhat==EPop)
   279 		{
   280 		test.Printf(_L("createL 8"));
   281 		CleanupStack::Pop();
   282 		test.Printf(_L("createL 9"));
   283 		CleanupStack::Pop(1);
   284 		test.Printf(_L("createL 10"));
   285 		}
   286 	if (aWhat==EPopAndDestroy)
   287 		{
   288 		test.Printf(_L("createL 11"));
   289 		CleanupStack::PopAndDestroy();
   290 		test.Printf(_L("createL 12"));
   291 		CleanupStack::PopAndDestroy(1);
   292 		test.Printf(_L("createL 13"));
   293 		}
   294 	if (aWhat==EMulti)
   295 		{
   296 		test.Printf(_L("createL 14"));
   297 		TRAPD(r,createMultiL())
   298 		test.Printf(_L("createL 15"));
   299 		test(r==(KLeaveValue+1));
   300 		test.Printf(_L("createL 16"));
   301 		__UHEAP_CHECK(2);
   302 		test.Printf(_L("createL 17"));
   303 		}
   304 	if (aLeave)
   305 		{
   306 		test.Printf(_L("createL 18"));
   307 		User::Leave(KLeaveValue);
   308 		}
   309     test.Printf(_L("createL 19"));
   310 	}
   311 
   312 LOCAL_C void createAllL(TBool aLeave)
   313 //
   314 // Call all functions which autmatically put objects on the cleanup list.
   315 //
   316 	{
   317 
   318 	__UHEAP_CHECK(KInitialCountAll);
   319 	TLex* pL=new(ELeave) TLex; // ::new, 1 cell
   320 	CleanupStack::PushL(pL);								// Push
   321 	__UHEAP_CHECK(KInitialCountAll+1);
   322 	CTest* pT=new(ELeave) CTest; // CBase::new, 1 cell
   323 	CleanupStack::PushL(pT);								// Push
   324 	__UHEAP_CHECK(KInitialCountAll+2);
   325 	pT->ConstructL(); // 1 more cell						// Push
   326 	__UHEAP_CHECK(KInitialCountAll+3);
   327 	User::AllocLC(0x10); // Test RHeap::AllocLC as well		// Push
   328 	__UHEAP_CHECK(KInitialCountAll+4);
   329 	_L("Hello").AllocLC(); // Test HBufC::NewLC() as well	// Push
   330 	__UHEAP_CHECK(KInitialCountAll+5);
   331 	HBufC* pH=HBufC::NewMaxLC(8);							// Push
   332 	test(pH->Length()==8);
   333 	__UHEAP_CHECK(KInitialCountAll+6);
   334 	if (aLeave)
   335 		User::Leave(KLeaveValue);
   336 	// new behavior for TCleanupTrapHander requires Pushes to the
   337 	// cleanup stack to be balanced by Pops
   338 	CleanupStack::PopAndDestroy(6);
   339 	}
   340 
   341 LOCAL_C void testSingleLevelCellsCleanup()
   342 //
   343 // Test single level cells cleanup
   344 //
   345 	{
   346 
   347 	test.Start(_L("Creating"));
   348 //
   349 	__UHEAP_MARK;
   350 	CCleanup* pC=CCleanup::New();
   351 	test(pC!=NULL);
   352 //
   353 	__UHEAP_MARK;
   354 //
   355 	test.Next(_L("PopAll when empty"));
   356 	pC->NextLevel();
   357 	pC->PopAll();
   358 	pC->NextLevel();
   359 	pC->PopAndDestroyAll();
   360 	__UHEAP_CHECK(0);
   361 //
   362 	test.Next(_L("Push and pop"));
   363 	TAny* p=User::Alloc(0x10);
   364 	test(p!=NULL);
   365 	__UHEAP_CHECK(1);
   366 	pC->NextLevel();
   367 	pC->PushL(p);
   368 	pC->Pop();
   369 	__UHEAP_CHECK(1);
   370 	User::Free(p);
   371 	__UHEAP_CHECK(0);
   372 	pC->PopAll();
   373 	__UHEAP_CHECK(0);
   374 //
   375 	test.Next(_L("Push and pop N"));
   376 	TAny* p1=User::Alloc(0x10);
   377 	test(p1!=NULL);
   378 	__UHEAP_CHECK(1);
   379 	TAny* p2=User::Alloc(0x10);
   380 	test(p2!=NULL);
   381 	__UHEAP_CHECK(2);
   382 	pC->NextLevel();
   383 	pC->PushL(p1);
   384 	pC->PushL(p2);
   385 	pC->Pop(2);
   386 	__UHEAP_CHECK(2);
   387 	User::Free(p1);
   388 	User::Free(p2);
   389 	__UHEAP_CHECK(0);
   390 	pC->PopAll();
   391 	__UHEAP_CHECK(0);
   392 //
   393 	test.Next(_L("Push and pop all"));
   394 	p1=User::Alloc(0x10);
   395 	test(p1!=NULL);
   396 	__UHEAP_CHECK(1);
   397 	p2=User::Alloc(0x10);
   398 	test(p2!=NULL);
   399 	__UHEAP_CHECK(2);
   400 	TAny* p3=User::Alloc(0x10);
   401 	test(p3!=NULL);
   402 	__UHEAP_CHECK(3);
   403 	pC->NextLevel();
   404 	pC->PushL(p1);
   405 	pC->PushL(p2);
   406 	pC->PushL(p3);
   407 	pC->PopAll();
   408 	__UHEAP_CHECK(3);
   409 	User::Free(p1);
   410 	User::Free(p2);
   411 	User::Free(p3);
   412 	__UHEAP_CHECK(0);
   413 //
   414 	test.Next(_L("Push and pop and destroy"));
   415 	p=User::Alloc(0x10);
   416 	test(p!=NULL);
   417 	__UHEAP_CHECK(1);
   418 	pC->NextLevel();
   419 	pC->PushL(p);
   420 	pC->PopAndDestroy();
   421 	__UHEAP_CHECK(0);
   422 	pC->PopAll();
   423 //
   424 	test.Next(_L("Push and pop and destroy N"));
   425 	p1=User::Alloc(0x10);
   426 	test(p1!=NULL);
   427 	__UHEAP_CHECK(1);
   428 	p2=User::Alloc(0x10);
   429 	test(p2!=NULL);
   430 	__UHEAP_CHECK(2);
   431 	pC->NextLevel();
   432 	pC->PushL(p1);
   433 	pC->PushL(p2);
   434 	pC->PopAndDestroy(2);
   435 	__UHEAP_CHECK(0);
   436 	pC->PopAll();
   437 	__UHEAP_CHECK(0);
   438 //
   439 	test.Next(_L("Push and pop and destroy all"));
   440 	p1=User::Alloc(0x10);
   441 	test(p1!=NULL);
   442 	__UHEAP_CHECK(1);
   443 	p2=User::Alloc(0x10);
   444 	test(p2!=NULL);
   445 	__UHEAP_CHECK(2);
   446 	p3=User::Alloc(0x10);
   447 	test(p3!=NULL);
   448 	__UHEAP_CHECK(3);
   449 	pC->NextLevel();
   450 	pC->PushL(p1);
   451 	pC->PushL(p2);
   452 	pC->PushL(p3);
   453 	pC->PopAndDestroyAll();
   454 	__UHEAP_CHECK(0);
   455 //
   456 	__UHEAP_MARKEND;
   457 //
   458 	delete pC;
   459 	__UHEAP_MARKEND;
   460 //
   461 	test.End();
   462 	}
   463 
   464 LOCAL_C void testSingleLevelObjCleanup()
   465 //
   466 // Test single level object cleanup
   467 //
   468 	{
   469 
   470 	test.Start(_L("Creating"));
   471 //
   472 	__UHEAP_MARK;
   473 	CCleanup* pC=CCleanup::New();
   474 	test(pC!=NULL);
   475 //
   476 	__UHEAP_MARK;
   477 //
   478 	test.Next(_L("Push and pop"));
   479 	CBufFlat* p=CBufFlat::NewL(8);
   480 	test(p!=NULL);
   481 	__UHEAP_CHECK(1);
   482 	pC->NextLevel();
   483 	pC->PushL(p);
   484 	pC->Pop();
   485 	__UHEAP_CHECK(1);
   486 	User::Free(p);
   487 	__UHEAP_CHECK(0);
   488 	pC->PopAll();
   489 	__UHEAP_CHECK(0);
   490 //
   491 	test.Next(_L("Push and pop N"));
   492 	CBufFlat* p1=CBufFlat::NewL(8);
   493 	test(p1!=NULL);
   494 	__UHEAP_CHECK(1);
   495 	CBufFlat* p2=CBufFlat::NewL(8);
   496 	test(p2!=NULL);
   497 	__UHEAP_CHECK(2);
   498 	pC->NextLevel();
   499 	pC->PushL(p1);
   500 	pC->PushL(p2);
   501 	pC->Pop(2);
   502 	__UHEAP_CHECK(2);
   503 	User::Free(p1);
   504 	User::Free(p2);
   505 	__UHEAP_CHECK(0);
   506 	pC->PopAll();
   507 	__UHEAP_CHECK(0);
   508 //
   509 	test.Next(_L("Push and pop all"));
   510 	p1=CBufFlat::NewL(8);
   511 	test(p1!=NULL);
   512 	__UHEAP_CHECK(1);
   513 	p2=CBufFlat::NewL(8);
   514 	test(p2!=NULL);
   515 	__UHEAP_CHECK(2);
   516 	CBufFlat* p3=CBufFlat::NewL(8);
   517 	test(p3!=NULL);
   518 	__UHEAP_CHECK(3);
   519 	pC->NextLevel();
   520 	pC->PushL(p1);
   521 	pC->PushL(p2);
   522 	pC->PushL(p3);
   523 	pC->PopAll();
   524 	__UHEAP_CHECK(3);
   525 	User::Free(p1);
   526 	User::Free(p2);
   527 	User::Free(p3);
   528 	__UHEAP_CHECK(0);
   529 //
   530 	test.Next(_L("Push and pop and destroy"));
   531 	p=CBufFlat::NewL(8);
   532 	test(p!=NULL);
   533 	__UHEAP_CHECK(1);
   534 	pC->NextLevel();
   535 	pC->PushL(p);
   536 	pC->PopAndDestroy();
   537 	__UHEAP_CHECK(0);
   538 	pC->PopAll();
   539 //
   540 	test.Next(_L("Push and pop and destroy N"));
   541 	p1=CBufFlat::NewL(8);
   542 	test(p1!=NULL);
   543 	__UHEAP_CHECK(1);
   544 	p2=CBufFlat::NewL(8);
   545 	test(p2!=NULL);
   546 	__UHEAP_CHECK(2);
   547 	pC->NextLevel();
   548 	pC->PushL(p1);
   549 	pC->PushL(p2);
   550 	pC->PopAndDestroy(2);
   551 	__UHEAP_CHECK(0);
   552 	pC->PopAll();
   553 	__UHEAP_CHECK(0);
   554 //
   555 	test.Next(_L("Push and pop and destroy all"));
   556 	p1=CBufFlat::NewL(8);
   557 	test(p1!=NULL);
   558 	__UHEAP_CHECK(1);
   559 	p2=CBufFlat::NewL(8);
   560 	test(p2!=NULL);
   561 	__UHEAP_CHECK(2);
   562 	p3=CBufFlat::NewL(8);
   563 	test(p3!=NULL);
   564 	__UHEAP_CHECK(3);
   565 	pC->NextLevel();
   566 	pC->PushL(p1);
   567 	pC->PushL(p2);
   568 	pC->PushL(p3);
   569 	pC->PopAndDestroyAll();
   570 	__UHEAP_CHECK(0);
   571 //
   572 	__UHEAP_MARKEND;
   573 //
   574 	delete pC;
   575 	__UHEAP_MARKEND;
   576 //
   577 	test.End();
   578 	}
   579 
   580 LOCAL_C void testSingleLevelItemCleanup()
   581 //
   582 // Test single level object cleanup
   583 //
   584 	{
   585 
   586 	test.Start(_L("Creating"));
   587 //
   588 	__UHEAP_MARK;
   589 	CCleanup* pC=CCleanup::New();
   590 	test(pC!=NULL);
   591 //
   592 	__UHEAP_MARK;
   593 //
   594 	test.Next(_L("Push and pop"));
   595 	RItem r;
   596 	r.Open();
   597 	test(r.IsOpen());
   598 	pC->NextLevel();
   599 	pC->PushL(r);
   600 	pC->Pop();
   601 	test(r.IsOpen());
   602 	r.Close();
   603 	test(!r.IsOpen());
   604 	pC->PopAll();
   605 //
   606 	test.Next(_L("Push and pop N"));
   607 	RItem r1;
   608 	r1.Open();
   609 	RItem r2;
   610 	r2.Open();
   611 	pC->NextLevel();
   612 	pC->PushL(r1);
   613 	pC->PushL(r2);
   614 	pC->Pop(2);
   615 	test(r1.IsOpen());
   616 	test(r2.IsOpen());
   617 	r1.Close();
   618 	r2.Close();
   619 	pC->PopAll();
   620 //
   621 	test.Next(_L("Push and pop all"));
   622 	r1.Open();
   623 	r2.Open();
   624 	RItem r3;
   625 	r3.Open();
   626 	pC->NextLevel();
   627 	pC->PushL(r1);
   628 	pC->PushL(r2);
   629 	pC->PushL(r3);
   630 	pC->PopAll();
   631 	test(r1.IsOpen());
   632 	test(r2.IsOpen());
   633 	test(r3.IsOpen());
   634 	r1.Close();
   635 	r2.Close();
   636 	r3.Close();
   637 //
   638 	test.Next(_L("Push and pop and destroy"));
   639 	r.Open();
   640 	pC->NextLevel();
   641 	pC->PushL(r);
   642 	pC->PopAndDestroy();
   643 	test(!r.IsOpen());
   644 	pC->PopAll();
   645 //
   646 	test.Next(_L("Push and pop and destroy N"));
   647 	r1.Open();
   648 	r2.Open();
   649 	pC->NextLevel();
   650 	pC->PushL(r1);
   651 	pC->PushL(r2);
   652 	pC->PopAndDestroy(2);
   653 	test(!r1.IsOpen());
   654 	test(!r2.IsOpen());
   655 	pC->PopAll();
   656 //
   657 	test.Next(_L("Push and pop and destroy all"));
   658 	r1.Open();
   659 	r2.Open();
   660 	r3.Open();
   661 	pC->NextLevel();
   662 	pC->PushL(r1);
   663 	pC->PushL(r2);
   664 	pC->PushL(r3);
   665 	pC->PopAndDestroyAll();
   666 	test(!r1.IsOpen());
   667 	test(!r2.IsOpen());
   668 	test(!r3.IsOpen());
   669 //
   670 	__UHEAP_MARKEND;
   671 //
   672 	delete pC;
   673 	__UHEAP_MARKEND;
   674 //
   675 	test.End();
   676 	}
   677 
   678 LOCAL_C void testSingleLevelMixCleanup()
   679 //
   680 // Test single level mixed cleanup
   681 //
   682 	{
   683 
   684 	test.Start(_L("Creating"));
   685 //
   686 	__UHEAP_MARK;
   687 	CCleanup* pC=CCleanup::New();
   688 	test(pC!=NULL);
   689 //
   690 	__UHEAP_MARK;
   691 //
   692 	test.Next(_L("PushO PushC PushI and pop N"));
   693 	CBufFlat* p1=CBufFlat::NewL(8);
   694 	test(p1!=NULL);
   695 	__UHEAP_CHECK(1);
   696 	TAny* p2=User::Alloc(0x10);
   697 	test(p2!=NULL);
   698 	__UHEAP_CHECK(2);
   699 	RItem r;
   700 	r.Open();
   701 	pC->NextLevel();
   702 	pC->PushL(p1);
   703 	pC->PushL(p2);
   704 	pC->PushL(r);
   705 	pC->Pop(3);
   706 	__UHEAP_CHECK(2);
   707 	test(r.IsOpen());
   708 	User::Free(p1);
   709 	User::Free(p2);
   710 	r.Close();
   711 	__UHEAP_CHECK(0);
   712 	pC->PopAll();
   713 	__UHEAP_CHECK(0);
   714 //
   715 	test.Next(_L("PushO PushI PushC PushO and pop all"));
   716 	p1=CBufFlat::NewL(8);
   717 	test(p1!=NULL);
   718 	__UHEAP_CHECK(1);
   719 	r.Open();
   720 	p2=User::Alloc(0x10);
   721 	test(p2!=NULL);
   722 	__UHEAP_CHECK(2);
   723 	CBufFlat* p3=CBufFlat::NewL(8);
   724 	test(p3!=NULL);
   725 	__UHEAP_CHECK(3);
   726 	pC->NextLevel();
   727 	pC->PushL(p1);
   728 	pC->PushL(r);
   729 	pC->PushL(p2);
   730 	pC->PushL(p3);
   731 	pC->PopAll();
   732 	__UHEAP_CHECK(3);
   733 	test(r.IsOpen());
   734 	User::Free(p1);
   735 	User::Free(p2);
   736 	User::Free(p3);
   737 	r.Close();
   738 	__UHEAP_CHECK(0);
   739 //
   740 	test.Next(_L("PushO PushC PushI and pop and destroy N"));
   741 	p1=CBufFlat::NewL(8);
   742 	test(p1!=NULL);
   743 	__UHEAP_CHECK(1);
   744 	p2=User::Alloc(0x10);
   745 	test(p2!=NULL);
   746 	__UHEAP_CHECK(2);
   747 	r.Open();
   748 	pC->NextLevel();
   749 	pC->PushL(p1);
   750 	pC->PushL(p2);
   751 	pC->PushL(r);
   752 	pC->PopAndDestroy(3);
   753 	test(!r.IsOpen());
   754 	__UHEAP_CHECK(0);
   755 	pC->PopAll();
   756 	__UHEAP_CHECK(0);
   757 //
   758 	test.Next(_L("PushO PushI PushC PushO and pop and destroy all"));
   759 	p1=CBufFlat::NewL(8);
   760 	test(p1!=NULL);
   761 	__UHEAP_CHECK(1);
   762 	r.Open();
   763 	p2=User::Alloc(0x10);
   764 	test(p2!=NULL);
   765 	__UHEAP_CHECK(2);
   766 	p3=CBufFlat::NewL(8);
   767 	test(p3!=NULL);
   768 	__UHEAP_CHECK(3);
   769 	pC->NextLevel();
   770 	pC->PushL(p1);
   771 	pC->PushL(r);
   772 	pC->PushL(p2);
   773 	pC->PushL(p3);
   774 	pC->PopAndDestroyAll();
   775 	test(!r.IsOpen());
   776 	__UHEAP_CHECK(0);
   777 //
   778 	__UHEAP_MARKEND;
   779 //
   780 	delete pC;
   781 	__UHEAP_MARKEND;
   782 //
   783 	test.End();
   784 	}
   785 
   786 LOCAL_C void testMultiLevelCellsCleanup()
   787 //
   788 // Test multi level cells cleanup
   789 //
   790 	{
   791 
   792 	test.Start(_L("Creating"));
   793 //
   794 	__UHEAP_MARK;
   795 	CCleanup* pC=CCleanup::New();
   796 	test(pC!=NULL);
   797 //
   798 	__UHEAP_MARK;
   799 //
   800 	test.Next(_L("Nest push push nest push popall popall"));
   801 	TAny* p1=User::Alloc(0x10);
   802 	test(p1!=NULL);
   803 	__UHEAP_CHECK(1);
   804 	TAny* p2=User::Alloc(0x10);
   805 	test(p2!=NULL);
   806 	__UHEAP_CHECK(2);
   807 	TAny* p3=User::Alloc(0x10);
   808 	test(p3!=NULL);
   809 	__UHEAP_CHECK(3);
   810 	pC->NextLevel();
   811 	pC->PushL(p1);
   812 	pC->PushL(p2);
   813 	pC->NextLevel();
   814 	pC->PushL(p3);
   815 	pC->PopAll();
   816 	__UHEAP_CHECK(3);
   817 	pC->PopAll();
   818 	__UHEAP_CHECK(3);
   819 	User::Free(p1);
   820 	User::Free(p2);
   821 	User::Free(p3);
   822 	__UHEAP_CHECK(0);
   823 //
   824 	test.Next(_L("Nest push push nest push popallD popallD"));
   825 	p1=User::Alloc(0x10);
   826 	test(p1!=NULL);
   827 	__UHEAP_CHECK(1);
   828 	p2=User::Alloc(0x10);
   829 	test(p2!=NULL);
   830 	__UHEAP_CHECK(2);
   831 	p3=User::Alloc(0x10);
   832 	test(p3!=NULL);
   833 	__UHEAP_CHECK(3);
   834 	pC->NextLevel();
   835 	pC->PushL(p1);
   836 	pC->PushL(p2);
   837 	pC->NextLevel();
   838 	pC->PushL(p3);
   839 	pC->PopAndDestroyAll();
   840 	__UHEAP_CHECK(2);
   841 	pC->PopAndDestroyAll();
   842 	__UHEAP_CHECK(0);
   843 //
   844 	__UHEAP_MARKEND;
   845 //
   846 	delete pC;
   847 	__UHEAP_MARKEND;
   848 //
   849 	test.End();
   850 	}
   851 
   852 LOCAL_C void testMultiLevelObjCleanup()
   853 //
   854 // Test multi level object cleanup
   855 //
   856 	{
   857 
   858 	test.Start(_L("Creating"));
   859 //
   860 	__UHEAP_MARK;
   861 	CCleanup* pC=CCleanup::New();
   862 	test(pC!=NULL);
   863 //
   864 	__UHEAP_MARK;
   865 //
   866 	test.Next(_L("Nest push push nest push popall popall"));
   867 	CBufFlat* p1=CBufFlat::NewL(8);
   868 	test(p1!=NULL);
   869 	__UHEAP_CHECK(1);
   870 	CBufFlat* p2=CBufFlat::NewL(8);
   871 	test(p2!=NULL);
   872 	__UHEAP_CHECK(2);
   873 	CBufFlat* p3=CBufFlat::NewL(8);
   874 	test(p3!=NULL);
   875 	__UHEAP_CHECK(3);
   876 	pC->NextLevel();
   877 	pC->PushL(p1);
   878 	pC->PushL(p2);
   879 	pC->NextLevel();
   880 	pC->PushL(p3);
   881 	pC->PopAll();
   882 	__UHEAP_CHECK(3);
   883 	pC->PopAll();
   884 	__UHEAP_CHECK(3);
   885 	User::Free(p1);
   886 	User::Free(p2);
   887 	User::Free(p3);
   888 	__UHEAP_CHECK(0);
   889 //
   890 	test.Next(_L("Nest push push nest push popallD popallD"));
   891 	p1=CBufFlat::NewL(8);
   892 	test(p1!=NULL);
   893 	__UHEAP_CHECK(1);
   894 	p2=CBufFlat::NewL(8);
   895 	test(p2!=NULL);
   896 	__UHEAP_CHECK(2);
   897 	p3=CBufFlat::NewL(8);
   898 	test(p3!=NULL);
   899 	__UHEAP_CHECK(3);
   900 	pC->NextLevel();
   901 	pC->PushL(p1);
   902 	pC->PushL(p2);
   903 	pC->NextLevel();
   904 	pC->PushL(p3);
   905 	pC->PopAndDestroyAll();
   906 	__UHEAP_CHECK(2);
   907 	pC->PopAndDestroyAll();
   908 	__UHEAP_CHECK(0);
   909 //
   910 	__UHEAP_MARKEND;
   911 //
   912 	delete pC;
   913 	__UHEAP_MARKEND;
   914 //
   915 	test.End();
   916 	}
   917 
   918 LOCAL_C void testMultiLevelItemCleanup()
   919 //
   920 // Test multi level item cleanup
   921 //
   922 	{
   923 
   924 	test.Start(_L("Creating"));
   925 //
   926 	__UHEAP_MARK;
   927 	CCleanup* pC=CCleanup::New();
   928 	test(pC!=NULL);
   929 //
   930 	__UHEAP_MARK;
   931 //
   932 	test.Next(_L("Nest push push nest push popall popall"));
   933 	RItem r1;
   934 	r1.Open();
   935 	RItem r2;
   936 	r2.Open();
   937 	RItem r3;
   938 	r3.Open();
   939 	pC->NextLevel();
   940 	pC->PushL(r1);
   941 	pC->PushL(r2);
   942 	pC->NextLevel();
   943 	pC->PushL(r3);
   944 	pC->PopAll();
   945 	test(r1.IsOpen());
   946 	test(r2.IsOpen());
   947 	test(r3.IsOpen());
   948 	pC->PopAll();
   949 	test(r1.IsOpen());
   950 	test(r2.IsOpen());
   951 	test(r3.IsOpen());
   952 	r1.Close();
   953 	r2.Close();
   954 	r3.Close();
   955 //
   956 	test.Next(_L("Nest push push nest push popallD popallD"));
   957 	r1.Open();
   958 	r2.Open();
   959 	r3.Open();
   960 	pC->NextLevel();
   961 	pC->PushL(r1);
   962 	pC->PushL(r2);
   963 	pC->NextLevel();
   964 	pC->PushL(r3);
   965 	pC->PopAndDestroyAll();
   966 	test(r1.IsOpen());
   967 	test(r2.IsOpen());
   968 	test(!r3.IsOpen());
   969 	pC->PopAndDestroyAll();
   970 	test(!r1.IsOpen());
   971 	test(!r2.IsOpen());
   972 	test(!r3.IsOpen());
   973 //
   974 	__UHEAP_MARKEND;
   975 //
   976 	delete pC;
   977 	__UHEAP_MARKEND;
   978 //
   979 	test.End();
   980 	}
   981 
   982 LOCAL_C void testMultiLevelMixCleanup()
   983 //
   984 // Test multi level mixed cleanup
   985 //
   986 	{
   987 
   988 	test.Start(_L("Creating"));
   989 //
   990 	__UHEAP_MARK;
   991 	CCleanup* pC=CCleanup::New();
   992 	test(pC!=NULL);
   993 //
   994 	__UHEAP_MARK;
   995 //
   996 	test.Next(_L("Nest pushO pushC nest pushI popall popall"));
   997 	CBufFlat* p1=CBufFlat::NewL(8);
   998 	test(p1!=NULL);
   999 	__UHEAP_CHECK(1);
  1000 	TAny* p2=User::Alloc(0x10);
  1001 	test(p2!=NULL);
  1002 	__UHEAP_CHECK(2);
  1003 	RItem r3;
  1004 	r3.Open();
  1005 	pC->NextLevel();
  1006 	pC->PushL(p1);
  1007 	pC->PushL(p2);
  1008 	pC->NextLevel();
  1009 	pC->PushL(r3);
  1010 	pC->PopAll();
  1011 	__UHEAP_CHECK(2);
  1012 	test(r3.IsOpen());
  1013 	pC->PopAll();
  1014 	__UHEAP_CHECK(2);
  1015 	test(r3.IsOpen());
  1016 	User::Free(p1);
  1017 	User::Free(p2);
  1018 	r3.Close();
  1019 	__UHEAP_CHECK(0);
  1020 //
  1021 	test.Next(_L("Nest pushO pushC nest pushI popallD popallD"));
  1022 	p1=CBufFlat::NewL(8);
  1023 	test(p1!=NULL);
  1024 	__UHEAP_CHECK(1);
  1025 	p2=User::Alloc(0x10);
  1026 	test(p2!=NULL);
  1027 	__UHEAP_CHECK(2);
  1028 	r3.Open();
  1029 	pC->NextLevel();
  1030 	pC->PushL(p1);
  1031 	pC->PushL(p2);
  1032 	pC->NextLevel();
  1033 	pC->PushL(r3);
  1034 	pC->PopAndDestroyAll();
  1035 	__UHEAP_CHECK(2);
  1036 	test(!r3.IsOpen());
  1037 	pC->PopAndDestroyAll();
  1038 	test(!r3.IsOpen());
  1039 	__UHEAP_CHECK(0);
  1040 //
  1041 	__UHEAP_MARKEND;
  1042 //
  1043 	delete pC;
  1044 	__UHEAP_MARKEND;
  1045 //
  1046 	test.End();
  1047 	}
  1048 
  1049 LOCAL_C void testSpecialCaseCleanup()
  1050 //
  1051 // Test special case cleanup
  1052 //
  1053 	{
  1054 
  1055 	test.Start(_L("Creating"));
  1056 //
  1057 	__UHEAP_MARK;
  1058 	CCleanup* pC=CCleanup::New();
  1059 	test(pC!=NULL);
  1060 	__UHEAP_CHECK(KInitialCount);
  1061 //
  1062 	test.Next(_L("Nest push push push fail"));
  1063 	CBufFlat* p1=CBufFlat::NewL(8);
  1064 	test(p1!=NULL);
  1065 	__UHEAP_CHECK(KInitialCount+1);
  1066 	CBufFlat* p2=CBufFlat::NewL(8);
  1067 	test(p2!=NULL);
  1068 	__UHEAP_CHECK(KInitialCount+2);
  1069 	CBufFlat* p3=CBufFlat::NewL(8);
  1070 	test(p3!=NULL);
  1071 	__UHEAP_CHECK(KInitialCount+3);
  1072 	CBufFlat* p4=CBufFlat::NewL(8);
  1073 	test(p4!=NULL);
  1074 	__UHEAP_CHECK(KInitialCount+4);
  1075 	CBufFlat* p5=CBufFlat::NewL(8);
  1076 	test(p5!=NULL);
  1077 	__UHEAP_CHECK(KInitialCount+5);
  1078 	CBufFlat* p6=CBufFlat::NewL(8);
  1079 	test(p6!=NULL);
  1080 	__UHEAP_CHECK(KInitialCount+6);
  1081 	pC->NextLevel();
  1082 	pC->PushL(p1);
  1083 	pC->PushL(p2);
  1084 	pC->PushL(p3);
  1085 	pC->PushL(p4);
  1086 	pC->PushL(p5);
  1087 //
  1088 // The granularity is 4 so this should try and grow the array
  1089 // since room is always made for a free slot. We set the allocator
  1090 // to fail so that we can test that the free slot is re-established
  1091 // when we do the cleanup. This test only works in debug mode.
  1092 //
  1093 	__UHEAP_FAILNEXT(1);
  1094 	TRAPD(r,pC->PushL(p6));
  1095 #if defined(_DEBUG)
  1096 	test(r==KErrNoMemory);
  1097 #endif
  1098 	__UHEAP_CHECK(KInitialCount+6);
  1099 	pC->PopAndDestroyAll();
  1100 	__UHEAP_CHECK(KInitialCount);
  1101 //
  1102 	test.Next(_L("Nest push push push push popallD"));
  1103 	p1=CBufFlat::NewL(8);
  1104 	test(p1!=NULL);
  1105 	__UHEAP_CHECK(KInitialCount+1);
  1106 	p2=CBufFlat::NewL(8);
  1107 	test(p2!=NULL);
  1108 	__UHEAP_CHECK(KInitialCount+2);
  1109 	p3=CBufFlat::NewL(8);
  1110 	test(p3!=NULL);
  1111 	__UHEAP_CHECK(KInitialCount+3);
  1112 	p4=CBufFlat::NewL(8);
  1113 	test(p4!=NULL);
  1114 	__UHEAP_CHECK(KInitialCount+4);
  1115 	pC->NextLevel();
  1116 	pC->PushL(p1);
  1117 	pC->NextLevel();
  1118 	pC->PushL(p2);
  1119 	pC->PushL(p3);
  1120 	pC->PushL(p4);
  1121 	pC->PopAndDestroyAll();
  1122 	__UHEAP_CHECK(KInitialCount+1);
  1123 	pC->PopAndDestroyAll();
  1124 	__UHEAP_CHECK(KInitialCount);
  1125 //
  1126 	test.Next(_L("Destroy cleanup object"));
  1127 //
  1128 	p1=CBufFlat::NewL(8);
  1129 	test(p1!=NULL);
  1130 	__UHEAP_CHECK(KInitialCount+1);
  1131 	p2=CBufFlat::NewL(8);
  1132 	test(p2!=NULL);
  1133 	__UHEAP_CHECK(KInitialCount+2);
  1134 	p3=CBufFlat::NewL(8);
  1135 	test(p3!=NULL);
  1136 	__UHEAP_CHECK(KInitialCount+3);
  1137 	p4=CBufFlat::NewL(8);
  1138 	test(p4!=NULL);
  1139 	__UHEAP_CHECK(KInitialCount+4);
  1140 	pC->NextLevel();
  1141 	pC->PushL(p1);
  1142 	pC->NextLevel();
  1143 	pC->PushL(p2);
  1144 	pC->PushL(p3);
  1145 	pC->PushL(p4);
  1146 	delete pC;
  1147 	__UHEAP_CHECK(0);
  1148 //
  1149 	__UHEAP_MARKEND;
  1150 //
  1151 	test.End();
  1152 	}
  1153 
  1154 LOCAL_C void testUnTrap()
  1155 //
  1156 // Test cleanup with normal exits
  1157 //
  1158 	{
  1159 
  1160 	test.Start(_L("Creating"));
  1161 //
  1162 	__UHEAP_MARK;
  1163 	CTrapCleanup* pT=CTrapCleanup::New();
  1164 	test(pT!=NULL);
  1165 	__UHEAP_CHECK(KInitialCountAll);
  1166 //
  1167 	__UHEAP_MARK;
  1168 //
  1169 	test.Next(_L("PushC PushO EPop cleanup empty"));
  1170 	TRAPD(r,createL(EPop,EFalse))
  1171 	test.Next(_L("PushC PushO EPop cleanup empty 1"));
  1172 	test(r==KErrNone);
  1173 	test.Next(_L("PushC PushO EPop cleanup empty 2"));
  1174 	__UHEAP_CHECK(2);
  1175 	test.Next(_L("PushC PushO EPop cleanup empty 3"));
  1176 	User::Free(gP1);
  1177 	test.Next(_L("PushC PushO EPop cleanup empty 4"));
  1178 	delete gP2;
  1179 	test.Next(_L("PushC PushO EPop cleanup empty 5"));
  1180 	__UHEAP_CHECK(0);
  1181 //
  1182 	test.Next(_L("PushC PushO EPopAndDestroy cleanup empty"));
  1183 	TRAP(r,createL(EPopAndDestroy,EFalse))
  1184 	test(r==KErrNone);
  1185 	__UHEAP_CHECK(0);
  1186 //
  1187 /*
  1188 // Change of behavior for TCleanupTrapHandler means that the current
  1189 // cleanup stack must be empty when UnTrap is called. IE. calls to
  1190 // Push should be balanced with a Pop within the same function.
  1191 	test.Next(_L("PushC PushO ENull cleanup 2 objects"));
  1192 	TRAP(r,createL(ENull,EFalse))
  1193 	test(r==KErrNone);
  1194 	__UHEAP_CHECK(0);
  1195 */
  1196 	__UHEAP_MARKEND;
  1197 //
  1198 	test.Next(_L("Test all LC functions"));
  1199 	TRAP(r,createAllL(EFalse))
  1200 	test(r==KErrNone);
  1201 	__UHEAP_CHECK(KInitialCountAll);
  1202 //
  1203 	delete pT;
  1204 	__UHEAP_MARKEND;
  1205 //
  1206 	test.End();
  1207 	}
  1208 
  1209 LOCAL_C void testLeave()
  1210 //
  1211 // Test cleanup with leave exits
  1212 //
  1213 	{
  1214 
  1215 	test.Start(_L("Creating"));
  1216 //
  1217 	__UHEAP_MARK;
  1218 	CTrapCleanup* pT=CTrapCleanup::New();
  1219 	test(pT!=NULL);
  1220 	__UHEAP_CHECK(KInitialCountAll);
  1221 //
  1222 	__UHEAP_MARK;
  1223 //
  1224 	test.Next(_L("PushC PushO EPop cleanup empty and leave"));
  1225 	TRAPD(r,createL(EPop,ETrue))
  1226 	test(r==KLeaveValue);
  1227 	__UHEAP_CHECK(2);
  1228 	User::Free(gP1);
  1229 	delete gP2;
  1230 	__UHEAP_CHECK(0);
  1231 //
  1232 	test.Next(_L("PushC PushO EPopAndDestroy cleanup empty and leave"));
  1233 	TRAP(r,createL(EPopAndDestroy,ETrue))
  1234 	test(r==KLeaveValue);
  1235 	__UHEAP_CHECK(0);
  1236 //
  1237 	test.Next(_L("PushC PushO ENull cleanup 2 objects and leave"));
  1238 	TRAP(r,createL(ENull,ETrue))
  1239 	test(r==KLeaveValue);
  1240 	__UHEAP_CHECK(0);
  1241 	__UHEAP_MARKEND;
  1242 //
  1243 	test.Next(_L("Test all LC functions and leave"));
  1244 	TRAP(r,createAllL(ETrue))
  1245 	test(r==KLeaveValue);
  1246 	__UHEAP_CHECK(KInitialCountAll);
  1247 //
  1248 	delete pT;
  1249 	__UHEAP_MARKEND;
  1250 //
  1251 	test.End();
  1252 	}
  1253 
  1254 LOCAL_C void testMultiLeave()
  1255 //
  1256 // Test cleanup with multiple leave exits
  1257 //
  1258 	{
  1259 
  1260 	test.Start(_L("Creating"));
  1261 //
  1262 	__UHEAP_MARK;
  1263 	CTrapCleanup* pT=CTrapCleanup::New();
  1264 	test(pT!=NULL);
  1265 //
  1266 	__UHEAP_MARK;
  1267 //
  1268 	test.Next(_L("PushC PushO nest PushO cleanup leave leave"));
  1269 	TRAPD(r,createL(EMulti,ETrue))
  1270 	test(r==KLeaveValue);
  1271 	__UHEAP_CHECK(0);
  1272 	__UHEAP_MARKEND;
  1273 //
  1274 	delete pT;
  1275 	__UHEAP_MARKEND;
  1276 //
  1277 	test.End();
  1278 	}
  1279 
  1280 LOCAL_C void addNullItemL()
  1281 	{
  1282 	CleanupStack::PushL((TAny*)0);
  1283 	}
  1284 
  1285 LOCAL_C void addCellL()
  1286 	{
  1287 	User::AllocLC(4);
  1288 	}
  1289 
  1290 LOCAL_C void useCleanupStackL()
  1291 	{
  1292 	addNullItemL();
  1293 	addCellL();
  1294 	CleanupStack::PopAndDestroy();
  1295 	CleanupStack::Pop();
  1296 	}
  1297 
  1298 LOCAL_C void reentrantCleanup(TAny*)
  1299 //
  1300 // A cleanup operation which uses a trap harness and the cleanup stack
  1301 //
  1302 	{
  1303 	TRAPD(ignore,useCleanupStackL())
  1304 	}
  1305 
  1306 LOCAL_C void addReentrantItemL()
  1307 	{
  1308 	CleanupStack::PushL(TCleanupItem(reentrantCleanup));
  1309 	}
  1310 
  1311 LOCAL_C void addItemsL(TInt aCount)
  1312 //
  1313 // add number of reentrant items to make stack fail
  1314 //
  1315 	{
  1316 	while (--aCount>=0)
  1317 		addReentrantItemL();
  1318 #if !defined(_DEBUG)
  1319 	User::Leave(KErrNoMemory);	// heap failure not available
  1320 #endif
  1321 	}
  1322 
  1323 const TInt KInitialStackSize=8;	// from UC_CLN.CPP
  1324 const TInt KGrowItems=KInitialStackSize-3;
  1325 
  1326 LOCAL_C void testReentrancyL()
  1327 //
  1328 // Test the Cleanup stack can go re-entrant
  1329 //
  1330 	{
  1331 
  1332 	test.Next(_L("PopAndDestroy()"));
  1333 	__UHEAP_MARK;
  1334 	addNullItemL();
  1335 	addCellL();
  1336 	addReentrantItemL();
  1337 	CleanupStack::PopAndDestroy(2);
  1338 	CleanupStack::Pop();
  1339 	__UHEAP_MARKEND;
  1340 //
  1341 	test.Next(_L("cleanup after a leave"));
  1342 	addNullItemL();
  1343 	TRAPD(r,addReentrantItemL();User::Leave(KLeaveValue);)
  1344 	test(r==KLeaveValue);
  1345 	CleanupStack::Pop();
  1346 //
  1347 	test.Next(_L("cleanup after stack failure"));
  1348 	// Ensuring stack reallocate fails by placing following cell
  1349 	TInt* forceAlloc=(TInt*)User::AllocL(4);
  1350 	for (TInt i=0;i<KGrowItems;++i)
  1351 		addNullItemL();
  1352 	__UHEAP_SETFAIL(RHeap::EDeterministic,1);	// fail everything 
  1353 	TRAP(r,addItemsL(1);)	// will leave as stack full and cannot grow
  1354 	test(r==KErrNoMemory);
  1355 	__UHEAP_RESET;
  1356 	CleanupStack::Pop(KGrowItems);
  1357 //
  1358 	test.Next(_L("multiple re-entrancy & stack failure"));
  1359 	__UHEAP_SETFAIL(RHeap::EDeterministic,1);	// fail everything
  1360 	TRAP(r,addItemsL(KGrowItems+1););
  1361 	test(r==KErrNoMemory);
  1362 	__UHEAP_RESET;
  1363 	User::Free(forceAlloc);
  1364 	}
  1365 
  1366 LOCAL_C void testReentrancy()
  1367 //
  1368 // Test the Cleanup stack can go re-entrant
  1369 //
  1370 	{
  1371 
  1372 	test.Start(_L("Creating"));
  1373 //
  1374 	__UHEAP_MARK;
  1375 	CTrapCleanup* pT=CTrapCleanup::New();
  1376 	test(pT!=NULL);
  1377 //
  1378 	TRAPD(r,testReentrancyL());
  1379 	test(r==KErrNone);
  1380 //
  1381 	delete pT;
  1382 	__UHEAP_MARKEND;
  1383 //
  1384 	test.End();
  1385 	}
  1386 
  1387 LOCAL_C void testAutoCloseL()
  1388 //
  1389 // A leaving function for testAutoClose()
  1390 //
  1391 	{
  1392 	test.Next(_L("Create a TAutoClose object"));
  1393 	TAutoClose<RTimer> tim;
  1394 	tim.iObj.CreateLocal();
  1395 	test.Next(_L("Push it on the cleanup stack"));
  1396 	tim.PushL();
  1397 	test.Next(_L("Leave before object goes out of scope"));
  1398 	User::Leave(KErrGeneral);
  1399 	tim.Pop();
  1400 	}
  1401 
  1402 LOCAL_C void testAutoClose()
  1403 //
  1404 // Test the TAutoClose class
  1405 //
  1406 	{
  1407 
  1408 	// Kill the granules
  1409 	RTimer s[20];
  1410 	TInt i;
  1411 	for (i=0; i<20; i++)
  1412 		s[i].CreateLocal();
  1413 	for (i=0; i<20; i++)
  1414 		s[i].Close();
  1415 
  1416 	__KHEAP_MARK;
  1417 	test.Start(_L("Make a TAutoClose object"));
  1418 		{
  1419 		TAutoClose<RTimer> tim;
  1420 		tim.iObj.CreateLocal();
  1421 
  1422 		test.Next(_L("Let it fall out of scope"));
  1423 		}
  1424 	test.Next(_L("Check the object has closed"));
  1425 	__KHEAP_CHECK(0);
  1426 
  1427 	TRAPD(r, testAutoCloseL());
  1428 	test.Next(_L("Check object has been closed and cleaned up after leave"));
  1429 	__KHEAP_MARKEND;
  1430 	test.End();
  1431 	}
  1432 
  1433 void CTest::ConstructL()
  1434 //
  1435 // Allocate a cell with CBase::new
  1436 //
  1437 	{
  1438 
  1439 	TLex* pL=new(ELeave) TLex;
  1440 	CleanupStack::PushL(pL);
  1441 	}
  1442 
  1443 void RItem::Cleanup(TAny* aPtr)
  1444 //
  1445 // Invoke the Close member on the RItem at aPtr
  1446 //
  1447 	{							
  1448 
  1449 	((RItem*)aPtr)->Close();
  1450 	}
  1451 
  1452 LOCAL_C TInt getStackPointer()
  1453 	{
  1454 	static TUint8 there;
  1455 	TUint8 here;
  1456 	return &here-&there;
  1457 	}
  1458 LOCAL_C void sheLeavesMeL(TBool sheLeavesMeNot)
  1459 	{
  1460 	if (!sheLeavesMeNot)
  1461 		User::Leave(KErrBadName);	// Montague
  1462 	}
  1463 
  1464 // Variables for stack balance test need to be global or clever compiler optimisations
  1465 // Can interfere with stack balance calculations.
  1466 TInt StackBalanceLoopCounter;
  1467 TInt StackBalanceResult=KErrNone;
  1468 TInt StackBalanceBefore;
  1469 TInt StackBalanceAfter;
  1470 
  1471 // Split into two functions because x86gcc makes a local stack optimisation for the second
  1472 // loop which unbalances the stack frame of the first loop.
  1473 LOCAL_C TInt StackBalanceNotLeaving()
  1474 	{
  1475 	StackBalanceBefore=getStackPointer();
  1476 	for (StackBalanceLoopCounter=0; StackBalanceLoopCounter<20;StackBalanceLoopCounter++)
  1477 		{
  1478 		TRAP(StackBalanceResult,sheLeavesMeL(ETrue));
  1479 		}
  1480 	StackBalanceAfter=getStackPointer();
  1481 	return StackBalanceAfter-StackBalanceBefore;
  1482 	}
  1483 LOCAL_C TInt StackBalanceLeaving()
  1484 	{
  1485 	StackBalanceBefore=getStackPointer();
  1486 	for (StackBalanceLoopCounter=0; StackBalanceLoopCounter<20;StackBalanceLoopCounter++)
  1487 		{
  1488 		TRAP(StackBalanceResult,sheLeavesMeL(EFalse));
  1489 		}
  1490 	StackBalanceAfter=getStackPointer();
  1491 	return StackBalanceAfter-StackBalanceBefore;
  1492 	}
  1493 
  1494 LOCAL_C void testStackBalance()
  1495 //
  1496 // Ensure that we get the stack properly balanced
  1497 //
  1498 	{
  1499 	// Not leaving case
  1500 	test.Start(_L("Stack balance without Leaving"));
  1501 	TInt balance = StackBalanceNotLeaving();
  1502 	test.Printf(_L("Stack balance: %d bytes\n"), balance);
  1503 	test(balance == 0);
  1504 
  1505 	// Leaving case
  1506 	test.Next(_L("Stack balance after Leave"));
  1507 	balance = StackBalanceLeaving();
  1508 	test.Printf(_L("Stack balance: %d bytes\n"), balance);
  1509 	test(balance == 0);
  1510 	test.End();
  1511 	}
  1512 
  1513 void Inc(TAny* aPtr)
  1514 	{
  1515 	++(*(TInt*)aPtr);
  1516 	}
  1517 
  1518 void testTrapIgnore()
  1519 	{
  1520 	test.Start(_L("Create cleanup"));
  1521 	CCleanup* pC=CCleanup::New();
  1522 	test(pC!=NULL);
  1523 	TInt count = 0;
  1524 
  1525 	test.Next(_L("TRAP_IGNORE with no leave"));
  1526 	TRAP_IGNORE(
  1527 		CleanupStack::PushL(TCleanupItem(Inc,&count));
  1528 		CleanupStack::Pop();
  1529 		);
  1530 	test(count==0);
  1531 
  1532 	test.Next(_L("TRAP_IGNORE with leave"));
  1533 	TRAP_IGNORE(
  1534 		CleanupStack::PushL(TCleanupItem(Inc,&count));
  1535 		User::Leave(KErrGeneral);
  1536 		);
  1537 	test(count==1);
  1538 
  1539 	delete pC;
  1540 	test.End();
  1541 	}
  1542 
  1543 GLDEF_C TInt E32Main()
  1544     {
  1545 	test.Title();
  1546 	
  1547 	test.Start(_L("Test destructor causing stack reallocation"));
  1548 	testDestructorStackReallocation();	
  1549 	
  1550 	test.Next(_L("CCleanup single level tests just alloc cells"));
  1551 	testSingleLevelCellsCleanup();
  1552 
  1553 	test.Next(_L("CCleanup single level tests just objects"));
  1554 	testSingleLevelObjCleanup();
  1555 
  1556 	test.Next(_L("CCleanup single level tests just items"));
  1557 	testSingleLevelItemCleanup();
  1558 
  1559 	test.Next(_L("CCleanup single level tests mixed"));
  1560 	testSingleLevelMixCleanup();
  1561 
  1562 	test.Next(_L("CCleanup multi level tests just alloc cells"));
  1563 	testMultiLevelCellsCleanup();
  1564 
  1565 	test.Next(_L("CCleanup multi level tests just objects"));
  1566 	testMultiLevelObjCleanup();
  1567 
  1568 	test.Next(_L("CCleanup multi level tests just items"));
  1569 	testMultiLevelItemCleanup();
  1570 
  1571 	test.Next(_L("CCleanup multi level tests mixed"));
  1572 	testMultiLevelMixCleanup();
  1573 
  1574 	test.Next(_L("CCleanup special case test"));
  1575 	testSpecialCaseCleanup();
  1576 
  1577 	test.Next(_L("Install trap handler"));
  1578 	CTrapCleanup* pT=CTrapCleanup::New();
  1579 	test(pT!=NULL);
  1580 
  1581 	test.Next(_L("Untrap handling tests"));
  1582 	testUnTrap();
  1583 
  1584 	test.Next(_L("Leave handling tests"));
  1585 	testLeave();
  1586 
  1587 	test.Next(_L("Multi level leave handling tests"));
  1588 	testMultiLeave();
  1589 
  1590 	test.Next(_L("Test TAutoClose"));
  1591 	testAutoClose();
  1592 
  1593 	test.Next(_L("Test Re-entrancy of cleanup stack"));
  1594 	testReentrancy();
  1595 
  1596 	test.Next(_L("Test stack safety of TRAP and Leave"));
  1597 	testStackBalance();
  1598 
  1599 	test.Next(_L("Test TRAP_IGNORE"));
  1600 	testTrapIgnore();
  1601 
  1602 	test.End();
  1603 	return(0);
  1604     }
  1605