diff -r c55016431358 -r 0a7b44b10206 symport/e32/euser/cbase/ub_cln.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/symport/e32/euser/cbase/ub_cln.cpp Thu Jun 25 15:59:54 2009 +0100 @@ -0,0 +1,780 @@ +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Symbian Foundation License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\euser\cbase\ub_cln.cpp +// +// + +#include "ub_std.h" +#include "us_data.h" + +const TInt KCleanupGranularity=4; +const TInt KCleanupInitialSlots=8; + +LOCAL_C void doDelete(CBase *aPtr) +// +// Delete the CBase pointer +// + { + + delete aPtr; + } + +LOCAL_C CCleanup &cleanup() +// +// Return the CTrapHandler's cleanup list. +// + { + + TCleanupTrapHandler *pH=(TCleanupTrapHandler *)GetTrapHandler(); + __ASSERT_ALWAYS(pH!=NULL,Panic(EClnNoTrapHandlerInstalled)); + return(pH->Cleanup()); + } + + + + +TCleanupTrapHandler::TCleanupTrapHandler() + : iCleanup(NULL) +/** +Default constructor. +*/ + {} + + + + +void TCleanupTrapHandler::Trap() +/** +Deals with the invocation of a call to TRAP. +*/ + { + + iCleanup->NextLevel(); + } + + + + +void TCleanupTrapHandler::UnTrap() +/** +Deals with a function exiting a TRAP without leaving. +*/ + { + + iCleanup->PreviousLevel(); + } + + + + +void TCleanupTrapHandler::Leave(TInt /*aValue*/) +/** +Deals with a function within a TRAP leaving. + +@param aValue The leave value. +*/ + { + + iCleanup->PopAndDestroyAll(); + } + + + + +class TCleanupStackItem + { +public: + void Set(const TCleanupItem &aItem); + inline void Cleanup(); + inline TBool IsLevelMarker() const; + inline void MarkLevel(); + inline void PushLevel(); + inline TInt PopLevel(); + inline TBool Check(TAny* aExpectedItem) const; +private: + TCleanupOperation iOperation; + union + { + TAny *iPtr; + TInt iLevelCount; // may stack >1 level on this entry + }; + }; +inline void TCleanupStackItem::MarkLevel() + { iOperation=NULL; iLevelCount=1; } +inline TBool TCleanupStackItem::IsLevelMarker() const + { return (iOperation==NULL); } +inline void TCleanupStackItem::Cleanup() + { (*iOperation)(iPtr); } +inline void TCleanupStackItem::PushLevel() + { ++iLevelCount; } +inline TInt TCleanupStackItem::PopLevel() + { return (--iLevelCount); } +inline TBool TCleanupStackItem::Check(TAny* aExpectedItem) const + { return (iOperation && iPtr==aExpectedItem); } + +void TCleanupStackItem::Set(const TCleanupItem &anItem) +// +// Initialise an entry as a cleanup item. +// + { + + __ASSERT_ALWAYS(anItem.iOperation!=NULL,Panic(EClnNoCleanupOperation)); + iOperation=anItem.iOperation; + iPtr=anItem.iPtr; + } + + + + +EXPORT_C CCleanup *CCleanup::New() +/** +Creates a new cleanup stack object. + +The cleanup stack itself is allocated with enough space initially to hold +a number of stack items. + +@return A pointer to the new cleanup stack object. This is Null if there is + insufficient memory. +*/ + { + + CCleanup *pC=new CCleanup; + if (pC!=NULL) + { + TCleanupStackItem *base=(TCleanupStackItem *)User::Alloc(KCleanupInitialSlots*sizeof(TCleanupStackItem)); + if (base!=NULL) + { + pC->iBase=base; + pC->iNext=base; + pC->iTop=base+KCleanupInitialSlots; + } + else + { + delete pC; + pC=NULL; + } + } + return(pC); + } + + + + +EXPORT_C CCleanup *CCleanup::NewL() +/** +Creates a new cleanup stack object, and leaves if there is insufficient memory +to create it. + +The cleanup stack itself is allocated with enough space initially to hold +a number of stack items. + +@return A pointer to the new cleanup stack object. This is Null if there is + nsufficient memory. +*/ + { + + CCleanup *pC=New(); + User::LeaveIfNull(pC); + return(pC); + } + + + + +EXPORT_C CCleanup::CCleanup() +/** +Default constructor. +*/ + { + +// iBase=NULL; +// iTop=NULL; +// iNext=NULL; + } + + + + +EXPORT_C CCleanup::~CCleanup() +/** +Destructor. + +Pops and destroys all items from the cleanup stack and then destroys +the cleanup stack itself. +*/ + { + + while (iNext>iBase) + PopAndDestroyAll(); + User::Free(iBase); + } + + + + +EXPORT_C void CCleanup::NextLevel() +/** +Goes to the next cleanup level. +*/ + { + + if (iNext>iBase && (iNext-1)->IsLevelMarker()) + (iNext-1)->PushLevel(); + else + { + iNext->MarkLevel(); + ++iNext; + } + } + + + + +EXPORT_C void CCleanup::PreviousLevel() +/** +Goes to the previous cleanup level. + +@panic E32USER-CBase 71 If the previous stack item does not represent a cleanup + level. +*/ + { + + TCleanupStackItem *item=iNext; + --item; + // current level must be empty + __ASSERT_ALWAYS(item->IsLevelMarker(), Panic(EClnLevelNotEmpty)); + if (item->PopLevel()) + ++item; + iNext=item; + } + + + + +EXPORT_C void CCleanup::PushL(TAny *aPtr) +/** +Pushes a cleanup item onto the cleanup stack. + +The cleanup item represents an operation that frees the specified heap cell. + +@param aPtr A pointer to a heap cell that will be freed by + the cleanup operation. +*/ + { + + PushL(TCleanupItem(User::Free,aPtr)); + } + + + + +EXPORT_C void CCleanup::PushL(CBase *anObject) +/** +Pushes a cleanup item onto the cleanup stack. + +The cleanup item represents an operation that deletes the specified CBase +derived object. + +@param anObject A pointer to CBase derived object that will be deleted by + the cleanup operation. +*/ + { + + PushL(TCleanupItem(TCleanupOperation(doDelete),anObject)); + } + + + + +EXPORT_C void CCleanup::PushL(TCleanupItem anItem) +/** +Pushes a cleanup item onto the cleanup stack. + +The cleanup item represents a call back operation that performs the required +cleanup. + +@param anItem Encapsulates a cleanup operation and an object on which the + cleanup operation is to be performed. + +@see CleanupClosePushL +@see CleanupReleasePushL +@see CleanupDeletePushL +*/ + { + + TCleanupStackItem *item=iNext; + __ASSERT_ALWAYS(item>iBase,Panic(EClnPushAtLevelZero)); + __ASSERT_ALWAYS(itemSet(anItem); + iNext=++item; +// +// We always try and make sure that there are two free slots in the cleanup array. +// one for a level marker and one for an item to follow it +// If this fails its o.k. as we have already added the entry to the list, so +// it will be cleaned up o.k. +// + if (item+1>=iTop) + { + TInt size=(TUint8 *)(iTop+KCleanupGranularity)-(TUint8 *)iBase; + TCleanupStackItem *base=(TCleanupStackItem *)User::ReAllocL(iBase,size); + iNext=PtrAdd(base,(TUint8 *)item-(TUint8 *)iBase); + iBase=base; + iTop=PtrAdd(base,size); + } + } + + + + +EXPORT_C void CCleanup::DoPop(TInt aCount,TBool aDestroy) +/** +Provides an implementation for Pop() and PopAndDestroy(). + +@param aCount The number of cleanup items to be popped from + the cleanup stack. +@param aDestroy ETrue, if cleanup is to be performed; EFalse, otherwise. +*/ + { + + __ASSERT_ALWAYS(aCount>=0,Panic(EClnPopCountNegative)); + __ASSERT_ALWAYS((iNext-aCount)>=iBase,Panic(EClnPopUnderflow)); + while (aCount--) + { + --iNext; + __ASSERT_ALWAYS(!iNext->IsLevelMarker(),Panic(EClnPopAcrossLevels)); + if (aDestroy) + { + TInt offset = iNext - iBase; + iNext->Cleanup(); + // Check that there are no extra items on the cleanup stack + // (if there are, we will not be deleting the right aCount items) + __ASSERT_ALWAYS((iNext - iBase) == offset,Panic(EClnStackModified)); + } + } + } + + + + +EXPORT_C void CCleanup::DoPopAll(TBool aDestroy) +/** +Provides an implementation for PopAll() and PopAndDestroyAll(). + +@param aDestroy ETrue, if cleanup is to be performed; EFalse, otherwise. +*/ + { + + __ASSERT_ALWAYS(iNext>iBase,Panic(EClnLevelUnderflow)); + while (!(--iNext)->IsLevelMarker()) + { + if (aDestroy) + iNext->Cleanup(); + } + if (iNext->PopLevel()) + ++iNext; // still marks a level + } + + + + +EXPORT_C void CCleanup::Pop() +/** +Pops a single cleanup item from the cleanup stack. + +@panic E32USER-CBase 64 If there are no items on the cleanup stack. +@panic E32USER-CBase 63 If a cleanup level is crossed. +*/ + { + + DoPop(1,EFalse); + } + + + + +EXPORT_C void CCleanup::Pop(TInt aCount) +/** +Pops the specified number of cleanup items from the cleanup stack. + +@param aCount The number of cleanup items to be popped from the cleanup stack. + +@panic E32USER-CBase 70 If the specified number of cleanup items is negative. +@panic E32USER-CBase 64 If the specifed number of items is greater than the + number of items on the cleanup stack. +@panic E32USER-CBase 63 If the specified number of items is such that it causes + a cleanup level to be crossed. +*/ + { + + DoPop(aCount,EFalse); + } + + + + +EXPORT_C void CCleanup::PopAll() +/** +Pops all cleanup items at the current level, and then decrements the level. +*/ + { + + DoPopAll(EFalse); + } + + + + +EXPORT_C void CCleanup::PopAndDestroy() +/** +Pops a single cleanup item from the cleanup stack, and invokes its cleanup +operation. + +@panic E32USER-CBase 64 If there are no items on the cleanup stack. +@panic E32USER-CBase 63 If a cleanup level is crossed. +*/ + { + + DoPop(1,ETrue); + } + + + + +EXPORT_C void CCleanup::PopAndDestroy(TInt aCount) +/** +Pops the specified number of cleanup items from the cleanup stack, and invokes +their cleanup operations. + +@param aCount The number of cleanup items to be popped from the cleanup stack. + +@panic E32USER-CBase 70 If the specified number of cleanup items is negative. +@panic E32USER-CBase 64 If the specifed number of items is greater than the + number of items on the cleanup stack. +@panic E32USER-CBase 63 If the specified number of items is such that it causes + a cleanup level to be crossed. +*/ + { + + DoPop(aCount,ETrue); + } + + + + +EXPORT_C void CCleanup::PopAndDestroyAll() +/** +Pops all cleanup items at the current level, invokes their cleanup operations +and then decrements the level. +*/ + { + + DoPopAll(ETrue); + } + + + + +EXPORT_C void CCleanup::Check(TAny* aExpectedItem) +/** +Checks that the cleanup item at the top of the cleanup stack +represents a cleanup operation for the specified object. + +@param aExpectedItem The object which is the subject of the test. +*/ + { + + TCleanupStackItem* last=iNext-1; + __ASSERT_ALWAYS(last>=iBase && last->Check(aExpectedItem), Panic(EClnCheckFailed)); + } + + + + +EXPORT_C CTrapCleanup *CTrapCleanup::New() +/** +Allocates and constructs a cleanup stack. + +If successfully constructed, this cleanup stack becomes +the current cleanup stack. + +@return A pointer to the new cleanup stack. This pointer is NULL, if allocation + fails. +*/ + { + + CTrapCleanup *pT=new CTrapCleanup; + if (pT!=NULL) + { + CCleanup *pC=CCleanup::New(); + if (pC!=NULL) + { + pT->iHandler.iCleanup=pC; + pT->iOldHandler=User::SetTrapHandler(&pT->iHandler); + } + else + { + delete pT; + pT=NULL; + } + } + return(pT); + } + + + + +EXPORT_C CTrapCleanup::CTrapCleanup() +/** +Default constructor. +*/ +// : iHandler() + { + } + + + + +EXPORT_C CTrapCleanup::~CTrapCleanup() +/** +Destructor. + +Frees resources owned by the object, prior to its destruction. This cleanup +stack ceases to be the current cleanup stack. + +If there is a stack of cleanup stacks, then the next cleanup stack becomes +the current cleanup stack. +*/ + { + + if (iHandler.iCleanup!=NULL) + { + User::SetTrapHandler(iOldHandler); + delete iHandler.iCleanup; + } + } + + + + +EXPORT_C void CleanupStack::PushL(TAny *aPtr) +/** +Pushes a pointer to an object onto the cleanup stack. + +If a leave occurs while an object is on the stack, it is cleaned +up automatically. Untyped objects are cleaned up with User::Free() +(a rather limited form of cleanup, not even the C++ destructor is called). + +Typically, when an object has been fully constructed and it can be guaranteed +that a pointer to this new object is stored in some other object before a leave +occurs, issue CleanupStack::Pop() to pop it back off the stack. + +If no cleanup stack has been allocated, a panic occurs. + +It is guaranteed that the object is pushed onto the cleanup stack. However, +this function may leave if a stack frame for the next PushL() cannot be +allocated. In this case, the cleanup stack will be cleaned up as normal, and +no extra programmer intervention is needed. + +@param aPtr Pointer to any object. If cleanup is necessary, the object will be + freed by User::Free(), which does not invoke any destructor: it + simply frees its memory + +@panic E32USER-CBase 66 if a call to this function is made when no prior + call to TRAP has been made. +*/ + { + + cleanup().PushL(aPtr); + } + + + + +EXPORT_C void CleanupStack::PushL(CBase *aPtr) +/** +Pushes a pointer to an object onto the cleanup stack. + +If a leave occurs while an object is on the stack, it is cleaned +up automatically. CBase derived objects are cleaned up with delete. + +Typically, when an object has been fully constructed and it can be guaranteed +that a pointer to this new object is stored in some other object before a leave +occurs, issue CleanupStack::Pop() to pop it back off the stack. + +If no cleanup stack has been allocated, a panic occurs. + +It is guaranteed that the object is pushed onto the cleanup stack. However, +this function may leave if a stack frame for the next PushL() cannot be +allocated. In this case, the cleanup stack will be cleaned up as normal, +and no extra programmer intervention is needed. + +@param aPtr Pointer to a CBase-derived object. If cleanup is necessary, the + object will be freed by delete, thus invoking its destructor, + and freeing its memory. + +@panic E32USER-CBase 66 if a call to this function is made when no prior + call to TRAP has been made. +*/ + { + + cleanup().PushL(aPtr); + } + + + + +EXPORT_C void CleanupStack::PushL(TCleanupItem anItem) +/** +Pushes a cleanup item onto the cleanup stack. + +If a leave occurs while a cleanup item is on the stack, the cleanup operation +defined in the construction of the TCleanupItem, is invoked. + +Typically, when an object has been fully constructed and it can be guaranteed +that a pointer to this new object is stored in some other object before a leave +occurs, issue CleanupStack::Pop() to pop it back off the stack. + +If no cleanup stack has been allocated, a panic occurs. + +It is guaranteed that the object is pushed onto the cleanup stack. However, +this function may leave if a stack frame for the next PushL() cannot be +allocated. In this case, the cleanup stack will be cleaned up as normal, +and no extra programmer intervention is needed. + +@param anItem A cleanup item. If cleanup is necessary, the cleanup operation + defined in the construction of anItem is called. + +@panic E32USER-CBase 66 if a call to this function is made when no prior + call to TRAP has been made. +*/ + { + + cleanup().PushL(anItem); + } + + + + +EXPORT_C void CleanupStack::Pop() +/** +Pops an object previously pushed onto the cleanup stack +by CleanupStack::PushL(). + +After an object has been successfully constructed and stored within +another object, it cannot be orphaned and, therefore, the object +(i.e. a pointer or a cleanup item) can be popped from the cleanup stack. + +If no cleanup stack has been allocated, or there is nothing on the stack, +a panic is raised. +*/ + { + + cleanup().Pop(); + } + + + + +EXPORT_C void CleanupStack::Pop(TInt aCount) +/** +Pops a specified number of objects previously pushed onto the +cleanup stack by CleanupStack::PushL(). + +After an object has been successfully constructed and stored within another +object, it cannot be orphaned and, therefore, the object(s), that is, pointers +and cleanup items can be popped from the cleanup stack. + +If no cleanup stack has been allocated, or there is nothing on the stack, +a panic is raised. + +@param aCount The number of objects to be popped off the cleanup stack. +*/ + { + + cleanup().Pop(aCount); + } + + + + +EXPORT_C void CleanupStack::PopAndDestroy() +/** +Pops and cleans up an item pushed onto the stack. + +If the item on the stack is a CBase* pointer, the pointer is removed from +the stack and the object is destroyed with delete. + +If the item on the stack is a TAny* pointer, the pointer is removed from +the stack and the memory occupied by the object is freed with User::Free(). + +If the item on the stack is a cleanup item, i.e. an object of +type TCleanupItem, the item is removed from the stack and the cleanup +operation defined during construction of the TCleanupItem object is invoked. + +If no cleanup stack has been allocated, or there is nothing on the stack, +a panic occurs. +*/ + { + + cleanup().PopAndDestroy(); + } + + + + +EXPORT_C void CleanupStack::PopAndDestroy(TInt aCount) +/** +Pops and cleans up the specified number of items pushed onto the stack. + +If an item on the stack is a CBase* pointer, the pointer is removed from +the stack and the object is destroyed with delete. + +If an item on the stack is a TAny* pointer, the pointer is removed from the +stack and the memory occupied by the object is freed with User::Free(). + +If an item on the stack is a cleanup item, i.e. an object of type TCleanupItem, +the item is removed from the stack and the cleanup operation defined during +construction of the TCleanupItem object is invoked. + +If no cleanup stack has been allocated, or there is nothing on the stack, +a panic occurs. + +@param aCount The number of objects to be popped off the cleanup stack and +destroyed. +*/ + { + + cleanup().PopAndDestroy(aCount); + } + + + + +EXPORT_C void CleanupStack::Check(TAny* aExpectedItem) +/** +Checks that the specified object is at the top of the cleanup stack. + +If the specified item is not at the top of the cleanup stack, then the function +raises an E32USER-CBase 90 panic. + +The function is part of Symbian OS in both debug and release builds, and is +an aid to debugging. + +@param aExpectedItem A pointer to the item expected to be at the top of the + cleanup stack. +*/ + { + + cleanup().Check(aExpectedItem); + }