| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| |
| #include "oscl_error_trapcleanup.h" |
| #include "oscl_assert.h" |
| #include "oscl_error_codes.h" |
| |
| _OsclBasicAllocator OsclErrorTrapImp::iDefAlloc; |
| |
| OsclErrorTrapImp::OsclErrorTrapImp(Oscl_DefAlloc *alloc, int32 &aError) |
| { |
| aError = 0; |
| iAlloc = (alloc) ? alloc : &iDefAlloc; |
| #if defined(PVERROR_IMP_JUMPS) |
| { |
| OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclJump)); |
| if (!ptr) |
| { |
| iJumpData = NULL; |
| aError = OsclErrNoMemory; |
| } |
| else |
| { |
| iJumpData = new(ptr) OsclJump(); |
| } |
| } |
| #endif |
| OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStack)); |
| if (!ptr) |
| { |
| iTrapStack = NULL; |
| aError = OsclErrNoMemory; |
| } |
| else |
| { |
| iTrapStack = new(ptr) OsclTrapStack(iAlloc); |
| } |
| iLeave = OsclErrNone; |
| } |
| |
| |
| OsclErrorTrapImp::~OsclErrorTrapImp() |
| { |
| if (iTrapStack) |
| { |
| iTrapStack->~OsclTrapStack(); |
| iAlloc->deallocate(iTrapStack); |
| } |
| #if defined(PVERROR_IMP_JUMPS) |
| if (iJumpData) |
| { |
| iJumpData->~OsclJump(); |
| iAlloc->deallocate(iJumpData); |
| } |
| #endif |
| } |
| |
| |
| OSCL_EXPORT_REF OsclErrorTrapImp * OsclErrorTrapImp::Trap() |
| //static function to enter a trap level. |
| { |
| int32 error; |
| OsclErrorTrapImp *trap = GetErrorTrap(error); |
| if (!trap) |
| return NULL;//trap is non-functional. |
| trap->iLeave = OsclErrNone; |
| trap->iTrapStack->Trap(); |
| #if defined(PVERROR_IMP_JUMPS) |
| trap->iJumpData->PushMark(); |
| #endif |
| return trap; |
| } |
| |
| OSCL_EXPORT_REF OsclErrorTrapImp* OsclErrorTrapImp::TrapNoTls(OsclErrorTrapImp* aTrap) |
| //static function to enter a trap level. the trapimp can be passed in to avoid |
| //the overhead of a TLS lookup. |
| { |
| //thread context check |
| int32 error; |
| OSCL_ASSERT(aTrap == NULL || aTrap == GetErrorTrap(error)); |
| |
| OsclErrorTrapImp* trap = (aTrap) ? aTrap : GetErrorTrap(error); |
| if (!trap) |
| return NULL;//trap is non-functional. |
| trap->iLeave = OsclErrNone; |
| trap->iTrapStack->Trap(); |
| #if defined(PVERROR_IMP_JUMPS) |
| trap->iJumpData->PushMark(); |
| #endif |
| return trap; |
| } |
| |
| OSCL_EXPORT_REF void OsclErrorTrapImp::UnTrap() |
| { |
| //clear the global leave code |
| iLeave = 0; |
| |
| bool notempty = iTrapStack->UnTrap(); |
| OSCL_UNUSED_ARG(notempty); |
| |
| #if defined(PVERROR_IMP_JUMPS) |
| iJumpData->PopMark(); |
| #endif |
| |
| OSCL_ASSERT(!notempty);//ETrapLevelNotEmpty |
| } |
| |
| /////////////// |
| //OsclTrapStack |
| /////////////// |
| |
| inline void OsclTrapStack::Trap() |
| //enter a trap by marking the current top of the cleanup stack. |
| { |
| if (iTop) |
| PushTrapL(iTop->iTAny); |
| else |
| PushTrapL((OsclAny*)NULL); |
| } |
| |
| inline bool OsclTrapStack::UnTrap() |
| //leave the current trap by popping the trap stack. |
| { |
| //check for untrap without corresponding trap. |
| OSCL_ASSERT(TrapTop());//ETrapLevelUnderflow |
| |
| //make sure all cleanup items in this level have |
| //been popped. |
| bool notempty = (iTop |
| && iTop->iTAny != TrapTop()->iTAny); |
| |
| PopTrap(); |
| |
| return notempty; |
| } |
| |
| |
| OsclTrapStack::OsclTrapStack(Oscl_DefAlloc *alloc) |
| { |
| iTop = NULL; |
| iTrapTopIndex = (-1); |
| iAlloc = alloc; |
| } |
| |
| OsclTrapStack::~OsclTrapStack() |
| { |
| //there should not be leftover items at this point |
| OSCL_ASSERT(!iTop); |
| OSCL_ASSERT(!TrapTop()); |
| |
| //pop all items off the stack so memory gets freed. |
| while (iTop) |
| Pop(); |
| while (TrapTop()) |
| PopTrap(); |
| } |
| |
| void OsclTrapStack::PushL(_OsclHeapBase *aCBase) |
| //Push a CBase item onto the cleanup stack |
| { |
| //Note: on Symbian you get a panic for doing |
| //a push outside any TRAP statement, so generate an |
| //error here also. |
| OSCL_ASSERT(TrapTop());//ETrapPushAtLevelZero |
| |
| OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStackItem)); |
| OsclError::LeaveIfNull(ptr); |
| OsclTrapStackItem * item = new(ptr) OsclTrapStackItem(aCBase); |
| Push(item); |
| } |
| |
| void OsclTrapStack::PushL(OsclAny *aTAny) |
| //Push a nonOsclTrapStackCBase item onto the cleanup stack |
| { |
| //Note: on Symbian you get a panic for doing |
| //a push outside any TRAP statement, so generate an |
| //error here also. |
| OSCL_ASSERT(TrapTop());//ETrapPushAtLevelZero |
| |
| OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStackItem)); |
| OsclError::LeaveIfNull(ptr); |
| OsclTrapStackItem *item = new(ptr) OsclTrapStackItem(aTAny); |
| Push(item); |
| } |
| |
| inline void OsclTrapStack::PushTrapL(OsclAny *aTAny) |
| //Push a nonOsclTrapStackCBase item onto the trap mark stack |
| { |
| pushTrapIndex(); |
| //construct this item using the stack top element memory |
| new((OsclAny*)TrapTop()) OsclTrapStackItem(aTAny); |
| } |
| |
| void OsclTrapStack::PushL(OsclTrapItem anItem) |
| { |
| //Note: on Symbian you get a panic for doing |
| //a push outside any TRAP statement, so generate an |
| //error here also. |
| OSCL_ASSERT(TrapTop());//ETrapPushAtLevelZero |
| |
| OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStackItem)); |
| OsclError::LeaveIfNull(ptr); |
| OsclTrapStackItem *item = new(ptr) OsclTrapStackItem(anItem); |
| Push(item); |
| } |
| |
| void OsclTrapStack::Push(OsclTrapStackItem *aItem) |
| //push the given item onto the stack. |
| { |
| if (aItem) |
| { |
| aItem->iNext = iTop; |
| iTop = aItem; |
| } |
| } |
| |
| void OsclTrapStack::Pop() |
| //pop the stack. |
| { |
| if (!iTop) |
| OsclError::Leave(OsclErrUnderflow);//ETrapPopUnderflow |
| |
| //check for a pop beyond the current trap level |
| if (TrapTop() && iTop->iTAny == TrapTop()->iTAny) |
| OsclError::Leave(OsclErrUnderflow);//ETrapPopAcrossLevels |
| |
| OsclTrapStackItem *next = iTop->iNext; |
| iTop->~OsclTrapStackItem(); |
| iAlloc->deallocate(iTop); |
| iTop = next; |
| } |
| |
| inline void OsclTrapStack::PopTrap() |
| //pop the trap mark stack. |
| { |
| OSCL_ASSERT(TrapTop());//ETrapPopUnderflow |
| |
| //call destructor on the item in-place |
| TrapTop()->~OsclTrapStackItem(); |
| |
| popTrapIndex(); |
| } |
| |
| void OsclTrapStack::Pop(int32 aCount) |
| { |
| OSCL_ASSERT(aCount >= 0);//ETrapPopCountNegative |
| for (int i = 0; i < aCount; i++) |
| Pop(); |
| } |
| |
| void OsclTrapStack::PopDealloc() |
| { |
| if (!iTop) |
| OsclError::Leave(OsclErrUnderflow);//ETrapPopUnderflow; |
| |
| if (TrapTop() && iTop->iTAny == TrapTop()->iTAny) |
| OsclError::Leave(OsclErrUnderflow);//ETrapPopAcrossLevels; |
| |
| if (iTop->iCBase) |
| { |
| //CBase destructor will be called. |
| //Note: we assume the delete operator is |
| //defined in the CBase-derived class. If not, |
| //we won't get correct memory mgmt here. |
| delete(iTop->iCBase); |
| } |
| else if (iTop->iTrapOperation) |
| { |
| //user-supplied cleanup |
| (iTop->iTrapOperation)(iTop->iTAny); |
| } |
| else if (iTop->iTAny) |
| { |
| //no destructor, just free memory. |
| iAlloc->deallocate(iTop->iTAny); |
| } |
| Pop(); |
| } |
| |
| void OsclTrapStack::PopDealloc(int32 aCount) |
| { |
| for (int i = 0; i < aCount; i++) |
| PopDealloc(); |
| } |
| |
| void OsclTrapStack::Leaving() |
| //a leave is happening, so cleanup all items on the stack |
| //for the current trap level. |
| { |
| //check for a leave outside any trap. |
| OSCL_ASSERT(TrapTop());//ETrapLevelUnderflow |
| |
| while (iTop && iTop->iTAny != TrapTop()->iTAny) |
| PopDealloc(); |
| } |
| |
| |
| |
| |