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\system\t_ctrap.cpp sl@0: // Overview: sl@0: // Test the CCleanup, CTrapCleanup and TAutoClose classes sl@0: // API Information: sl@0: // CCleanup, CTrapCleanup, TAutoClose sl@0: // Details: sl@0: // - Test cleanup stack reallocation during cleanup. sl@0: // - Test cleanup stack modifications during the cleanup operation sl@0: // will cause a panic. sl@0: // - Test single-level cleanup of cells, objects, items and a mix: sl@0: // Create a CCleanup object, call a combination of methods, verify sl@0: // the results are as expected and verify the heap has not been sl@0: // corrupted. sl@0: // - Test multi-level cleanup of cells, objects, items and a mix: sl@0: // Create a CCleanup object, call a combination of methods, verify sl@0: // the results are as expected and verify the heap has not been sl@0: // corrupted. sl@0: // - Test a variety of special case cleanup tasks. Verify that the sl@0: // results are as expected. sl@0: // - Test CTrapCleanup cleanup of objects that either exit normally sl@0: // or leave. Also test the cleanup of multiple objects that leave. sl@0: // Verify results are as expected. sl@0: // - Test TAutoClose: create a TAutoClose object, verify that it is sl@0: // closed when it goes out of scope, push it on the cleanup stack, sl@0: // verify cleanup results are as expected. sl@0: // - Test that the Cleanup stack can go re-entrant. sl@0: // - Ensure that the stack is properly balanced with and without sl@0: // leaving. 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: #define __E32TEST_EXTENSION__ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: sl@0: const TInt KInitialCount=2; sl@0: const TInt KInitialCountAll=3; sl@0: const TInt KLeaveValue=0x12345678; sl@0: const TInt KMaxAlloc=6; sl@0: sl@0: static const TInt KHeapSize = 0x2000; sl@0: sl@0: enum TWhat {EPop,EPopAndDestroy,EMulti,ENull}; sl@0: sl@0: class CTest : public CBase sl@0: { sl@0: public: sl@0: void ConstructL(); sl@0: private: sl@0: TInt iData; sl@0: }; sl@0: sl@0: class CTest2: public CBase sl@0: { sl@0: public: sl@0: ~CTest2(); sl@0: }; sl@0: sl@0: class CTest3: public CBase sl@0: { sl@0: public: sl@0: ~CTest3(); sl@0: }; sl@0: sl@0: class RItem sl@0: { sl@0: public: sl@0: RItem() : iOpen(EFalse) {} sl@0: void Open() {iOpen=ETrue;} sl@0: void Close() {iOpen=EFalse;} sl@0: operator TCleanupItem() {return TCleanupItem(Cleanup,this);} sl@0: TBool IsOpen() const {return(iOpen);} sl@0: private: sl@0: static void Cleanup(TAny* aPtr); sl@0: private: sl@0: TBool iOpen; sl@0: }; sl@0: sl@0: LOCAL_D RTest test(_L("T_CTRAP")); sl@0: LOCAL_D TAny* gP1; sl@0: LOCAL_D CBufFlat* gP2; sl@0: sl@0: sl@0: LOCAL_C void ReallocateStackL() sl@0: { sl@0: TInt n = 0; sl@0: for(TInt i = 0; i < KMaxAlloc; ++i) sl@0: { sl@0: HBufC *p1 = HBufC::NewLC(4); //Stack re-allocation will be performed due to the additional objects pushed sl@0: //into the cleanup stack sl@0: n = p1->Length(); //include this line to avoid warnigs for unused "p1" variable sl@0: } sl@0: test.Printf(_L("ReallocateStackL(): PopAndDestroy KMaxAlloc pointers\n")); sl@0: CleanupStack::PopAndDestroy(KMaxAlloc); sl@0: } sl@0: sl@0: CTest2::~CTest2() sl@0: { sl@0: TInt err = KErrNoMemory; sl@0: sl@0: test.Printf(_L("~CTest2(): call ReallocateStackL()\n")); sl@0: sl@0: TRAP(err, ReallocateStackL() ); sl@0: } sl@0: sl@0: CTest3::~CTest3() sl@0: { sl@0: RDebug::Printf("~CTest3(): Modify Cleanup stack by pushing items"); sl@0: sl@0: TInt n = 0; sl@0: for(TInt i = 0; i < KMaxAlloc; ++i) sl@0: { sl@0: HBufC *p1 = HBufC::NewLC(4); //Stack re-allocation will be performed due to the additional objects pushed sl@0: //into the cleanup stack sl@0: n = p1->Length(); //include this line to avoid warnigs for unused "p1" variable sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void ModifyStack() sl@0: { sl@0: CTest3* ptr6 = new(ELeave)CTest3; sl@0: CleanupStack::PushL(ptr6); sl@0: sl@0: RDebug::Printf("ModifyStack(): PopAndDestroy ptr6"); sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: sl@0: LOCAL_C TInt PanicStackModifiedFn(TAny* aNopFn) sl@0: { sl@0: __UHEAP_MARK; sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); sl@0: sl@0: aNopFn = NULL; //avoid warnings for unused "aNopFn" variable sl@0: sl@0: TInt err = KErrNoMemory; sl@0: sl@0: RDebug::Printf("PanicStackModifiedFn(): call TRAP(err, ModifyStack())"); sl@0: sl@0: if(NULL != cleanup) sl@0: { sl@0: TRAP(err, ModifyStack()); sl@0: delete cleanup; sl@0: } sl@0: __UHEAP_MARKEND; sl@0: return err; sl@0: } sl@0: sl@0: LOCAL_C void PushAndCleanupL() sl@0: { sl@0: CTest2* ptr1 = new(ELeave)CTest2; sl@0: CleanupStack::PushL(ptr1); sl@0: sl@0: CTest2* ptr2 = new(ELeave)CTest2; sl@0: CleanupStack::PushL(ptr2); sl@0: sl@0: CTest2* ptr3 = new(ELeave)CTest2; sl@0: CleanupStack::PushL(ptr3); sl@0: sl@0: test.Printf(_L("PushAndCleanupL(): PopAndDestroy ptr3, ptr2 and ptr1\n")); sl@0: CleanupStack::PopAndDestroy(3); sl@0: sl@0: CTest2* ptr4 = new(ELeave)CTest2; sl@0: CleanupStack::PushL(ptr4); sl@0: sl@0: CTest2* ptr5 = new(ELeave)CTest2; sl@0: CleanupStack::PushL(ptr5); sl@0: sl@0: test.Printf(_L("PushAndCleanupL(): PopAndDestroy ptr5 and ptr4\n")); sl@0: CleanupStack::PopAndDestroy(); sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: sl@0: LOCAL_C void testDestructorStackReallocation() sl@0: { sl@0: __UHEAP_MARK; sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); sl@0: sl@0: TInt err = KErrNoMemory; sl@0: sl@0: if(NULL != cleanup) sl@0: { sl@0: TRAP(err, PushAndCleanupL()); sl@0: delete cleanup; sl@0: } sl@0: __UHEAP_MARKEND; sl@0: sl@0: test_KErrNone(err); sl@0: sl@0: test.Printf(_L("Verify cleanup stack modification during cleanup operation causes EClnStackModified panic\n")); sl@0: sl@0: // sl@0: //To verify the above case a new thread is created which does modify the cleanup stack during cleanup. sl@0: //The exit reason is then checked for the appropriate value(EClnStackModified) sl@0: // sl@0: sl@0: RThread panicThread; sl@0: sl@0: TInt r = panicThread.Create(_L("Panic EClnStackModified Thread"), PanicStackModifiedFn, KDefaultStackSize, KHeapSize, KHeapSize, NULL); sl@0: sl@0: test_KErrNone(r); sl@0: sl@0: TRequestStatus panicThreadStatus; sl@0: panicThread.Logon(panicThreadStatus); sl@0: sl@0: //don't want just in time debugging as we trap panics sl@0: TBool justInTime=User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: sl@0: panicThread.Resume(); sl@0: sl@0: User::WaitForRequest(panicThreadStatus); sl@0: sl@0: test_Equal(EExitPanic, panicThread.ExitType()); sl@0: test_Equal(EClnStackModified, panicThread.ExitReason()); sl@0: sl@0: User::SetJustInTime(justInTime); sl@0: sl@0: CLOSE_AND_WAIT(panicThread); sl@0: } sl@0: sl@0: LOCAL_C void createMultiL() sl@0: // sl@0: // Create an object on the cleanup list and leave sl@0: // sl@0: { sl@0: sl@0: CBufFlat* pT=CBufFlat::NewL(8); sl@0: User::LeaveIfNull(pT); sl@0: CleanupStack::PushL(pT); sl@0: __UHEAP_CHECK(3); sl@0: User::Leave(KLeaveValue+1); sl@0: } sl@0: sl@0: LOCAL_C void createL(TWhat aWhat,TBool aLeave) sl@0: // sl@0: // Create objects and then either leave or return. sl@0: // Optionally pop them again. sl@0: // sl@0: { sl@0: sl@0: gP1=User::AllocL(0x10); sl@0: test.Printf(_L("createL 1")); sl@0: CleanupStack::PushL(gP1); sl@0: test.Printf(_L("createL 2")); sl@0: __UHEAP_CHECK(1); sl@0: test.Printf(_L("createL 3")); sl@0: gP2=CBufFlat::NewL(8); sl@0: test.Printf(_L("createL 4")); sl@0: User::LeaveIfNull(gP2); sl@0: test.Printf(_L("createL 5")); sl@0: CleanupStack::PushL(gP2); sl@0: test.Printf(_L("createL 6")); sl@0: __UHEAP_CHECK(2); sl@0: test.Printf(_L("createL 7")); sl@0: if (aWhat==EPop) sl@0: { sl@0: test.Printf(_L("createL 8")); sl@0: CleanupStack::Pop(); sl@0: test.Printf(_L("createL 9")); sl@0: CleanupStack::Pop(1); sl@0: test.Printf(_L("createL 10")); sl@0: } sl@0: if (aWhat==EPopAndDestroy) sl@0: { sl@0: test.Printf(_L("createL 11")); sl@0: CleanupStack::PopAndDestroy(); sl@0: test.Printf(_L("createL 12")); sl@0: CleanupStack::PopAndDestroy(1); sl@0: test.Printf(_L("createL 13")); sl@0: } sl@0: if (aWhat==EMulti) sl@0: { sl@0: test.Printf(_L("createL 14")); sl@0: TRAPD(r,createMultiL()) sl@0: test.Printf(_L("createL 15")); sl@0: test(r==(KLeaveValue+1)); sl@0: test.Printf(_L("createL 16")); sl@0: __UHEAP_CHECK(2); sl@0: test.Printf(_L("createL 17")); sl@0: } sl@0: if (aLeave) sl@0: { sl@0: test.Printf(_L("createL 18")); sl@0: User::Leave(KLeaveValue); sl@0: } sl@0: test.Printf(_L("createL 19")); sl@0: } sl@0: sl@0: LOCAL_C void createAllL(TBool aLeave) sl@0: // sl@0: // Call all functions which autmatically put objects on the cleanup list. sl@0: // sl@0: { sl@0: sl@0: __UHEAP_CHECK(KInitialCountAll); sl@0: TLex* pL=new(ELeave) TLex; // ::new, 1 cell sl@0: CleanupStack::PushL(pL); // Push sl@0: __UHEAP_CHECK(KInitialCountAll+1); sl@0: CTest* pT=new(ELeave) CTest; // CBase::new, 1 cell sl@0: CleanupStack::PushL(pT); // Push sl@0: __UHEAP_CHECK(KInitialCountAll+2); sl@0: pT->ConstructL(); // 1 more cell // Push sl@0: __UHEAP_CHECK(KInitialCountAll+3); sl@0: User::AllocLC(0x10); // Test RHeap::AllocLC as well // Push sl@0: __UHEAP_CHECK(KInitialCountAll+4); sl@0: _L("Hello").AllocLC(); // Test HBufC::NewLC() as well // Push sl@0: __UHEAP_CHECK(KInitialCountAll+5); sl@0: HBufC* pH=HBufC::NewMaxLC(8); // Push sl@0: test(pH->Length()==8); sl@0: __UHEAP_CHECK(KInitialCountAll+6); sl@0: if (aLeave) sl@0: User::Leave(KLeaveValue); sl@0: // new behavior for TCleanupTrapHander requires Pushes to the sl@0: // cleanup stack to be balanced by Pops sl@0: CleanupStack::PopAndDestroy(6); sl@0: } sl@0: sl@0: LOCAL_C void testSingleLevelCellsCleanup() sl@0: // sl@0: // Test single level cells cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("PopAll when empty")); sl@0: pC->NextLevel(); sl@0: pC->PopAll(); sl@0: pC->NextLevel(); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop")); sl@0: TAny* p=User::Alloc(0x10); sl@0: test(p!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: pC->NextLevel(); sl@0: pC->PushL(p); sl@0: pC->Pop(); sl@0: __UHEAP_CHECK(1); sl@0: User::Free(p); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop N")); sl@0: TAny* p1=User::Alloc(0x10); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: TAny* p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->Pop(2); sl@0: __UHEAP_CHECK(2); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop all")); sl@0: p1=User::Alloc(0x10); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: TAny* p3=User::Alloc(0x10); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(3); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: User::Free(p3); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop and destroy")); sl@0: p=User::Alloc(0x10); sl@0: test(p!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: pC->NextLevel(); sl@0: pC->PushL(p); sl@0: pC->PopAndDestroy(); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: // sl@0: test.Next(_L("Push and pop and destroy N")); sl@0: p1=User::Alloc(0x10); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PopAndDestroy(2); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop and destroy all")); sl@0: p1=User::Alloc(0x10); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: p3=User::Alloc(0x10); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testSingleLevelObjCleanup() sl@0: // sl@0: // Test single level object cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("Push and pop")); sl@0: CBufFlat* p=CBufFlat::NewL(8); sl@0: test(p!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: pC->NextLevel(); sl@0: pC->PushL(p); sl@0: pC->Pop(); sl@0: __UHEAP_CHECK(1); sl@0: User::Free(p); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop N")); sl@0: CBufFlat* p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: CBufFlat* p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->Pop(2); sl@0: __UHEAP_CHECK(2); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop all")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: CBufFlat* p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(3); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: User::Free(p3); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop and destroy")); sl@0: p=CBufFlat::NewL(8); sl@0: test(p!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: pC->NextLevel(); sl@0: pC->PushL(p); sl@0: pC->PopAndDestroy(); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: // sl@0: test.Next(_L("Push and pop and destroy N")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PopAndDestroy(2); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Push and pop and destroy all")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testSingleLevelItemCleanup() sl@0: // sl@0: // Test single level object cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("Push and pop")); sl@0: RItem r; sl@0: r.Open(); sl@0: test(r.IsOpen()); sl@0: pC->NextLevel(); sl@0: pC->PushL(r); sl@0: pC->Pop(); sl@0: test(r.IsOpen()); sl@0: r.Close(); sl@0: test(!r.IsOpen()); sl@0: pC->PopAll(); sl@0: // sl@0: test.Next(_L("Push and pop N")); sl@0: RItem r1; sl@0: r1.Open(); sl@0: RItem r2; sl@0: r2.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(r1); sl@0: pC->PushL(r2); sl@0: pC->Pop(2); sl@0: test(r1.IsOpen()); sl@0: test(r2.IsOpen()); sl@0: r1.Close(); sl@0: r2.Close(); sl@0: pC->PopAll(); sl@0: // sl@0: test.Next(_L("Push and pop all")); sl@0: r1.Open(); sl@0: r2.Open(); sl@0: RItem r3; sl@0: r3.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(r1); sl@0: pC->PushL(r2); sl@0: pC->PushL(r3); sl@0: pC->PopAll(); sl@0: test(r1.IsOpen()); sl@0: test(r2.IsOpen()); sl@0: test(r3.IsOpen()); sl@0: r1.Close(); sl@0: r2.Close(); sl@0: r3.Close(); sl@0: // sl@0: test.Next(_L("Push and pop and destroy")); sl@0: r.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(r); sl@0: pC->PopAndDestroy(); sl@0: test(!r.IsOpen()); sl@0: pC->PopAll(); sl@0: // sl@0: test.Next(_L("Push and pop and destroy N")); sl@0: r1.Open(); sl@0: r2.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(r1); sl@0: pC->PushL(r2); sl@0: pC->PopAndDestroy(2); sl@0: test(!r1.IsOpen()); sl@0: test(!r2.IsOpen()); sl@0: pC->PopAll(); sl@0: // sl@0: test.Next(_L("Push and pop and destroy all")); sl@0: r1.Open(); sl@0: r2.Open(); sl@0: r3.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(r1); sl@0: pC->PushL(r2); sl@0: pC->PushL(r3); sl@0: pC->PopAndDestroyAll(); sl@0: test(!r1.IsOpen()); sl@0: test(!r2.IsOpen()); sl@0: test(!r3.IsOpen()); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testSingleLevelMixCleanup() sl@0: // sl@0: // Test single level mixed cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("PushO PushC PushI and pop N")); sl@0: CBufFlat* p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: TAny* p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: RItem r; sl@0: r.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PushL(r); sl@0: pC->Pop(3); sl@0: __UHEAP_CHECK(2); sl@0: test(r.IsOpen()); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: r.Close(); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("PushO PushI PushC PushO and pop all")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: r.Open(); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: CBufFlat* p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(r); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(3); sl@0: test(r.IsOpen()); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: User::Free(p3); sl@0: r.Close(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("PushO PushC PushI and pop and destroy N")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: r.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PushL(r); sl@0: pC->PopAndDestroy(3); sl@0: test(!r.IsOpen()); sl@0: __UHEAP_CHECK(0); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("PushO PushI PushC PushO and pop and destroy all")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: r.Open(); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(r); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PopAndDestroyAll(); sl@0: test(!r.IsOpen()); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testMultiLevelCellsCleanup() sl@0: // sl@0: // Test multi level cells cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("Nest push push nest push popall popall")); sl@0: TAny* p1=User::Alloc(0x10); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: TAny* p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: TAny* p3=User::Alloc(0x10); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(3); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: User::Free(p3); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Nest push push nest push popallD popallD")); sl@0: p1=User::Alloc(0x10); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: p3=User::Alloc(0x10); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p3); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(2); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testMultiLevelObjCleanup() sl@0: // sl@0: // Test multi level object cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("Nest push push nest push popall popall")); sl@0: CBufFlat* p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: CBufFlat* p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: CBufFlat* p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(3); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: User::Free(p3); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Nest push push nest push popallD popallD")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(3); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->NextLevel(); sl@0: pC->PushL(p3); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(2); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testMultiLevelItemCleanup() sl@0: // sl@0: // Test multi level item cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("Nest push push nest push popall popall")); sl@0: RItem r1; sl@0: r1.Open(); sl@0: RItem r2; sl@0: r2.Open(); sl@0: RItem r3; sl@0: r3.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(r1); sl@0: pC->PushL(r2); sl@0: pC->NextLevel(); sl@0: pC->PushL(r3); sl@0: pC->PopAll(); sl@0: test(r1.IsOpen()); sl@0: test(r2.IsOpen()); sl@0: test(r3.IsOpen()); sl@0: pC->PopAll(); sl@0: test(r1.IsOpen()); sl@0: test(r2.IsOpen()); sl@0: test(r3.IsOpen()); sl@0: r1.Close(); sl@0: r2.Close(); sl@0: r3.Close(); sl@0: // sl@0: test.Next(_L("Nest push push nest push popallD popallD")); sl@0: r1.Open(); sl@0: r2.Open(); sl@0: r3.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(r1); sl@0: pC->PushL(r2); sl@0: pC->NextLevel(); sl@0: pC->PushL(r3); sl@0: pC->PopAndDestroyAll(); sl@0: test(r1.IsOpen()); sl@0: test(r2.IsOpen()); sl@0: test(!r3.IsOpen()); sl@0: pC->PopAndDestroyAll(); sl@0: test(!r1.IsOpen()); sl@0: test(!r2.IsOpen()); sl@0: test(!r3.IsOpen()); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testMultiLevelMixCleanup() sl@0: // sl@0: // Test multi level mixed cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("Nest pushO pushC nest pushI popall popall")); sl@0: CBufFlat* p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: TAny* p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: RItem r3; sl@0: r3.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->NextLevel(); sl@0: pC->PushL(r3); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(2); sl@0: test(r3.IsOpen()); sl@0: pC->PopAll(); sl@0: __UHEAP_CHECK(2); sl@0: test(r3.IsOpen()); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: r3.Close(); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("Nest pushO pushC nest pushI popallD popallD")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(1); sl@0: p2=User::Alloc(0x10); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(2); sl@0: r3.Open(); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->NextLevel(); sl@0: pC->PushL(r3); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(2); sl@0: test(!r3.IsOpen()); sl@0: pC->PopAndDestroyAll(); sl@0: test(!r3.IsOpen()); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pC; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testSpecialCaseCleanup() sl@0: // sl@0: // Test special case cleanup sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: __UHEAP_CHECK(KInitialCount); sl@0: // sl@0: test.Next(_L("Nest push push push fail")); sl@0: CBufFlat* p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+1); sl@0: CBufFlat* p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+2); sl@0: CBufFlat* p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+3); sl@0: CBufFlat* p4=CBufFlat::NewL(8); sl@0: test(p4!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+4); sl@0: CBufFlat* p5=CBufFlat::NewL(8); sl@0: test(p5!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+5); sl@0: CBufFlat* p6=CBufFlat::NewL(8); sl@0: test(p6!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+6); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PushL(p4); sl@0: pC->PushL(p5); sl@0: // sl@0: // The granularity is 4 so this should try and grow the array sl@0: // since room is always made for a free slot. We set the allocator sl@0: // to fail so that we can test that the free slot is re-established sl@0: // when we do the cleanup. This test only works in debug mode. sl@0: // sl@0: __UHEAP_FAILNEXT(1); sl@0: TRAPD(r,pC->PushL(p6)); sl@0: #if defined(_DEBUG) sl@0: test(r==KErrNoMemory); sl@0: #endif sl@0: __UHEAP_CHECK(KInitialCount+6); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(KInitialCount); sl@0: // sl@0: test.Next(_L("Nest push push push push popallD")); sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+1); sl@0: p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+2); sl@0: p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+3); sl@0: p4=CBufFlat::NewL(8); sl@0: test(p4!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+4); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->NextLevel(); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PushL(p4); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(KInitialCount+1); sl@0: pC->PopAndDestroyAll(); sl@0: __UHEAP_CHECK(KInitialCount); sl@0: // sl@0: test.Next(_L("Destroy cleanup object")); sl@0: // sl@0: p1=CBufFlat::NewL(8); sl@0: test(p1!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+1); sl@0: p2=CBufFlat::NewL(8); sl@0: test(p2!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+2); sl@0: p3=CBufFlat::NewL(8); sl@0: test(p3!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+3); sl@0: p4=CBufFlat::NewL(8); sl@0: test(p4!=NULL); sl@0: __UHEAP_CHECK(KInitialCount+4); sl@0: pC->NextLevel(); sl@0: pC->PushL(p1); sl@0: pC->NextLevel(); sl@0: pC->PushL(p2); sl@0: pC->PushL(p3); sl@0: pC->PushL(p4); sl@0: delete pC; sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testUnTrap() sl@0: // sl@0: // Test cleanup with normal exits sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CTrapCleanup* pT=CTrapCleanup::New(); sl@0: test(pT!=NULL); sl@0: __UHEAP_CHECK(KInitialCountAll); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("PushC PushO EPop cleanup empty")); sl@0: TRAPD(r,createL(EPop,EFalse)) sl@0: test.Next(_L("PushC PushO EPop cleanup empty 1")); sl@0: test(r==KErrNone); sl@0: test.Next(_L("PushC PushO EPop cleanup empty 2")); sl@0: __UHEAP_CHECK(2); sl@0: test.Next(_L("PushC PushO EPop cleanup empty 3")); sl@0: User::Free(gP1); sl@0: test.Next(_L("PushC PushO EPop cleanup empty 4")); sl@0: delete gP2; sl@0: test.Next(_L("PushC PushO EPop cleanup empty 5")); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("PushC PushO EPopAndDestroy cleanup empty")); sl@0: TRAP(r,createL(EPopAndDestroy,EFalse)) sl@0: test(r==KErrNone); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: /* sl@0: // Change of behavior for TCleanupTrapHandler means that the current sl@0: // cleanup stack must be empty when UnTrap is called. IE. calls to sl@0: // Push should be balanced with a Pop within the same function. sl@0: test.Next(_L("PushC PushO ENull cleanup 2 objects")); sl@0: TRAP(r,createL(ENull,EFalse)) sl@0: test(r==KErrNone); sl@0: __UHEAP_CHECK(0); sl@0: */ sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.Next(_L("Test all LC functions")); sl@0: TRAP(r,createAllL(EFalse)) sl@0: test(r==KErrNone); sl@0: __UHEAP_CHECK(KInitialCountAll); sl@0: // sl@0: delete pT; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testLeave() sl@0: // sl@0: // Test cleanup with leave exits sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CTrapCleanup* pT=CTrapCleanup::New(); sl@0: test(pT!=NULL); sl@0: __UHEAP_CHECK(KInitialCountAll); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("PushC PushO EPop cleanup empty and leave")); sl@0: TRAPD(r,createL(EPop,ETrue)) sl@0: test(r==KLeaveValue); sl@0: __UHEAP_CHECK(2); sl@0: User::Free(gP1); sl@0: delete gP2; sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("PushC PushO EPopAndDestroy cleanup empty and leave")); sl@0: TRAP(r,createL(EPopAndDestroy,ETrue)) sl@0: test(r==KLeaveValue); sl@0: __UHEAP_CHECK(0); sl@0: // sl@0: test.Next(_L("PushC PushO ENull cleanup 2 objects and leave")); sl@0: TRAP(r,createL(ENull,ETrue)) sl@0: test(r==KLeaveValue); sl@0: __UHEAP_CHECK(0); sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.Next(_L("Test all LC functions and leave")); sl@0: TRAP(r,createAllL(ETrue)) sl@0: test(r==KLeaveValue); sl@0: __UHEAP_CHECK(KInitialCountAll); sl@0: // sl@0: delete pT; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void testMultiLeave() sl@0: // sl@0: // Test cleanup with multiple leave exits sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Creating")); sl@0: // sl@0: __UHEAP_MARK; sl@0: CTrapCleanup* pT=CTrapCleanup::New(); sl@0: test(pT!=NULL); sl@0: // sl@0: __UHEAP_MARK; sl@0: // sl@0: test.Next(_L("PushC PushO nest PushO cleanup leave leave")); sl@0: TRAPD(r,createL(EMulti,ETrue)) sl@0: test(r==KLeaveValue); sl@0: __UHEAP_CHECK(0); sl@0: __UHEAP_MARKEND; sl@0: // sl@0: delete pT; sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void addNullItemL() sl@0: { sl@0: CleanupStack::PushL((TAny*)0); sl@0: } sl@0: sl@0: LOCAL_C void addCellL() sl@0: { sl@0: User::AllocLC(4); sl@0: } sl@0: sl@0: LOCAL_C void useCleanupStackL() sl@0: { sl@0: addNullItemL(); sl@0: addCellL(); sl@0: CleanupStack::PopAndDestroy(); sl@0: CleanupStack::Pop(); sl@0: } sl@0: sl@0: LOCAL_C void reentrantCleanup(TAny*) sl@0: // sl@0: // A cleanup operation which uses a trap harness and the cleanup stack sl@0: // sl@0: { sl@0: TRAPD(ignore,useCleanupStackL()) sl@0: } sl@0: sl@0: LOCAL_C void addReentrantItemL() sl@0: { sl@0: CleanupStack::PushL(TCleanupItem(reentrantCleanup)); sl@0: } sl@0: sl@0: LOCAL_C void addItemsL(TInt aCount) sl@0: // sl@0: // add number of reentrant items to make stack fail sl@0: // sl@0: { sl@0: while (--aCount>=0) sl@0: addReentrantItemL(); sl@0: #if !defined(_DEBUG) sl@0: User::Leave(KErrNoMemory); // heap failure not available sl@0: #endif sl@0: } sl@0: sl@0: const TInt KInitialStackSize=8; // from UC_CLN.CPP sl@0: const TInt KGrowItems=KInitialStackSize-3; sl@0: sl@0: LOCAL_C void testReentrancyL() sl@0: // sl@0: // Test the Cleanup stack can go re-entrant sl@0: // sl@0: { sl@0: sl@0: test.Next(_L("PopAndDestroy()")); sl@0: __UHEAP_MARK; sl@0: addNullItemL(); sl@0: addCellL(); sl@0: addReentrantItemL(); sl@0: CleanupStack::PopAndDestroy(2); sl@0: CleanupStack::Pop(); sl@0: __UHEAP_MARKEND; sl@0: // sl@0: test.Next(_L("cleanup after a leave")); sl@0: addNullItemL(); sl@0: TRAPD(r,addReentrantItemL();User::Leave(KLeaveValue);) sl@0: test(r==KLeaveValue); sl@0: CleanupStack::Pop(); sl@0: // sl@0: test.Next(_L("cleanup after stack failure")); sl@0: // Ensuring stack reallocate fails by placing following cell sl@0: TInt* forceAlloc=(TInt*)User::AllocL(4); sl@0: for (TInt i=0;i tim; sl@0: tim.iObj.CreateLocal(); sl@0: test.Next(_L("Push it on the cleanup stack")); sl@0: tim.PushL(); sl@0: test.Next(_L("Leave before object goes out of scope")); sl@0: User::Leave(KErrGeneral); sl@0: tim.Pop(); sl@0: } sl@0: sl@0: LOCAL_C void testAutoClose() sl@0: // sl@0: // Test the TAutoClose class sl@0: // sl@0: { sl@0: sl@0: // Kill the granules sl@0: RTimer s[20]; sl@0: TInt i; sl@0: for (i=0; i<20; i++) sl@0: s[i].CreateLocal(); sl@0: for (i=0; i<20; i++) sl@0: s[i].Close(); sl@0: sl@0: __KHEAP_MARK; sl@0: test.Start(_L("Make a TAutoClose object")); sl@0: { sl@0: TAutoClose tim; sl@0: tim.iObj.CreateLocal(); sl@0: sl@0: test.Next(_L("Let it fall out of scope")); sl@0: } sl@0: test.Next(_L("Check the object has closed")); sl@0: __KHEAP_CHECK(0); sl@0: sl@0: TRAPD(r, testAutoCloseL()); sl@0: test.Next(_L("Check object has been closed and cleaned up after leave")); sl@0: __KHEAP_MARKEND; sl@0: test.End(); sl@0: } sl@0: sl@0: void CTest::ConstructL() sl@0: // sl@0: // Allocate a cell with CBase::new sl@0: // sl@0: { sl@0: sl@0: TLex* pL=new(ELeave) TLex; sl@0: CleanupStack::PushL(pL); sl@0: } sl@0: sl@0: void RItem::Cleanup(TAny* aPtr) sl@0: // sl@0: // Invoke the Close member on the RItem at aPtr sl@0: // sl@0: { sl@0: sl@0: ((RItem*)aPtr)->Close(); sl@0: } sl@0: sl@0: LOCAL_C TInt getStackPointer() sl@0: { sl@0: static TUint8 there; sl@0: TUint8 here; sl@0: return &here-&there; sl@0: } sl@0: LOCAL_C void sheLeavesMeL(TBool sheLeavesMeNot) sl@0: { sl@0: if (!sheLeavesMeNot) sl@0: User::Leave(KErrBadName); // Montague sl@0: } sl@0: sl@0: // Variables for stack balance test need to be global or clever compiler optimisations sl@0: // Can interfere with stack balance calculations. sl@0: TInt StackBalanceLoopCounter; sl@0: TInt StackBalanceResult=KErrNone; sl@0: TInt StackBalanceBefore; sl@0: TInt StackBalanceAfter; sl@0: sl@0: // Split into two functions because x86gcc makes a local stack optimisation for the second sl@0: // loop which unbalances the stack frame of the first loop. sl@0: LOCAL_C TInt StackBalanceNotLeaving() sl@0: { sl@0: StackBalanceBefore=getStackPointer(); sl@0: for (StackBalanceLoopCounter=0; StackBalanceLoopCounter<20;StackBalanceLoopCounter++) sl@0: { sl@0: TRAP(StackBalanceResult,sheLeavesMeL(ETrue)); sl@0: } sl@0: StackBalanceAfter=getStackPointer(); sl@0: return StackBalanceAfter-StackBalanceBefore; sl@0: } sl@0: LOCAL_C TInt StackBalanceLeaving() sl@0: { sl@0: StackBalanceBefore=getStackPointer(); sl@0: for (StackBalanceLoopCounter=0; StackBalanceLoopCounter<20;StackBalanceLoopCounter++) sl@0: { sl@0: TRAP(StackBalanceResult,sheLeavesMeL(EFalse)); sl@0: } sl@0: StackBalanceAfter=getStackPointer(); sl@0: return StackBalanceAfter-StackBalanceBefore; sl@0: } sl@0: sl@0: LOCAL_C void testStackBalance() sl@0: // sl@0: // Ensure that we get the stack properly balanced sl@0: // sl@0: { sl@0: // Not leaving case sl@0: test.Start(_L("Stack balance without Leaving")); sl@0: TInt balance = StackBalanceNotLeaving(); sl@0: test.Printf(_L("Stack balance: %d bytes\n"), balance); sl@0: test(balance == 0); sl@0: sl@0: // Leaving case sl@0: test.Next(_L("Stack balance after Leave")); sl@0: balance = StackBalanceLeaving(); sl@0: test.Printf(_L("Stack balance: %d bytes\n"), balance); sl@0: test(balance == 0); sl@0: test.End(); sl@0: } sl@0: sl@0: void Inc(TAny* aPtr) sl@0: { sl@0: ++(*(TInt*)aPtr); sl@0: } sl@0: sl@0: void testTrapIgnore() sl@0: { sl@0: test.Start(_L("Create cleanup")); sl@0: CCleanup* pC=CCleanup::New(); sl@0: test(pC!=NULL); sl@0: TInt count = 0; sl@0: sl@0: test.Next(_L("TRAP_IGNORE with no leave")); sl@0: TRAP_IGNORE( sl@0: CleanupStack::PushL(TCleanupItem(Inc,&count)); sl@0: CleanupStack::Pop(); sl@0: ); sl@0: test(count==0); sl@0: sl@0: test.Next(_L("TRAP_IGNORE with leave")); sl@0: TRAP_IGNORE( sl@0: CleanupStack::PushL(TCleanupItem(Inc,&count)); sl@0: User::Leave(KErrGeneral); sl@0: ); sl@0: test(count==1); sl@0: sl@0: delete pC; sl@0: test.End(); sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: test.Title(); sl@0: sl@0: test.Start(_L("Test destructor causing stack reallocation")); sl@0: testDestructorStackReallocation(); sl@0: sl@0: test.Next(_L("CCleanup single level tests just alloc cells")); sl@0: testSingleLevelCellsCleanup(); sl@0: sl@0: test.Next(_L("CCleanup single level tests just objects")); sl@0: testSingleLevelObjCleanup(); sl@0: sl@0: test.Next(_L("CCleanup single level tests just items")); sl@0: testSingleLevelItemCleanup(); sl@0: sl@0: test.Next(_L("CCleanup single level tests mixed")); sl@0: testSingleLevelMixCleanup(); sl@0: sl@0: test.Next(_L("CCleanup multi level tests just alloc cells")); sl@0: testMultiLevelCellsCleanup(); sl@0: sl@0: test.Next(_L("CCleanup multi level tests just objects")); sl@0: testMultiLevelObjCleanup(); sl@0: sl@0: test.Next(_L("CCleanup multi level tests just items")); sl@0: testMultiLevelItemCleanup(); sl@0: sl@0: test.Next(_L("CCleanup multi level tests mixed")); sl@0: testMultiLevelMixCleanup(); sl@0: sl@0: test.Next(_L("CCleanup special case test")); sl@0: testSpecialCaseCleanup(); sl@0: sl@0: test.Next(_L("Install trap handler")); sl@0: CTrapCleanup* pT=CTrapCleanup::New(); sl@0: test(pT!=NULL); sl@0: sl@0: test.Next(_L("Untrap handling tests")); sl@0: testUnTrap(); sl@0: sl@0: test.Next(_L("Leave handling tests")); sl@0: testLeave(); sl@0: sl@0: test.Next(_L("Multi level leave handling tests")); sl@0: testMultiLeave(); sl@0: sl@0: test.Next(_L("Test TAutoClose")); sl@0: testAutoClose(); sl@0: sl@0: test.Next(_L("Test Re-entrancy of cleanup stack")); sl@0: testReentrancy(); sl@0: sl@0: test.Next(_L("Test stack safety of TRAP and Leave")); sl@0: testStackBalance(); sl@0: sl@0: test.Next(_L("Test TRAP_IGNORE")); sl@0: testTrapIgnore(); sl@0: sl@0: test.End(); sl@0: return(0); sl@0: } sl@0: