blob: aaffd41b15a582de0e2cc4e04a5265ea86ba0f8d [file] [log] [blame]
/* ------------------------------------------------------------------
* 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();
}