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