• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------
2  * Copyright (C) 1998-2009 PacketVideo
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 
19 #include "oscl_error_trapcleanup.h"
20 #include "oscl_assert.h"
21 #include "oscl_error_codes.h"
22 
23 _OsclBasicAllocator OsclErrorTrapImp::iDefAlloc;
24 
OsclErrorTrapImp(Oscl_DefAlloc * alloc,int32 & aError)25 OsclErrorTrapImp::OsclErrorTrapImp(Oscl_DefAlloc *alloc, int32 &aError)
26 {
27     aError = 0;
28     iAlloc = (alloc) ? alloc : &iDefAlloc;
29 #if defined(PVERROR_IMP_JUMPS)
30     {
31         OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclJump));
32         if (!ptr)
33         {
34             iJumpData = NULL;
35             aError = OsclErrNoMemory;
36         }
37         else
38         {
39             iJumpData = new(ptr) OsclJump();
40         }
41     }
42 #endif
43     OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStack));
44     if (!ptr)
45     {
46         iTrapStack = NULL;
47         aError = OsclErrNoMemory;
48     }
49     else
50     {
51         iTrapStack = new(ptr) OsclTrapStack(iAlloc);
52     }
53     iLeave = OsclErrNone;
54 }
55 
56 
~OsclErrorTrapImp()57 OsclErrorTrapImp::~OsclErrorTrapImp()
58 {
59     if (iTrapStack)
60     {
61         iTrapStack->~OsclTrapStack();
62         iAlloc->deallocate(iTrapStack);
63     }
64 #if defined(PVERROR_IMP_JUMPS)
65     if (iJumpData)
66     {
67         iJumpData->~OsclJump();
68         iAlloc->deallocate(iJumpData);
69     }
70 #endif
71 }
72 
73 
Trap()74 OSCL_EXPORT_REF OsclErrorTrapImp * OsclErrorTrapImp::Trap()
75 //static function to enter a trap level.
76 {
77     int32 error;
78     OsclErrorTrapImp *trap = GetErrorTrap(error);
79     if (!trap)
80         return NULL;//trap is non-functional.
81     trap->iLeave = OsclErrNone;
82     trap->iTrapStack->Trap();
83 #if defined(PVERROR_IMP_JUMPS)
84     trap->iJumpData->PushMark();
85 #endif
86     return trap;
87 }
88 
TrapNoTls(OsclErrorTrapImp * aTrap)89 OSCL_EXPORT_REF OsclErrorTrapImp* OsclErrorTrapImp::TrapNoTls(OsclErrorTrapImp* aTrap)
90 //static function to enter a trap level.  the trapimp can be passed in to avoid
91 //the overhead of a TLS lookup.
92 {
93     //thread context check
94     int32 error;
95     OSCL_ASSERT(aTrap == NULL || aTrap == GetErrorTrap(error));
96 
97     OsclErrorTrapImp* trap = (aTrap) ? aTrap : GetErrorTrap(error);
98     if (!trap)
99         return NULL;//trap is non-functional.
100     trap->iLeave = OsclErrNone;
101     trap->iTrapStack->Trap();
102 #if defined(PVERROR_IMP_JUMPS)
103     trap->iJumpData->PushMark();
104 #endif
105     return trap;
106 }
107 
UnTrap()108 OSCL_EXPORT_REF void OsclErrorTrapImp::UnTrap()
109 {
110     //clear the global leave code
111     iLeave = 0;
112 
113     bool notempty = iTrapStack->UnTrap();
114     OSCL_UNUSED_ARG(notempty);
115 
116 #if defined(PVERROR_IMP_JUMPS)
117     iJumpData->PopMark();
118 #endif
119 
120     OSCL_ASSERT(!notempty);//ETrapLevelNotEmpty
121 }
122 
123 ///////////////
124 //OsclTrapStack
125 ///////////////
126 
Trap()127 inline void OsclTrapStack::Trap()
128 //enter a trap by marking the current top of the cleanup stack.
129 {
130     if (iTop)
131         PushTrapL(iTop->iTAny);
132     else
133         PushTrapL((OsclAny*)NULL);
134 }
135 
UnTrap()136 inline bool OsclTrapStack::UnTrap()
137 //leave the current trap by popping the trap stack.
138 {
139     //check for untrap without corresponding trap.
140     OSCL_ASSERT(TrapTop());//ETrapLevelUnderflow
141 
142     //make sure all cleanup items in this level have
143     //been popped.
144     bool notempty = (iTop
145                      && iTop->iTAny != TrapTop()->iTAny);
146 
147     PopTrap();
148 
149     return notempty;
150 }
151 
152 
OsclTrapStack(Oscl_DefAlloc * alloc)153 OsclTrapStack::OsclTrapStack(Oscl_DefAlloc *alloc)
154 {
155     iTop = NULL;
156     iTrapTopIndex = (-1);
157     iAlloc = alloc;
158 }
159 
~OsclTrapStack()160 OsclTrapStack::~OsclTrapStack()
161 {
162     //there should not be leftover items at this point
163     OSCL_ASSERT(!iTop);
164     OSCL_ASSERT(!TrapTop());
165 
166     //pop all items off the stack so memory gets freed.
167     while (iTop)
168         Pop();
169     while (TrapTop())
170         PopTrap();
171 }
172 
PushL(_OsclHeapBase * aCBase)173 void OsclTrapStack::PushL(_OsclHeapBase *aCBase)
174 //Push a CBase item onto the cleanup stack
175 {
176     //Note: on Symbian you get a panic for doing
177     //a push outside any TRAP statement, so generate an
178     //error here also.
179     OSCL_ASSERT(TrapTop());//ETrapPushAtLevelZero
180 
181     OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStackItem));
182     OsclError::LeaveIfNull(ptr);
183     OsclTrapStackItem * item = new(ptr) OsclTrapStackItem(aCBase);
184     Push(item);
185 }
186 
PushL(OsclAny * aTAny)187 void OsclTrapStack::PushL(OsclAny *aTAny)
188 //Push a nonOsclTrapStackCBase item onto the cleanup stack
189 {
190     //Note: on Symbian you get a panic for doing
191     //a push outside any TRAP statement, so generate an
192     //error here also.
193     OSCL_ASSERT(TrapTop());//ETrapPushAtLevelZero
194 
195     OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStackItem));
196     OsclError::LeaveIfNull(ptr);
197     OsclTrapStackItem *item = new(ptr) OsclTrapStackItem(aTAny);
198     Push(item);
199 }
200 
PushTrapL(OsclAny * aTAny)201 inline void OsclTrapStack::PushTrapL(OsclAny *aTAny)
202 //Push a nonOsclTrapStackCBase item onto the trap mark stack
203 {
204     pushTrapIndex();
205     //construct this item using the stack top element memory
206     new((OsclAny*)TrapTop()) OsclTrapStackItem(aTAny);
207 }
208 
PushL(OsclTrapItem anItem)209 void OsclTrapStack::PushL(OsclTrapItem anItem)
210 {
211     //Note: on Symbian you get a panic for doing
212     //a push outside any TRAP statement, so generate an
213     //error here also.
214     OSCL_ASSERT(TrapTop());//ETrapPushAtLevelZero
215 
216     OsclAny* ptr = iAlloc->ALLOCATE(sizeof(OsclTrapStackItem));
217     OsclError::LeaveIfNull(ptr);
218     OsclTrapStackItem *item = new(ptr) OsclTrapStackItem(anItem);
219     Push(item);
220 }
221 
Push(OsclTrapStackItem * aItem)222 void OsclTrapStack::Push(OsclTrapStackItem *aItem)
223 //push the given item onto the stack.
224 {
225     if (aItem)
226     {
227         aItem->iNext = iTop;
228         iTop = aItem;
229     }
230 }
231 
Pop()232 void OsclTrapStack::Pop()
233 //pop the stack.
234 {
235     if (!iTop)
236         OsclError::Leave(OsclErrUnderflow);//ETrapPopUnderflow
237 
238     //check for a pop beyond the current trap level
239     if (TrapTop() && iTop->iTAny == TrapTop()->iTAny)
240         OsclError::Leave(OsclErrUnderflow);//ETrapPopAcrossLevels
241 
242     OsclTrapStackItem *next = iTop->iNext;
243     iTop->~OsclTrapStackItem();
244     iAlloc->deallocate(iTop);
245     iTop = next;
246 }
247 
PopTrap()248 inline void OsclTrapStack::PopTrap()
249 //pop the trap mark stack.
250 {
251     OSCL_ASSERT(TrapTop());//ETrapPopUnderflow
252 
253     //call destructor on the item in-place
254     TrapTop()->~OsclTrapStackItem();
255 
256     popTrapIndex();
257 }
258 
Pop(int32 aCount)259 void OsclTrapStack::Pop(int32 aCount)
260 {
261     OSCL_ASSERT(aCount >= 0);//ETrapPopCountNegative
262     for (int i = 0; i < aCount; i++)
263         Pop();
264 }
265 
PopDealloc()266 void OsclTrapStack::PopDealloc()
267 {
268     if (!iTop)
269         OsclError::Leave(OsclErrUnderflow);//ETrapPopUnderflow;
270 
271     if (TrapTop() && iTop->iTAny == TrapTop()->iTAny)
272         OsclError::Leave(OsclErrUnderflow);//ETrapPopAcrossLevels;
273 
274     if (iTop->iCBase)
275     {
276         //CBase destructor will be called.
277         //Note: we assume the delete operator is
278         //defined in the CBase-derived class.  If not,
279         //we won't get correct memory mgmt here.
280         delete(iTop->iCBase);
281     }
282     else if (iTop->iTrapOperation)
283     {
284         //user-supplied cleanup
285         (iTop->iTrapOperation)(iTop->iTAny);
286     }
287     else if (iTop->iTAny)
288     {
289         //no destructor, just free memory.
290         iAlloc->deallocate(iTop->iTAny);
291     }
292     Pop();
293 }
294 
PopDealloc(int32 aCount)295 void OsclTrapStack::PopDealloc(int32 aCount)
296 {
297     for (int i = 0; i < aCount; i++)
298         PopDealloc();
299 }
300 
Leaving()301 void OsclTrapStack::Leaving()
302 //a leave is happening, so cleanup all items on the stack
303 //for the current trap level.
304 {
305     //check for a leave outside any trap.
306     OSCL_ASSERT(TrapTop());//ETrapLevelUnderflow
307 
308     while (iTop && iTop->iTAny != TrapTop()->iTAny)
309         PopDealloc();
310 }
311 
312 
313 
314 
315