|
1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\common\heap.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "common.h" |
|
19 #ifdef __KERNEL_MODE__ |
|
20 #include <kernel/kern_priv.h> |
|
21 #endif |
|
22 |
|
23 #ifdef _DEBUG |
|
24 #define __SIMULATE_ALLOC_FAIL(s) if (CheckForSimulatedAllocFail()) {s} |
|
25 #define __CHECK_CELL(p) CheckCell(p) |
|
26 #define __ZAP_CELL(p) memset( ((TUint8*)p) + RHeap::EAllocCellSize, 0xde, p->len - RHeap::EAllocCellSize) |
|
27 #define __DEBUG_SAVE(p) TInt dbgNestLevel = ((SDebugCell*)p)->nestingLevel |
|
28 #define __DEBUG_RESTORE(p) ((SDebugCell*)(((TUint8*)p)-EAllocCellSize))->nestingLevel = dbgNestLevel |
|
29 #else |
|
30 #define __SIMULATE_ALLOC_FAIL(s) |
|
31 #define __CHECK_CELL(p) |
|
32 #define __ZAP_CELL(p) |
|
33 #define __DEBUG_SAVE(p) |
|
34 #define __DEBUG_RESTORE(p) |
|
35 #endif |
|
36 |
|
37 #define __NEXT_CELL(p) ((SCell*)(((TUint8*)p)+p->len)) |
|
38 |
|
39 #define __POWER_OF_2(x) ((TUint32)((x)^((x)-1))>=(TUint32)(x)) |
|
40 |
|
41 #define __MEMORY_MONITOR_CHECK_CELL(p) \ |
|
42 { \ |
|
43 TLinAddr m = TLinAddr(iAlign-1); \ |
|
44 SCell* c = (SCell*)(((TUint8*)p)-EAllocCellSize); \ |
|
45 if((c->len & m) || (c->len<iMinCell) || ((TUint8*)c<iBase) || ((TUint8*)__NEXT_CELL(c)>iTop)) \ |
|
46 BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)p, (TUint32)c->len-EAllocCellSize); \ |
|
47 } |
|
48 |
|
49 /** |
|
50 @SYMPatchable |
|
51 @publishedPartner |
|
52 @released |
|
53 |
|
54 Defines the minimum cell size of a heap. |
|
55 |
|
56 The constant can be changed at ROM build time using patchdata OBY keyword. |
|
57 */ |
|
58 #ifdef __X86GCC__ // For X86GCC we dont use the proper data import attribute |
|
59 #undef IMPORT_D // since the constant is not really imported. GCC doesn't |
|
60 #define IMPORT_D // allow imports from self. |
|
61 #endif |
|
62 IMPORT_D extern const TInt KHeapMinCellSize; |
|
63 |
|
64 /** |
|
65 @SYMPatchable |
|
66 @publishedPartner |
|
67 @released |
|
68 |
|
69 This constant defines the ratio that determines the amount of hysteresis between heap growing and heap |
|
70 shrinking. |
|
71 It is a 32-bit fixed point number where the radix point is defined to be |
|
72 between bits 7 and 8 (where the LSB is bit 0) i.e. using standard notation, a Q8 or a fx24.8 |
|
73 fixed point number. For example, for a ratio of 2.0, set KHeapShrinkHysRatio=0x200. |
|
74 |
|
75 The heap shrinking hysteresis value is calculated to be: |
|
76 @code |
|
77 KHeapShrinkHysRatio*(iGrowBy>>8) |
|
78 @endcode |
|
79 where iGrowBy is a page aligned value set by the argument, aGrowBy, to the RHeap constructor. |
|
80 The default hysteresis value is iGrowBy bytes i.e. KHeapShrinkHysRatio=2.0. |
|
81 |
|
82 Memory usage may be improved by reducing the heap shrinking hysteresis |
|
83 by setting 1.0 < KHeapShrinkHysRatio < 2.0. Heap shrinking hysteresis is disabled/removed |
|
84 when KHeapShrinkHysRatio <= 1.0. |
|
85 |
|
86 The constant can be changed at ROM build time using patchdata OBY keyword. |
|
87 */ |
|
88 IMPORT_D extern const TInt KHeapShrinkHysRatio; |
|
89 |
|
90 #pragma warning( disable : 4705 ) // statement has no effect |
|
91 UEXPORT_C RHeap::RHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread) |
|
92 /** |
|
93 @internalComponent |
|
94 */ |
|
95 // |
|
96 // Constructor for fixed size heap |
|
97 // |
|
98 : iMinLength(aMaxLength), iMaxLength(aMaxLength), iOffset(0), iGrowBy(0), iChunkHandle(0), |
|
99 iNestingLevel(0), iAllocCount(0), iFailType(ENone), iTestData(NULL) |
|
100 { |
|
101 iAlign = aAlign ? aAlign : ECellAlignment; |
|
102 iPageSize = 0; |
|
103 iFlags = aSingleThread ? (ESingleThreaded|EFixedSize) : EFixedSize; |
|
104 Initialise(); |
|
105 } |
|
106 #pragma warning( default : 4705 ) |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 UEXPORT_C RHeap::RHeap(TInt aChunkHandle, TInt aOffset, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread) |
|
112 /** |
|
113 @internalComponent |
|
114 */ |
|
115 // |
|
116 // Constructor for chunk heaps. |
|
117 // |
|
118 : iOffset(aOffset), iChunkHandle(aChunkHandle), |
|
119 iNestingLevel(0), iAllocCount(0), iFailType(ENone), iTestData(NULL) |
|
120 { |
|
121 TInt sz = iBase - ((TUint8*)this - iOffset); |
|
122 GET_PAGE_SIZE(iPageSize); |
|
123 __ASSERT_ALWAYS(iOffset>=0, HEAP_PANIC(ETHeapNewBadOffset)); |
|
124 iMinLength = Max(aMinLength, sz + EAllocCellSize); |
|
125 iMinLength = _ALIGN_UP(iMinLength, iPageSize); |
|
126 iMaxLength = Max(aMaxLength, iMinLength); |
|
127 iMaxLength = _ALIGN_UP(iMaxLength, iPageSize); |
|
128 iGrowBy = _ALIGN_UP(aGrowBy, iPageSize); |
|
129 iFlags = aSingleThread ? ESingleThreaded : 0; |
|
130 iAlign = aAlign ? aAlign : ECellAlignment; |
|
131 Initialise(); |
|
132 } |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 UEXPORT_C TAny* RHeap::operator new(TUint aSize, TAny* aBase) __NO_THROW |
|
138 /** |
|
139 @internalComponent |
|
140 */ |
|
141 { |
|
142 __ASSERT_ALWAYS(aSize>=sizeof(RHeap), HEAP_PANIC(ETHeapNewBadSize)); |
|
143 RHeap* h = (RHeap*)aBase; |
|
144 h->iAlign = 0x80000000; // garbage value |
|
145 h->iBase = ((TUint8*)aBase) + aSize; |
|
146 return aBase; |
|
147 } |
|
148 |
|
149 void RHeap::Initialise() |
|
150 // |
|
151 // Initialise the heap. |
|
152 // |
|
153 { |
|
154 |
|
155 __ASSERT_ALWAYS((TUint32)iAlign>=sizeof(TAny*) && __POWER_OF_2(iAlign), HEAP_PANIC(ETHeapNewBadAlignment)); |
|
156 iCellCount = 0; |
|
157 iTotalAllocSize = 0; |
|
158 iBase = (TUint8*)Align(iBase + EAllocCellSize); |
|
159 iBase -= EAllocCellSize; |
|
160 TInt b = iBase - ((TUint8*)this - iOffset); |
|
161 TInt len = _ALIGN_DOWN(iMinLength - b, iAlign); |
|
162 iTop = iBase + len; |
|
163 iMinLength = iTop - ((TUint8*)this - iOffset); |
|
164 iMinCell = Align(KHeapMinCellSize + Max((TInt)EAllocCellSize, (TInt)EFreeCellSize)); |
|
165 #ifdef _DEBUG |
|
166 memset(iBase, 0xa5, len); |
|
167 #endif |
|
168 SCell* pM=(SCell*)iBase; // First free cell |
|
169 iFree.next=pM; // Free list points to first free cell |
|
170 iFree.len=0; // Stop free from joining this with a free block |
|
171 pM->next=NULL; // Terminate the free list |
|
172 pM->len=len; // Set the size of the free cell |
|
173 } |
|
174 |
|
175 #ifdef _DEBUG |
|
176 void RHeap::CheckCell(const SCell* aCell) const |
|
177 { |
|
178 TLinAddr m = TLinAddr(iAlign - 1); |
|
179 |
|
180 __ASSERT_DEBUG(!(aCell->len & m), HEAP_PANIC(ETHeapBadCellAddress)); |
|
181 __ASSERT_DEBUG(aCell->len >= iMinCell, HEAP_PANIC(ETHeapBadCellAddress)); |
|
182 __ASSERT_DEBUG((TUint8*)aCell>=iBase, HEAP_PANIC(ETHeapBadCellAddress)); |
|
183 __ASSERT_DEBUG((TUint8*)__NEXT_CELL(aCell)<=iTop, HEAP_PANIC(ETHeapBadCellAddress)); |
|
184 } |
|
185 #endif |
|
186 |
|
187 UEXPORT_C RHeap::SCell* RHeap::GetAddress(const TAny* aCell) const |
|
188 // |
|
189 // As much as possible, check a cell address and backspace it |
|
190 // to point at the cell header. |
|
191 // |
|
192 { |
|
193 |
|
194 TLinAddr m = TLinAddr(iAlign - 1); |
|
195 __ASSERT_ALWAYS(!(TLinAddr(aCell)&m), HEAP_PANIC(ETHeapBadCellAddress)); |
|
196 |
|
197 SCell* pC = (SCell*)(((TUint8*)aCell)-EAllocCellSize); |
|
198 __CHECK_CELL(pC); |
|
199 |
|
200 return pC; |
|
201 } |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 UEXPORT_C TInt RHeap::AllocLen(const TAny* aCell) const |
|
207 /** |
|
208 Gets the length of the available space in the specified allocated cell. |
|
209 |
|
210 @param aCell A pointer to the allocated cell. |
|
211 |
|
212 @return The length of the available space in the allocated cell. |
|
213 |
|
214 @panic USER 42 if aCell does not point to a valid cell. |
|
215 */ |
|
216 { |
|
217 |
|
218 SCell* pC = GetAddress(aCell); |
|
219 return pC->len - EAllocCellSize; |
|
220 } |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 #if !defined(__HEAP_MACHINE_CODED__) || defined(_DEBUG) |
|
227 RHeap::SCell* RHeap::DoAlloc(TInt aSize, SCell*& aLastFree) |
|
228 // |
|
229 // Allocate without growing. aSize includes cell header and alignment. |
|
230 // Lock already held. |
|
231 // |
|
232 { |
|
233 SCell* pP = &iFree; |
|
234 SCell* pC = pP->next; |
|
235 for (; pC; pP=pC, pC=pC->next) // Scan the free list |
|
236 { |
|
237 __CHECK_CELL(pC); |
|
238 SCell* pE; |
|
239 if (pC->len >= aSize) // Block size bigger than request |
|
240 { |
|
241 if (pC->len - aSize < iMinCell) // Leftover must be large enough to hold an SCell |
|
242 { |
|
243 aSize = pC->len; // It isn't, so take it all |
|
244 pE = pC->next; // Set the next field |
|
245 } |
|
246 else |
|
247 { |
|
248 pE = (SCell*)(((TUint8*)pC)+aSize); // Take amount required |
|
249 pE->len = pC->len - aSize; // Initialize new free cell |
|
250 pE->next = pC->next; |
|
251 } |
|
252 pP->next = pE; // Update previous pointer |
|
253 pC->len = aSize; // Set control size word |
|
254 #if defined(_DEBUG) |
|
255 ((SDebugCell*)pC)->nestingLevel = iNestingLevel; |
|
256 ((SDebugCell*)pC)->allocCount = ++iAllocCount; |
|
257 #endif |
|
258 return pC; |
|
259 } |
|
260 } |
|
261 aLastFree = pP; |
|
262 return NULL; |
|
263 } |
|
264 #endif |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 UEXPORT_C TAny* RHeap::Alloc(TInt aSize) |
|
270 /** |
|
271 Allocates a cell of the specified size from the heap. |
|
272 |
|
273 If there is insufficient memory available on the heap from which to allocate |
|
274 a cell of the required size, the function returns NULL. |
|
275 |
|
276 The cell is aligned according to the alignment value specified at construction, |
|
277 or the default alignment value, if an explict value was not specified. |
|
278 |
|
279 The resulting size of the allocated cell may be rounded up to a |
|
280 value greater than aSize, but is guaranteed to be not less than aSize. |
|
281 |
|
282 @param aSize The |
|
283 size of the cell to be allocated from the heap |
|
284 |
|
285 @return A pointer to the allocated cell. NULL if there is insufficient memory |
|
286 available. |
|
287 |
|
288 @panic USER 47 if the maximum unsigned value of aSize is greater than or equal |
|
289 to the value of KMaxTInt/2; for example, calling Alloc(-1) raises |
|
290 this panic. |
|
291 |
|
292 @see KMaxTInt |
|
293 */ |
|
294 { |
|
295 |
|
296 __CHECK_THREAD_STATE; |
|
297 __ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize)); |
|
298 __SIMULATE_ALLOC_FAIL(return NULL;) |
|
299 |
|
300 TInt origSize = aSize; |
|
301 aSize = Max(Align(aSize + EAllocCellSize), iMinCell); |
|
302 SCell* pL = NULL; |
|
303 Lock(); |
|
304 SCell* pC = (SCell*)DoAlloc(aSize, pL); |
|
305 if (!pC && !(iFlags & EFixedSize)) |
|
306 { |
|
307 // try to grow chunk heap |
|
308 TInt r = TryToGrowHeap(aSize, pL); |
|
309 if (r==KErrNone) |
|
310 pC = DoAlloc(aSize, pL); |
|
311 } |
|
312 if (pC) |
|
313 ++iCellCount, iTotalAllocSize += (pC->len - EAllocCellSize); |
|
314 Unlock(); |
|
315 if (pC) |
|
316 { |
|
317 TAny* result=((TUint8*)pC) + EAllocCellSize; |
|
318 if (iFlags & ETraceAllocs) |
|
319 { |
|
320 TUint32 traceData[2]; |
|
321 traceData[0] = AllocLen(result); |
|
322 traceData[1] = origSize; |
|
323 BTraceContextN(BTrace::EHeap, BTrace::EHeapAlloc, (TUint32)this, (TUint32)result, traceData, sizeof(traceData)); |
|
324 } |
|
325 #ifdef __KERNEL_MODE__ |
|
326 memclr(result, pC->len - EAllocCellSize); |
|
327 #endif |
|
328 return result; |
|
329 } |
|
330 if (iFlags & ETraceAllocs) |
|
331 BTraceContext8(BTrace::EHeap, BTrace::EHeapAllocFail, (TUint32)this, (TUint32)origSize); |
|
332 return NULL; |
|
333 } |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 TInt RHeap::TryToGrowHeap(TInt aSize, SCell* aLastFree) |
|
339 { |
|
340 TBool at_end = IsLastCell(aLastFree); |
|
341 TInt extra = at_end ? aSize - aLastFree->len : aSize; |
|
342 extra = (extra + iGrowBy - 1) / iGrowBy; |
|
343 extra *= iGrowBy; |
|
344 TInt cur_len = _ALIGN_UP(iTop - ((TUint8*)this - iOffset), iPageSize); |
|
345 TInt new_len = cur_len + extra; |
|
346 TInt r = KErrNoMemory; |
|
347 if (new_len <= iMaxLength) |
|
348 { |
|
349 r = SetBrk(new_len); |
|
350 if (r == KErrNone) |
|
351 { |
|
352 if (at_end) |
|
353 aLastFree->len += extra; |
|
354 else |
|
355 { |
|
356 SCell* pC = (SCell*)iTop; |
|
357 pC->len = extra; |
|
358 pC->next = NULL; |
|
359 aLastFree->next = pC; |
|
360 } |
|
361 iTop += extra; |
|
362 } |
|
363 } |
|
364 return r; |
|
365 } |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 #ifndef __KERNEL_MODE__ |
|
371 EXPORT_C TInt RHeap::Compress() |
|
372 /** |
|
373 Compresses the heap. |
|
374 |
|
375 The function frees excess committed space from the top |
|
376 of the heap. The size of the heap is never reduced below the minimum size |
|
377 specified during creation of the heap. |
|
378 |
|
379 @return The space reclaimed. If no space can be reclaimed, then this value |
|
380 is zero. |
|
381 */ |
|
382 { |
|
383 |
|
384 if (iFlags & EFixedSize) |
|
385 return 0; |
|
386 TInt r = 0; |
|
387 Lock(); |
|
388 SCell* pC = &iFree; |
|
389 for (; pC->next; pC=pC->next) {} |
|
390 if (pC!=&iFree) |
|
391 { |
|
392 __CHECK_CELL(pC); |
|
393 if (IsLastCell(pC)) |
|
394 r = Reduce(pC); |
|
395 } |
|
396 Unlock(); |
|
397 return r; |
|
398 } |
|
399 #endif |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 #if !defined(__HEAP_MACHINE_CODED__) || defined(_DEBUG) |
|
405 void RHeap::DoFree(SCell* pC) |
|
406 { |
|
407 __ZAP_CELL(pC); |
|
408 |
|
409 SCell* pP = &iFree; |
|
410 SCell* pE = pP->next; |
|
411 for (; pE && pE<pC; pP=pE, pE=pE->next) {} |
|
412 if (pE) // Is there a following free cell? |
|
413 { |
|
414 SCell* pN = __NEXT_CELL(pC); |
|
415 __ASSERT_ALWAYS(pN<=pE, HEAP_PANIC(ETHeapFreeBadNextCell)); // Following cell overlaps |
|
416 if (pN==pE) // Is it adjacent |
|
417 { |
|
418 pC->len += pE->len; // Yes - coalesce adjacent free cells |
|
419 pC->next = pE->next; |
|
420 } |
|
421 else // pN<pE, non-adjacent free cells |
|
422 pC->next = pE; // Otherwise just point to it |
|
423 } |
|
424 else |
|
425 pC->next = NULL; // No following free cell |
|
426 SCell* pN = __NEXT_CELL(pP); // pN=pP=&iFree if no preceding free cell |
|
427 __ASSERT_ALWAYS(pN<=pC, HEAP_PANIC(ETHeapFreeBadPrevCell)); // Previous cell overlaps |
|
428 if (pN==pC) // Is it adjacent |
|
429 { |
|
430 pP->len += pC->len; // Yes - coalesce adjacent free cells |
|
431 pP->next = pC->next; |
|
432 pC = pP; // for size reduction check |
|
433 } |
|
434 else // pN<pC, non-adjacent free cells |
|
435 pP->next = pC; // point previous cell to the one being freed |
|
436 pN = __NEXT_CELL(pC); // End of amalgamated free cell |
|
437 if ((TUint8*)pN==iTop && !(iFlags & EFixedSize) && |
|
438 pC->len >= KHeapShrinkHysRatio*(iGrowBy>>8)) |
|
439 Reduce(pC); |
|
440 } |
|
441 #endif |
|
442 |
|
443 |
|
444 |
|
445 |
|
446 UEXPORT_C void RHeap::Free(TAny* aCell) |
|
447 /** |
|
448 Frees the specified cell and returns it to the heap. |
|
449 |
|
450 @param aCell A pointer to a valid cell; this pointer can also be NULL, |
|
451 in which case the function does nothing and just returns. |
|
452 |
|
453 @panic USER 42 if aCell points to an invalid cell. |
|
454 */ |
|
455 { |
|
456 __CHECK_THREAD_STATE; |
|
457 if (!aCell) |
|
458 return; |
|
459 Lock(); |
|
460 if (iFlags & EMonitorMemory) |
|
461 __MEMORY_MONITOR_CHECK_CELL(aCell); |
|
462 SCell* pC = GetAddress(aCell); |
|
463 --iCellCount; |
|
464 iTotalAllocSize -= (pC->len - EAllocCellSize); |
|
465 DoFree(pC); |
|
466 if (iFlags & ETraceAllocs) |
|
467 BTraceContext8(BTrace::EHeap, BTrace::EHeapFree, (TUint32)this, (TUint32)aCell); |
|
468 Unlock(); |
|
469 } |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 TInt RHeap::Reduce(SCell* aCell) |
|
475 { |
|
476 TInt reduce=0; |
|
477 TInt offset=((TUint8*)aCell)-((TUint8*)this - iOffset); |
|
478 if (offset>=iMinLength) |
|
479 reduce = aCell->len; // length of entire free cell |
|
480 else |
|
481 reduce = offset + aCell->len - iMinLength; // length of free cell past minimum heap size |
|
482 reduce = _ALIGN_DOWN(reduce, iPageSize); // round down to page multiple |
|
483 if (reduce<=0) |
|
484 return 0; // can't reduce this heap |
|
485 TInt new_cell_len = aCell->len - reduce; // length of last free cell after reduction |
|
486 if (new_cell_len == 0) |
|
487 { |
|
488 // the free cell can be entirely eliminated |
|
489 SCell* pP = &iFree; |
|
490 for (; pP->next!=aCell; pP=pP->next) {} |
|
491 pP->next = NULL; |
|
492 } |
|
493 else |
|
494 { |
|
495 if (new_cell_len < iMinCell) |
|
496 { |
|
497 // max reduction would leave a cell too small |
|
498 reduce -= iPageSize; |
|
499 new_cell_len += iPageSize; |
|
500 } |
|
501 aCell->len = new_cell_len; // reduce the cell length |
|
502 } |
|
503 iTop -= reduce; |
|
504 TInt new_len = _ALIGN_UP(iTop - ((TUint8*)this - iOffset), iPageSize); |
|
505 TInt r = SetBrk(new_len); |
|
506 __ASSERT_ALWAYS(r==KErrNone, HEAP_PANIC(ETHeapReduceFailed)); |
|
507 return reduce; |
|
508 } |
|
509 |
|
510 |
|
511 |
|
512 |
|
513 #ifndef __KERNEL_MODE__ |
|
514 EXPORT_C void RHeap::Reset() |
|
515 /** |
|
516 Frees all allocated cells on this heap. |
|
517 */ |
|
518 { |
|
519 |
|
520 Lock(); |
|
521 if (!(iFlags & EFixedSize)) |
|
522 { |
|
523 TInt r = SetBrk(iMinLength); |
|
524 __ASSERT_ALWAYS(r==KErrNone, HEAP_PANIC(ETHeapResetFailed)); |
|
525 } |
|
526 Initialise(); |
|
527 Unlock(); |
|
528 } |
|
529 #endif |
|
530 |
|
531 |
|
532 |
|
533 |
|
534 inline void RHeap::FindFollowingFreeCell(SCell* aCell, SCell*& aPrev, SCell*& aNext) |
|
535 // |
|
536 // Find the free cell that immediately follows aCell, if one exists |
|
537 // If found, aNext is set to point to it, else it is set to NULL. |
|
538 // aPrev is set to the free cell before aCell or the dummy free cell where there are no free cells before aCell. |
|
539 // Called with lock enabled. |
|
540 // |
|
541 { |
|
542 aPrev = &iFree; |
|
543 aNext = aPrev->next; |
|
544 for (; aNext && aNext<aCell; aPrev=aNext, aNext=aNext->next) {} |
|
545 |
|
546 if (aNext) // If there is a following free cell, check its directly after aCell. |
|
547 { |
|
548 SCell* pNextCell = __NEXT_CELL(aCell); // end of this cell |
|
549 __ASSERT_ALWAYS(pNextCell<=aNext, (Unlock(), HEAP_PANIC(ETHeapReAllocBadNextCell))); // Following free cell overlaps |
|
550 if (pNextCell!=aNext) |
|
551 aNext=NULL; |
|
552 } |
|
553 } |
|
554 |
|
555 |
|
556 |
|
557 |
|
558 TInt RHeap::TryToGrowCell(SCell* aCell,SCell* aPrev, SCell* aNext, TInt aSize) |
|
559 // |
|
560 // Try to grow the heap cell 'aCell' in place, to size 'aSize'. |
|
561 // Requires the free cell immediately after aCell (aNext), and the free cell prior to |
|
562 // that (aPrev), to be provided. (As found by FindFollowingFreeCell) |
|
563 // |
|
564 |
|
565 { |
|
566 TInt extra = aSize - aCell->len; |
|
567 if (aNext && (aNext->len>=extra)) // Is there a following free cell big enough? |
|
568 { |
|
569 if (aNext->len - extra >= iMinCell) // take part of free cell ? |
|
570 { |
|
571 SCell* pX = (SCell*)((TUint8*)aNext + extra); // remainder of free cell |
|
572 pX->next = aNext->next; // remainder->next = original free cell->next |
|
573 pX->len = aNext->len - extra; // remainder length = original free cell length - extra |
|
574 aPrev->next = pX; // put remainder into free chain |
|
575 } |
|
576 else |
|
577 { |
|
578 extra = aNext->len; // Take whole free cell |
|
579 aPrev->next = aNext->next; // remove from free chain |
|
580 } |
|
581 #ifdef __KERNEL_MODE__ |
|
582 memclr(((TUint8*)aCell) + aCell->len, extra); |
|
583 #endif |
|
584 aCell->len += extra; // update reallocated cell length |
|
585 iTotalAllocSize += extra; |
|
586 return KErrNone; |
|
587 } |
|
588 return KErrGeneral; // No space to grow cell |
|
589 } |
|
590 |
|
591 |
|
592 |
|
593 |
|
594 // UEXPORT_C TAny* RHeap::ReAlloc(TAny* aCell, TInt aSize, TInt aMode) |
|
595 /** |
|
596 Increases or decreases the size of an existing cell in the heap. |
|
597 |
|
598 If the cell is being decreased in size, then it is guaranteed not to move, |
|
599 and the function returns the pointer originally passed in aCell. Note that the |
|
600 length of the cell will be the same if the difference between the old size |
|
601 and the new size is smaller than the minimum cell size. |
|
602 |
|
603 If the cell is being increased in size, i.e. aSize is bigger than its |
|
604 current size, then the function tries to grow the cell in place. |
|
605 If successful, then the function returns the pointer originally |
|
606 passed in aCell. If unsuccessful, then: |
|
607 |
|
608 1. if the cell cannot be moved, i.e. aMode has the ENeverMove bit set, then |
|
609 the function returns NULL. |
|
610 2. if the cell can be moved, i.e. aMode does not have the ENeverMove bit set, |
|
611 then the function tries to allocate a new replacement cell, and, if |
|
612 successful, returns a pointer to the new cell; if unsuccessful, it |
|
613 returns NULL. |
|
614 |
|
615 Note that in debug mode, the function returns NULL if the cell cannot be grown |
|
616 in place, regardless of whether the ENeverMove bit is set. |
|
617 |
|
618 If the reallocated cell is at a different location from the original cell, then |
|
619 the content of the original cell is copied to the reallocated cell. |
|
620 |
|
621 If the supplied pointer, aCell is NULL, then the function attempts to allocate |
|
622 a new cell, but only if the cell can be moved, i.e. aMode does not have |
|
623 the ENeverMove bit set. |
|
624 |
|
625 Note the following general points: |
|
626 |
|
627 1. If reallocation fails, the content of the original cell is preserved. |
|
628 |
|
629 2. The resulting size of the re-allocated cell may be rounded up to a value |
|
630 greater than aSize, but is guaranteed to be not less than aSize. |
|
631 |
|
632 @param aCell A pointer to the cell to be reallocated. This may be NULL. |
|
633 |
|
634 @param aSize The new size of the cell. This may be bigger or smaller than the |
|
635 size of the original cell. |
|
636 |
|
637 @param aMode Flags controlling the reallocation. The only bit which has any |
|
638 effect on this function is that defined by the enumeration |
|
639 ENeverMove of the enum RAllocator::TReAllocMode. |
|
640 If this is set, then any successful reallocation guarantees not |
|
641 to have changed the start address of the cell. |
|
642 By default, this parameter is zero. |
|
643 |
|
644 @return A pointer to the reallocated cell. This may be the same as the original |
|
645 pointer supplied through aCell. NULL if there is insufficient memory to |
|
646 reallocate the cell, or to grow it in place. |
|
647 |
|
648 @panic USER 42, if aCell is not NULL, and does not point to a valid cell. |
|
649 @panic USER 47, if the maximum unsigned value of aSize is greater |
|
650 than or equal to KMaxTInt/2. For example, |
|
651 calling ReAlloc(someptr,-1) raises this panic. |
|
652 |
|
653 @see RAllocator::TReAllocMode |
|
654 */ |
|
655 UEXPORT_C TAny* RHeap::ReAlloc(TAny* aCell, TInt aSize, TInt aMode) |
|
656 { |
|
657 if (aCell && iFlags&EMonitorMemory) |
|
658 __MEMORY_MONITOR_CHECK_CELL(aCell); |
|
659 TAny* retval = ReAllocImpl(aCell, aSize, aMode); |
|
660 if (iFlags & ETraceAllocs) |
|
661 { |
|
662 if (retval) |
|
663 { |
|
664 TUint32 traceData[3]; |
|
665 traceData[0] = AllocLen(retval); |
|
666 traceData[1] = aSize; |
|
667 traceData[2] = (TUint32)aCell; |
|
668 BTraceContextN(BTrace::EHeap, BTrace::EHeapReAlloc,(TUint32)this, (TUint32)retval,traceData, sizeof(traceData)); |
|
669 } |
|
670 else |
|
671 BTraceContext12(BTrace::EHeap, BTrace::EHeapReAllocFail, (TUint32)this, (TUint32)aCell, (TUint32)aSize); |
|
672 } |
|
673 return retval; |
|
674 } |
|
675 inline TAny* RHeap::ReAllocImpl(TAny* aCell, TInt aSize, TInt aMode) |
|
676 { |
|
677 __CHECK_THREAD_STATE; |
|
678 if (!aCell) |
|
679 return (aMode & ENeverMove) ? NULL : Alloc(aSize); |
|
680 __ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize)); |
|
681 Lock(); |
|
682 SCell* pC = GetAddress(aCell); |
|
683 TInt old_len = pC->len; |
|
684 __DEBUG_SAVE(pC); |
|
685 aSize = Max(Align(aSize + EAllocCellSize), iMinCell); |
|
686 if (aSize > old_len) // Trying to grow cell |
|
687 { |
|
688 __SIMULATE_ALLOC_FAIL({ Unlock(); return NULL;}) |
|
689 |
|
690 // Try to grow cell in place, without reallocation |
|
691 SCell* pPrev; |
|
692 SCell* pNext; |
|
693 FindFollowingFreeCell(pC,pPrev, pNext); |
|
694 TInt r = TryToGrowCell(pC, pPrev, pNext, aSize); |
|
695 |
|
696 if (r==KErrNone) |
|
697 { |
|
698 Unlock(); |
|
699 return aCell; |
|
700 } |
|
701 |
|
702 if (!(aMode & ENeverMove)) |
|
703 // If moving allowed, try re-alloc. |
|
704 // If we need to extend heap,and cell is at the end, try and grow in place |
|
705 { |
|
706 SCell* pLastFree; |
|
707 SCell* pNewCell = (SCell*)DoAlloc(aSize, pLastFree); |
|
708 if (!pNewCell && !(iFlags & EFixedSize)) |
|
709 // if we need to extend the heap to alloc |
|
710 { |
|
711 if (IsLastCell(pC) || (pNext && IsLastCell(pNext))) |
|
712 // if last used Cell, try and extend heap and then cell |
|
713 { |
|
714 TInt r = TryToGrowHeap(aSize - old_len, pLastFree); |
|
715 if (r==KErrNone) |
|
716 { |
|
717 r = TryToGrowCell(pC, pPrev, pPrev->next, aSize); |
|
718 Unlock(); |
|
719 __ASSERT_DEBUG(r == KErrNone, HEAP_PANIC(ETHeapCellDidntGrow)); |
|
720 return aCell; |
|
721 } |
|
722 } |
|
723 else |
|
724 // try to grow chunk heap and Alloc on it |
|
725 { |
|
726 TInt r = TryToGrowHeap(aSize, pLastFree); |
|
727 if (r==KErrNone) |
|
728 pNewCell = DoAlloc(aSize, pLastFree); |
|
729 } |
|
730 } |
|
731 |
|
732 if (pNewCell) |
|
733 // if we created a new cell, adjust tellies, copy the contents and delete old cell. |
|
734 { |
|
735 iCellCount++; |
|
736 iTotalAllocSize += (pNewCell->len - EAllocCellSize); |
|
737 |
|
738 Unlock(); |
|
739 TUint8* raw = ((TUint8*) pNewCell); |
|
740 |
|
741 memcpy(raw + EAllocCellSize, aCell, old_len - EAllocCellSize); |
|
742 #ifdef __KERNEL_MODE__ |
|
743 memclr(raw + old_len, pNewCell->len - old_len); |
|
744 #endif |
|
745 Free(aCell); |
|
746 __DEBUG_RESTORE(raw + EAllocCellSize); |
|
747 return raw + EAllocCellSize; |
|
748 } |
|
749 } |
|
750 else |
|
751 // No moving, but still posible to extend the heap (if heap extendable) |
|
752 { |
|
753 if (!(iFlags & EFixedSize) && (IsLastCell(pC) || (pNext && IsLastCell(pNext)))) |
|
754 { |
|
755 SCell* pLastFree = pNext ? pNext : pPrev; |
|
756 TInt r = TryToGrowHeap(aSize - old_len, pLastFree); |
|
757 if (r==KErrNone) |
|
758 { |
|
759 r = TryToGrowCell(pC, pPrev, pPrev->next, aSize); |
|
760 Unlock(); |
|
761 __ASSERT_DEBUG(r==KErrNone, HEAP_PANIC(ETHeapCellDidntGrow)); |
|
762 return aCell; |
|
763 } |
|
764 } |
|
765 } |
|
766 Unlock(); |
|
767 return NULL; |
|
768 } |
|
769 if (old_len - aSize >= iMinCell) |
|
770 { |
|
771 // cell shrinking, remainder big enough to form a new free cell |
|
772 SCell* pX = (SCell*)((TUint8*)pC + aSize); // pointer to new free cell |
|
773 pC->len = aSize; // update cell size |
|
774 pX->len = old_len - aSize; // size of remainder |
|
775 iTotalAllocSize -= pX->len; |
|
776 DoFree(pX); // link new free cell into chain, shrink heap if necessary |
|
777 } |
|
778 Unlock(); |
|
779 return aCell; |
|
780 } |
|
781 |
|
782 |
|
783 |
|
784 |
|
785 #ifndef __KERNEL_MODE__ |
|
786 |
|
787 EXPORT_C TInt RHeap::Available(TInt& aBiggestBlock) const |
|
788 /** |
|
789 Gets the total free space currently available on the heap and the space |
|
790 available in the largest free block. |
|
791 |
|
792 The space available represents the total space which can be allocated. |
|
793 |
|
794 Note that compressing the heap may reduce the total free space available and |
|
795 the space available in the largest free block. |
|
796 |
|
797 @param aBiggestBlock On return, contains the space available |
|
798 in the largest free block on the heap. |
|
799 |
|
800 @return The total free space currently available on the heap. |
|
801 */ |
|
802 { |
|
803 |
|
804 TInt total = 0; |
|
805 TInt max = 0; |
|
806 Lock(); |
|
807 SCell* pC = iFree.next; |
|
808 for (; pC; pC=pC->next) |
|
809 { |
|
810 TInt l = pC->len - EAllocCellSize; |
|
811 if (l > max) |
|
812 max = l; |
|
813 total += l; |
|
814 } |
|
815 Unlock(); |
|
816 aBiggestBlock = max; |
|
817 return total; |
|
818 } |
|
819 |
|
820 |
|
821 |
|
822 |
|
823 EXPORT_C TInt RHeap::AllocSize(TInt& aTotalAllocSize) const |
|
824 /** |
|
825 Gets the number of cells allocated on this heap, and the total space |
|
826 allocated to them. |
|
827 |
|
828 @param aTotalAllocSize On return, contains the total space allocated |
|
829 to the cells. |
|
830 |
|
831 @return The number of cells allocated on this heap. |
|
832 */ |
|
833 { |
|
834 Lock(); |
|
835 TInt c = iCellCount; |
|
836 aTotalAllocSize = iTotalAllocSize; |
|
837 Unlock(); |
|
838 return c; |
|
839 } |
|
840 |
|
841 |
|
842 |
|
843 |
|
844 EXPORT_C RHeap* UserHeap::FixedHeap(TAny* aBase, TInt aMaxLength, TInt aAlign, TBool aSingleThread) |
|
845 /** |
|
846 Creates a fixed length heap at a specified location. |
|
847 |
|
848 On successful return from this function, aMaxLength bytes are committed by the chunk. |
|
849 The heap cannot be extended. |
|
850 |
|
851 @param aBase A pointer to the location where the heap is to be constructed. |
|
852 @param aMaxLength The length of the heap. If the supplied value is less |
|
853 than KMinHeapSize, it is discarded and the value KMinHeapSize |
|
854 is used instead. |
|
855 @param aAlign The alignment of heap cells. |
|
856 @param aSingleThread Indicates whether single threaded or not. |
|
857 |
|
858 @return A pointer to the new heap, or NULL if the heap could not be created. |
|
859 |
|
860 @panic USER 56 if aMaxLength is negative. |
|
861 @panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. |
|
862 */ |
|
863 // |
|
864 // Force construction of the fixed memory. |
|
865 // |
|
866 { |
|
867 |
|
868 __ASSERT_ALWAYS(aMaxLength>=0, ::Panic(ETHeapMaxLengthNegative)); |
|
869 if (aMaxLength<KMinHeapSize) |
|
870 aMaxLength=KMinHeapSize; |
|
871 RHeap* h = new(aBase) RHeap(aMaxLength, aAlign, aSingleThread); |
|
872 if (!aSingleThread) |
|
873 { |
|
874 TInt r = h->iLock.CreateLocal(); |
|
875 if (r!=KErrNone) |
|
876 return NULL; |
|
877 h->iHandles = (TInt*)&h->iLock; |
|
878 h->iHandleCount = 1; |
|
879 } |
|
880 return h; |
|
881 } |
|
882 |
|
883 |
|
884 /** |
|
885 Constructor where minimum and maximum length of the heap can be defined. |
|
886 It defaults the chunk heap to be created to have use a new local chunk, |
|
887 to have a grow by value of KMinHeapGrowBy, to be unaligned, not to be |
|
888 single threaded and not to have any mode flags set. |
|
889 |
|
890 @param aMinLength The minimum length of the heap to be created. |
|
891 @param aMaxLength The maximum length to which the heap to be created can grow. |
|
892 If the supplied value is less than KMinHeapSize, then it |
|
893 is discarded and the value KMinHeapSize used instead. |
|
894 */ |
|
895 EXPORT_C TChunkHeapCreateInfo::TChunkHeapCreateInfo(TInt aMinLength, TInt aMaxLength) : |
|
896 iVersionNumber(EVersion0), iMinLength(aMinLength), iMaxLength(aMaxLength), |
|
897 iAlign(0), iGrowBy(1), iSingleThread(EFalse), |
|
898 iOffset(0), iPaging(EUnspecified), iMode(0), iName(NULL) |
|
899 { |
|
900 } |
|
901 |
|
902 |
|
903 /** |
|
904 Sets the chunk heap to create a new chunk with the specified name. |
|
905 |
|
906 This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or |
|
907 TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object. |
|
908 |
|
909 @param aName The name to be given to the chunk heap to be created |
|
910 If NULL, the function constructs a local chunk to host the heap. |
|
911 If not NULL, a pointer to a descriptor containing the name to be |
|
912 assigned to the global chunk hosting the heap. |
|
913 */ |
|
914 EXPORT_C void TChunkHeapCreateInfo::SetCreateChunk(const TDesC* aName) |
|
915 { |
|
916 iName = (TDesC*)aName; |
|
917 iChunk.SetHandle(KNullHandle); |
|
918 } |
|
919 |
|
920 |
|
921 /** |
|
922 Sets the chunk heap to be created to use the chunk specified. |
|
923 |
|
924 This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or |
|
925 TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object. |
|
926 |
|
927 @param aChunk A handle to the chunk to use for the heap. |
|
928 */ |
|
929 EXPORT_C void TChunkHeapCreateInfo::SetUseChunk(const RChunk aChunk) |
|
930 { |
|
931 iName = NULL; |
|
932 iChunk = aChunk; |
|
933 } |
|
934 |
|
935 |
|
936 /** |
|
937 Creates a chunk heap of the type specified by the parameter aCreateInfo. |
|
938 |
|
939 @param aCreateInfo A reference to a TChunkHeapCreateInfo object specifying the |
|
940 type of chunk heap to create. |
|
941 |
|
942 @return A pointer to the new heap or NULL if the heap could not be created. |
|
943 |
|
944 @panic USER 41 if the heap's specified minimum length is greater than the specified maximum length. |
|
945 @panic USER 55 if the heap's specified minimum length is negative. |
|
946 @panic USER 172 if the heap's specified alignment is not a power of 2 or is less than the size of a TAny*. |
|
947 */ |
|
948 EXPORT_C RHeap* UserHeap::ChunkHeap(const TChunkHeapCreateInfo& aCreateInfo) |
|
949 { |
|
950 // aCreateInfo must have been configured to use a new chunk or an exiting chunk. |
|
951 __ASSERT_ALWAYS(!(aCreateInfo.iMode & (TUint32)~EChunkHeapMask), ::Panic(EHeapCreateInvalidMode)); |
|
952 RHeap* h = NULL; |
|
953 |
|
954 if (aCreateInfo.iChunk.Handle() == KNullHandle) |
|
955 {// A new chunk is to be created for this heap. |
|
956 __ASSERT_ALWAYS(aCreateInfo.iMinLength >= 0, ::Panic(ETHeapMinLengthNegative)); |
|
957 __ASSERT_ALWAYS(aCreateInfo.iMaxLength >= aCreateInfo.iMinLength, ::Panic(ETHeapCreateMaxLessThanMin)); |
|
958 |
|
959 TInt maxLength = aCreateInfo.iMaxLength; |
|
960 if (maxLength < KMinHeapSize) |
|
961 maxLength = KMinHeapSize; |
|
962 |
|
963 TChunkCreateInfo chunkInfo; |
|
964 chunkInfo.SetNormal(0, maxLength); |
|
965 chunkInfo.SetOwner((aCreateInfo.iSingleThread)? EOwnerThread : EOwnerProcess); |
|
966 if (aCreateInfo.iName) |
|
967 chunkInfo.SetGlobal(*aCreateInfo.iName); |
|
968 // Set the paging attributes of the chunk. |
|
969 if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EPaged) |
|
970 chunkInfo.SetPaging(TChunkCreateInfo::EPaged); |
|
971 if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EUnpaged) |
|
972 chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged); |
|
973 // Create the chunk. |
|
974 RChunk chunk; |
|
975 if (chunk.Create(chunkInfo) != KErrNone) |
|
976 return NULL; |
|
977 // Create the heap using the new chunk. |
|
978 TUint mode = aCreateInfo.iMode | EChunkHeapDuplicate; // Must duplicate the handle. |
|
979 h = OffsetChunkHeap(chunk, aCreateInfo.iMinLength, aCreateInfo.iOffset, |
|
980 aCreateInfo.iGrowBy, maxLength, aCreateInfo.iAlign, |
|
981 aCreateInfo.iSingleThread, mode); |
|
982 chunk.Close(); |
|
983 } |
|
984 else |
|
985 { |
|
986 h = OffsetChunkHeap(aCreateInfo.iChunk, aCreateInfo.iMinLength, aCreateInfo.iOffset, |
|
987 aCreateInfo.iGrowBy, aCreateInfo.iMaxLength, aCreateInfo.iAlign, |
|
988 aCreateInfo.iSingleThread, aCreateInfo.iMode); |
|
989 } |
|
990 return h; |
|
991 } |
|
992 |
|
993 |
|
994 EXPORT_C RHeap* UserHeap::ChunkHeap(const TDesC* aName, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread) |
|
995 /** |
|
996 Creates a heap in a local or global chunk. |
|
997 |
|
998 The chunk hosting the heap can be local or global. |
|
999 |
|
1000 A local chunk is one which is private to the process creating it and is not |
|
1001 intended for access by other user processes. |
|
1002 A global chunk is one which is visible to all processes. |
|
1003 |
|
1004 The hosting chunk is local, if the pointer aName is NULL, otherwise |
|
1005 the hosting chunk is global and the descriptor *aName is assumed to contain |
|
1006 the name to be assigned to it. |
|
1007 |
|
1008 Ownership of the host chunk is vested in the current process. |
|
1009 |
|
1010 A minimum and a maximum size for the heap can be specified. On successful |
|
1011 return from this function, the size of the heap is at least aMinLength. |
|
1012 If subsequent requests for allocation of memory from the heap cannot be |
|
1013 satisfied by compressing the heap, the size of the heap is extended in |
|
1014 increments of aGrowBy until the request can be satisfied. Attempts to extend |
|
1015 the heap causes the size of the host chunk to be adjusted. |
|
1016 |
|
1017 Note that the size of the heap cannot be adjusted by more than aMaxLength. |
|
1018 |
|
1019 @param aName If NULL, the function constructs a local chunk to host |
|
1020 the heap. |
|
1021 If not NULL, a pointer to a descriptor containing the name |
|
1022 to be assigned to the global chunk hosting the heap. |
|
1023 @param aMinLength The minimum length of the heap. |
|
1024 @param aMaxLength The maximum length to which the heap can grow. |
|
1025 If the supplied value is less than KMinHeapSize, then it |
|
1026 is discarded and the value KMinHeapSize used instead. |
|
1027 @param aGrowBy The increments to the size of the host chunk. If a value is |
|
1028 not explicitly specified, the value KMinHeapGrowBy is taken |
|
1029 by default |
|
1030 @param aAlign The alignment of heap cells. |
|
1031 @param aSingleThread Indicates whether single threaded or not. |
|
1032 |
|
1033 @return A pointer to the new heap or NULL if the heap could not be created. |
|
1034 |
|
1035 @panic USER 41 if aMinLength is greater than the supplied value of aMaxLength. |
|
1036 @panic USER 55 if aMinLength is negative. |
|
1037 @panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. |
|
1038 */ |
|
1039 // |
|
1040 // Allocate a Chunk of the requested size and force construction. |
|
1041 // |
|
1042 { |
|
1043 TChunkHeapCreateInfo createInfo(aMinLength, aMaxLength); |
|
1044 createInfo.SetCreateChunk(aName); |
|
1045 createInfo.SetGrowBy(aGrowBy); |
|
1046 createInfo.SetAlignment(aAlign); |
|
1047 createInfo.SetSingleThread(aSingleThread); |
|
1048 return ChunkHeap(createInfo); |
|
1049 } |
|
1050 |
|
1051 |
|
1052 |
|
1053 |
|
1054 EXPORT_C RHeap* UserHeap::ChunkHeap(RChunk aChunk, TInt aMinLength, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode) |
|
1055 /** |
|
1056 Creates a heap in an existing chunk. |
|
1057 |
|
1058 This function is intended to be used to create a heap in a user writable code |
|
1059 chunk as created by a call to RChunk::CreateLocalCode(). |
|
1060 This type of heap can be used to hold code fragments from a JIT compiler. |
|
1061 |
|
1062 The maximum length to which the heap can grow is the same as |
|
1063 the maximum size of the chunk. |
|
1064 |
|
1065 @param aChunk The chunk that will host the heap. |
|
1066 @param aMinLength The minimum length of the heap. |
|
1067 @param aGrowBy The increments to the size of the host chunk. |
|
1068 @param aMaxLength The maximum length to which the heap can grow. |
|
1069 @param aAlign The alignment of heap cells. |
|
1070 @param aSingleThread Indicates whether single threaded or not. |
|
1071 @param aMode Flags controlling the heap creation. This should be set |
|
1072 from one or more of the values in TChunkHeapCreateMode. |
|
1073 |
|
1074 @return A pointer to the new heap or NULL if the heap could not be created. |
|
1075 |
|
1076 @panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. |
|
1077 */ |
|
1078 // |
|
1079 // Construct a heap in an already existing chunk |
|
1080 // |
|
1081 { |
|
1082 |
|
1083 return OffsetChunkHeap(aChunk, aMinLength, 0, aGrowBy, aMaxLength, aAlign, aSingleThread, aMode); |
|
1084 } |
|
1085 |
|
1086 |
|
1087 |
|
1088 |
|
1089 EXPORT_C RHeap* UserHeap::OffsetChunkHeap(RChunk aChunk, TInt aMinLength, TInt aOffset, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode) |
|
1090 /** |
|
1091 Creates a heap in an existing chunk, offset from the beginning of the chunk. |
|
1092 |
|
1093 This function is intended to be used to create a heap where a fixed amount of |
|
1094 additional data must be stored at a known location. The additional data can be |
|
1095 placed at the base address of the chunk, allowing it to be located without |
|
1096 depending on the internals of the heap structure. |
|
1097 |
|
1098 The maximum length to which the heap can grow is the maximum size of the chunk, |
|
1099 minus the offset. |
|
1100 |
|
1101 @param aChunk The chunk that will host the heap. |
|
1102 @param aMinLength The minimum length of the heap. |
|
1103 @param aOffset The offset from the start of the chunk, to the start of the heap. |
|
1104 @param aGrowBy The increments to the size of the host chunk. |
|
1105 @param aMaxLength The maximum length to which the heap can grow. |
|
1106 @param aAlign The alignment of heap cells. |
|
1107 @param aSingleThread Indicates whether single threaded or not. |
|
1108 @param aMode Flags controlling the heap creation. This should be set |
|
1109 from one or more of the values in TChunkHeapCreateMode. |
|
1110 |
|
1111 @return A pointer to the new heap or NULL if the heap could not be created. |
|
1112 |
|
1113 @panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. |
|
1114 */ |
|
1115 // |
|
1116 // Construct a heap in an already existing chunk |
|
1117 // |
|
1118 { |
|
1119 |
|
1120 TInt page_size; |
|
1121 UserHal::PageSizeInBytes(page_size); |
|
1122 if (!aAlign) |
|
1123 aAlign = RHeap::ECellAlignment; |
|
1124 TInt maxLength = aChunk.MaxSize(); |
|
1125 TInt round_up = Max(aAlign, page_size); |
|
1126 TInt min_cell = _ALIGN_UP(Max((TInt)RHeap::EAllocCellSize, (TInt)RHeap::EFreeCellSize), aAlign); |
|
1127 aOffset = _ALIGN_UP(aOffset, 8); |
|
1128 if (aMaxLength && aMaxLength+aOffset<maxLength) |
|
1129 maxLength = _ALIGN_UP(aMaxLength+aOffset, round_up); |
|
1130 __ASSERT_ALWAYS(aMinLength>=0, ::Panic(ETHeapMinLengthNegative)); |
|
1131 __ASSERT_ALWAYS(maxLength>=aMinLength, ::Panic(ETHeapCreateMaxLessThanMin)); |
|
1132 aMinLength = _ALIGN_UP(Max(aMinLength, (TInt)sizeof(RHeap) + min_cell) + aOffset, round_up); |
|
1133 TInt r=aChunk.Adjust(aMinLength); |
|
1134 if (r!=KErrNone) |
|
1135 return NULL; |
|
1136 |
|
1137 RHeap* h = new (aChunk.Base() + aOffset) RHeap(aChunk.Handle(), aOffset, aMinLength, maxLength, aGrowBy, aAlign, aSingleThread); |
|
1138 |
|
1139 TBool duplicateLock = EFalse; |
|
1140 if (!aSingleThread) |
|
1141 { |
|
1142 duplicateLock = aMode & EChunkHeapSwitchTo; |
|
1143 if(h->iLock.CreateLocal(duplicateLock ? EOwnerThread : EOwnerProcess)!=KErrNone) |
|
1144 { |
|
1145 h->iChunkHandle = 0; |
|
1146 return NULL; |
|
1147 } |
|
1148 } |
|
1149 |
|
1150 if (aMode & EChunkHeapSwitchTo) |
|
1151 User::SwitchHeap(h); |
|
1152 |
|
1153 h->iHandles = &h->iChunkHandle; |
|
1154 if (!aSingleThread) |
|
1155 { |
|
1156 // now change the thread-relative chunk/semaphore handles into process-relative handles |
|
1157 h->iHandleCount = 2; |
|
1158 if(duplicateLock) |
|
1159 { |
|
1160 RHandleBase s = h->iLock; |
|
1161 r = h->iLock.Duplicate(RThread()); |
|
1162 s.Close(); |
|
1163 } |
|
1164 if (r==KErrNone && (aMode & EChunkHeapDuplicate)) |
|
1165 { |
|
1166 r = ((RChunk*)&h->iChunkHandle)->Duplicate(RThread()); |
|
1167 if (r!=KErrNone) |
|
1168 h->iLock.Close(), h->iChunkHandle=0; |
|
1169 } |
|
1170 } |
|
1171 else |
|
1172 { |
|
1173 h->iHandleCount = 1; |
|
1174 if (aMode & EChunkHeapDuplicate) |
|
1175 r = ((RChunk*)&h->iChunkHandle)->Duplicate(RThread(), EOwnerThread); |
|
1176 } |
|
1177 |
|
1178 // return the heap address |
|
1179 return (r==KErrNone) ? h : NULL; |
|
1180 } |
|
1181 |
|
1182 |
|
1183 |
|
1184 #define UserTestDebugMaskBit(bit) (TBool)(UserSvr::DebugMask(bit>>5) & (1<<(bit&31))) |
|
1185 |
|
1186 _LIT(KLitDollarHeap,"$HEAP"); |
|
1187 EXPORT_C TInt UserHeap::CreateThreadHeap(SStdEpocThreadCreateInfo& aInfo, RHeap*& aHeap, TInt aAlign, TBool aSingleThread) |
|
1188 /** |
|
1189 @internalComponent |
|
1190 */ |
|
1191 // |
|
1192 // Create a user-side heap |
|
1193 // |
|
1194 { |
|
1195 TInt page_size; |
|
1196 UserHal::PageSizeInBytes(page_size); |
|
1197 TInt minLength = _ALIGN_UP(aInfo.iHeapInitialSize, page_size); |
|
1198 TInt maxLength = Max(aInfo.iHeapMaxSize, minLength); |
|
1199 if (UserTestDebugMaskBit(96)) // 96 == KUSERHEAPTRACE in nk_trace.h |
|
1200 aInfo.iFlags |= ETraceHeapAllocs; |
|
1201 |
|
1202 // Create the thread's heap chunk. |
|
1203 RChunk c; |
|
1204 TChunkCreateInfo createInfo; |
|
1205 createInfo.SetThreadHeap(0, maxLength, KLitDollarHeap()); // Initialise with no memory committed. |
|
1206 |
|
1207 // Set the paging policy of the heap chunk based on the thread's paging policy. |
|
1208 TUint pagingflags = aInfo.iFlags & EThreadCreateFlagPagingMask; |
|
1209 switch (pagingflags) |
|
1210 { |
|
1211 case EThreadCreateFlagPaged: |
|
1212 createInfo.SetPaging(TChunkCreateInfo::EPaged); |
|
1213 break; |
|
1214 case EThreadCreateFlagUnpaged: |
|
1215 createInfo.SetPaging(TChunkCreateInfo::EUnpaged); |
|
1216 break; |
|
1217 case EThreadCreateFlagPagingUnspec: |
|
1218 // Leave the chunk paging policy unspecified so the process's |
|
1219 // paging policy is used. |
|
1220 break; |
|
1221 } |
|
1222 |
|
1223 TInt r = c.Create(createInfo); |
|
1224 if (r!=KErrNone) |
|
1225 return r; |
|
1226 |
|
1227 aHeap = ChunkHeap(c, minLength, page_size, maxLength, aAlign, aSingleThread, EChunkHeapSwitchTo|EChunkHeapDuplicate); |
|
1228 c.Close(); |
|
1229 if (!aHeap) |
|
1230 return KErrNoMemory; |
|
1231 if (aInfo.iFlags & ETraceHeapAllocs) |
|
1232 { |
|
1233 aHeap->iFlags |= RHeap::ETraceAllocs; |
|
1234 BTraceContext8(BTrace::EHeap, BTrace::EHeapCreate,(TUint32)aHeap, RHeap::EAllocCellSize); |
|
1235 TInt handle = aHeap->ChunkHandle(); |
|
1236 TInt chunkId = ((RHandleBase&)handle).BTraceId(); |
|
1237 BTraceContext8(BTrace::EHeap, BTrace::EHeapChunkCreate, (TUint32)aHeap, chunkId); |
|
1238 } |
|
1239 if (aInfo.iFlags & EMonitorHeapMemory) |
|
1240 aHeap->iFlags |= RHeap::EMonitorMemory; |
|
1241 return KErrNone; |
|
1242 } |
|
1243 |
|
1244 #endif // __KERNEL_MODE__ |
|
1245 |
|
1246 void RHeap::WalkCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen) |
|
1247 { |
|
1248 (void)aCell; |
|
1249 SHeapCellInfo& info = *(SHeapCellInfo*)aPtr; |
|
1250 switch(aType) |
|
1251 { |
|
1252 case EGoodAllocatedCell: |
|
1253 { |
|
1254 ++info.iTotalAlloc; |
|
1255 info.iTotalAllocSize += (aLen-EAllocCellSize); |
|
1256 #if defined(_DEBUG) |
|
1257 RHeap& h = *info.iHeap; |
|
1258 if ( ((SDebugCell*)aCell)->nestingLevel == h.iNestingLevel ) |
|
1259 { |
|
1260 if (++info.iLevelAlloc==1) |
|
1261 info.iStranded = (SDebugCell*)aCell; |
|
1262 #ifdef __KERNEL_MODE__ |
|
1263 if (KDebugNum(KSERVER) || KDebugNum(KTESTFAST)) |
|
1264 { |
|
1265 // __KTRACE_OPT(KSERVER,Kern::Printf("LEAKED KERNEL HEAP CELL @ %08x : len=%d", aCell, aLen)); |
|
1266 Kern::Printf("LEAKED KERNEL HEAP CELL @ %08x : len=%d", aCell, aLen); |
|
1267 TLinAddr base = ((TLinAddr)aCell)&~0x0f; |
|
1268 TLinAddr end = ((TLinAddr)aCell)+(TLinAddr)aLen; |
|
1269 while(base<end) |
|
1270 { |
|
1271 const TUint32* p = (const TUint32*)base; |
|
1272 Kern::Printf("%08x: %08x %08x %08x %08x", p, p[0], p[1], p[2], p[3]); |
|
1273 base += 16; |
|
1274 } |
|
1275 } |
|
1276 #endif |
|
1277 } |
|
1278 #endif |
|
1279 break; |
|
1280 } |
|
1281 case EGoodFreeCell: |
|
1282 ++info.iTotalFree; |
|
1283 break; |
|
1284 case EBadAllocatedCellSize: |
|
1285 HEAP_PANIC(ETHeapBadAllocatedCellSize); |
|
1286 case EBadAllocatedCellAddress: |
|
1287 HEAP_PANIC(ETHeapBadAllocatedCellAddress); |
|
1288 case EBadFreeCellAddress: |
|
1289 HEAP_PANIC(ETHeapBadFreeCellAddress); |
|
1290 case EBadFreeCellSize: |
|
1291 HEAP_PANIC(ETHeapBadFreeCellSize); |
|
1292 default: |
|
1293 HEAP_PANIC(ETHeapWalkBadCellType); |
|
1294 } |
|
1295 } |
|
1296 |
|
1297 TInt RHeap::DoCountAllocFree(TInt& aFree) |
|
1298 { |
|
1299 SHeapCellInfo info; |
|
1300 memclr(&info, sizeof(info)); |
|
1301 info.iHeap = this; |
|
1302 Walk(&WalkCheckCell, &info); |
|
1303 aFree = info.iTotalFree; |
|
1304 return info.iTotalAlloc; |
|
1305 } |
|
1306 |
|
1307 |
|
1308 UEXPORT_C TInt RHeap::DebugFunction(TInt aFunc, TAny* a1, TAny* a2) |
|
1309 /** |
|
1310 @internalComponent |
|
1311 */ |
|
1312 { |
|
1313 TInt r = KErrNone; |
|
1314 switch(aFunc) |
|
1315 { |
|
1316 case RAllocator::ECount: |
|
1317 r = DoCountAllocFree(*(TInt*)a1); |
|
1318 break; |
|
1319 case RAllocator::EMarkStart: |
|
1320 __DEBUG_ONLY(DoMarkStart()); |
|
1321 break; |
|
1322 case RAllocator::EMarkEnd: |
|
1323 __DEBUG_ONLY( r = DoMarkEnd((TInt)a1) ); |
|
1324 break; |
|
1325 case RAllocator::ECheck: |
|
1326 r = DoCheckHeap((SCheckInfo*)a1); |
|
1327 break; |
|
1328 case RAllocator::ESetFail: |
|
1329 __DEBUG_ONLY(DoSetAllocFail((TAllocFail)(TInt)a1, (TInt)a2)); |
|
1330 break; |
|
1331 case RAllocator::ESetBurstFail: |
|
1332 #if _DEBUG |
|
1333 { |
|
1334 SRAllocatorBurstFail* fail = (SRAllocatorBurstFail*) a2; |
|
1335 DoSetAllocFail((TAllocFail)(TInt)a1, fail->iRate, fail->iBurst); |
|
1336 } |
|
1337 #endif |
|
1338 break; |
|
1339 |
|
1340 case RAllocator::ECheckFailure: |
|
1341 // iRand will be incremented for each EFailNext, EBurstFailNext, |
|
1342 // EDeterministic and EBurstDeterministic failure. |
|
1343 r = iRand; |
|
1344 break; |
|
1345 |
|
1346 case RAllocator::ECopyDebugInfo: |
|
1347 { |
|
1348 TInt nestingLevel = ((SDebugCell*)a1)[-1].nestingLevel; |
|
1349 ((SDebugCell*)a2)[-1].nestingLevel = nestingLevel; |
|
1350 break; |
|
1351 } |
|
1352 case RHeap::EWalk: |
|
1353 Walk((TWalkFunc)a1, a2); |
|
1354 break; |
|
1355 default: |
|
1356 return KErrNotSupported; |
|
1357 } |
|
1358 return r; |
|
1359 } |
|
1360 |
|
1361 |
|
1362 |
|
1363 |
|
1364 void RHeap::Walk(TWalkFunc aFunc, TAny* aPtr) |
|
1365 // |
|
1366 // Walk the heap calling the info function. |
|
1367 // |
|
1368 { |
|
1369 |
|
1370 Lock(); |
|
1371 SCell* pC = (SCell*)iBase; // allocated cells |
|
1372 SCell* pF = &iFree; // free cells |
|
1373 FOREVER |
|
1374 { |
|
1375 pF = pF->next; // next free cell |
|
1376 if (!pF) |
|
1377 pF = (SCell*)iTop; // to make size checking work |
|
1378 else if ( (TUint8*)pF>=iTop || (pF->next && pF->next<=pF) ) |
|
1379 { |
|
1380 if (iFlags & ETraceAllocs) |
|
1381 BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pF+EFreeCellSize, 0); |
|
1382 // free cell pointer off the end or going backwards |
|
1383 Unlock(); |
|
1384 (*aFunc)(aPtr, EBadFreeCellAddress, pF, 0); |
|
1385 return; |
|
1386 } |
|
1387 else |
|
1388 { |
|
1389 TInt l = pF->len; |
|
1390 if (l<iMinCell || (l & (iAlign-1))) |
|
1391 { |
|
1392 if (iFlags & ETraceAllocs) |
|
1393 BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pF+EFreeCellSize, l-EFreeCellSize); |
|
1394 // free cell length invalid |
|
1395 Unlock(); |
|
1396 (*aFunc)(aPtr, EBadFreeCellSize, pF, l); |
|
1397 return; |
|
1398 } |
|
1399 } |
|
1400 while (pC!=pF) // walk allocated cells up to next free cell |
|
1401 { |
|
1402 TInt l = pC->len; |
|
1403 if (l<iMinCell || (l & (iAlign-1))) |
|
1404 { |
|
1405 if (iFlags & ETraceAllocs) |
|
1406 BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pC+EAllocCellSize, l-EAllocCellSize); |
|
1407 // allocated cell length invalid |
|
1408 Unlock(); |
|
1409 (*aFunc)(aPtr, EBadAllocatedCellSize, pC, l); |
|
1410 return; |
|
1411 } |
|
1412 (*aFunc)(aPtr, EGoodAllocatedCell, pC, l); |
|
1413 SCell* pN = __NEXT_CELL(pC); |
|
1414 if (pN > pF) |
|
1415 { |
|
1416 if (iFlags & ETraceAllocs) |
|
1417 BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pC+EAllocCellSize, l-EAllocCellSize); |
|
1418 // cell overlaps next free cell |
|
1419 Unlock(); |
|
1420 (*aFunc)(aPtr, EBadAllocatedCellAddress, pC, l); |
|
1421 return; |
|
1422 } |
|
1423 pC = pN; |
|
1424 } |
|
1425 if ((TUint8*)pF == iTop) |
|
1426 break; // reached end of heap |
|
1427 pC = __NEXT_CELL(pF); // step to next allocated cell |
|
1428 (*aFunc)(aPtr, EGoodFreeCell, pF, pF->len); |
|
1429 } |
|
1430 Unlock(); |
|
1431 } |
|
1432 |
|
1433 TInt RHeap::DoCheckHeap(SCheckInfo* aInfo) |
|
1434 { |
|
1435 (void)aInfo; |
|
1436 SHeapCellInfo info; |
|
1437 memclr(&info, sizeof(info)); |
|
1438 info.iHeap = this; |
|
1439 Walk(&WalkCheckCell, &info); |
|
1440 #if defined(_DEBUG) |
|
1441 if (!aInfo) |
|
1442 return KErrNone; |
|
1443 TInt expected = aInfo->iCount; |
|
1444 TInt actual = aInfo->iAll ? info.iTotalAlloc : info.iLevelAlloc; |
|
1445 if (actual!=expected && !iTestData) |
|
1446 { |
|
1447 #ifdef __KERNEL_MODE__ |
|
1448 Kern::Fault("KERN-ALLOC COUNT", (expected<<16)|actual ); |
|
1449 #else |
|
1450 User::Panic(_L("ALLOC COUNT"), (expected<<16)|actual ); |
|
1451 #endif |
|
1452 } |
|
1453 #endif |
|
1454 return KErrNone; |
|
1455 } |
|
1456 |
|
1457 #ifdef _DEBUG |
|
1458 void RHeap::DoMarkStart() |
|
1459 { |
|
1460 if (iNestingLevel==0) |
|
1461 iAllocCount=0; |
|
1462 iNestingLevel++; |
|
1463 } |
|
1464 |
|
1465 TUint32 RHeap::DoMarkEnd(TInt aExpected) |
|
1466 { |
|
1467 if (iNestingLevel==0) |
|
1468 return 0; |
|
1469 SHeapCellInfo info; |
|
1470 SHeapCellInfo* p = iTestData ? (SHeapCellInfo*)iTestData : &info; |
|
1471 memclr(p, sizeof(info)); |
|
1472 p->iHeap = this; |
|
1473 Walk(&WalkCheckCell, p); |
|
1474 if (p->iLevelAlloc != aExpected && !iTestData) |
|
1475 return (TUint32)(p->iStranded + 1); |
|
1476 if (--iNestingLevel == 0) |
|
1477 iAllocCount = 0; |
|
1478 return 0; |
|
1479 } |
|
1480 |
|
1481 void ResetAllocCellLevels(TAny* aPtr, RHeap::TCellType aType, TAny* aCell, TInt aLen) |
|
1482 { |
|
1483 (void)aPtr; |
|
1484 (void)aLen; |
|
1485 RHeap::SDebugCell* cell = (RHeap::SDebugCell*)aCell; |
|
1486 if (aType == RHeap::EGoodAllocatedCell) |
|
1487 { |
|
1488 cell->nestingLevel = 0; |
|
1489 } |
|
1490 } |
|
1491 |
|
1492 void RHeap::DoSetAllocFail(TAllocFail aType, TInt aRate) |
|
1493 {// Default to a burst mode of 1, as aType may be a burst type. |
|
1494 DoSetAllocFail(aType, aRate, 1); |
|
1495 } |
|
1496 |
|
1497 // Don't change as the ETHeapBadDebugFailParameter check below and the API |
|
1498 // documentation rely on this being 16 for RHeap. |
|
1499 LOCAL_D const TInt KBurstFailRateShift = 16; |
|
1500 LOCAL_D const TInt KBurstFailRateMask = (1 << KBurstFailRateShift) - 1; |
|
1501 |
|
1502 void RHeap::DoSetAllocFail(TAllocFail aType, TInt aRate, TUint aBurst) |
|
1503 { |
|
1504 if (aType==EReset) |
|
1505 { |
|
1506 // reset levels of all allocated cells to 0 |
|
1507 // this should prevent subsequent tests failing unnecessarily |
|
1508 iFailed = EFalse; // Reset for ECheckFailure relies on this. |
|
1509 Walk(&ResetAllocCellLevels, NULL); |
|
1510 // reset heap allocation mark as well |
|
1511 iNestingLevel=0; |
|
1512 iAllocCount=0; |
|
1513 aType=ENone; |
|
1514 } |
|
1515 |
|
1516 switch (aType) |
|
1517 { |
|
1518 case EBurstRandom: |
|
1519 case EBurstTrueRandom: |
|
1520 case EBurstDeterministic: |
|
1521 case EBurstFailNext: |
|
1522 // If the fail type is a burst type then iFailRate is split in 2: |
|
1523 // the 16 lsbs are the fail rate and the 16 msbs are the burst length. |
|
1524 if (TUint(aRate) > (TUint)KMaxTUint16 || aBurst > KMaxTUint16) |
|
1525 HEAP_PANIC(ETHeapBadDebugFailParameter); |
|
1526 |
|
1527 iFailed = EFalse; |
|
1528 iFailType = aType; |
|
1529 iFailRate = (aRate == 0) ? 1 : aRate; |
|
1530 iFailAllocCount = -iFailRate; |
|
1531 iFailRate = iFailRate | (aBurst << KBurstFailRateShift); |
|
1532 break; |
|
1533 |
|
1534 default: |
|
1535 iFailed = EFalse; |
|
1536 iFailType = aType; |
|
1537 iFailRate = (aRate == 0) ? 1 : aRate; // A rate of <1 is meaningless |
|
1538 iFailAllocCount = 0; |
|
1539 break; |
|
1540 } |
|
1541 |
|
1542 // Set up iRand for either: |
|
1543 // - random seed value, or |
|
1544 // - a count of the number of failures so far. |
|
1545 iRand = 0; |
|
1546 #ifndef __KERNEL_MODE__ |
|
1547 switch (iFailType) |
|
1548 { |
|
1549 case ETrueRandom: |
|
1550 case EBurstTrueRandom: |
|
1551 { |
|
1552 TTime time; |
|
1553 time.HomeTime(); |
|
1554 TInt64 seed = time.Int64(); |
|
1555 iRand = Math::Rand(seed); |
|
1556 break; |
|
1557 } |
|
1558 case ERandom: |
|
1559 case EBurstRandom: |
|
1560 { |
|
1561 TInt64 seed = 12345; |
|
1562 iRand = Math::Rand(seed); |
|
1563 break; |
|
1564 } |
|
1565 default: |
|
1566 break; |
|
1567 } |
|
1568 #endif |
|
1569 } |
|
1570 |
|
1571 TBool RHeap::CheckForSimulatedAllocFail() |
|
1572 // |
|
1573 // Check to see if the user has requested simulated alloc failure, and if so possibly |
|
1574 // Return ETrue indicating a failure. |
|
1575 // |
|
1576 { |
|
1577 // For burst mode failures iFailRate is shared |
|
1578 TUint16 rate = (TUint16)(iFailRate & KBurstFailRateMask); |
|
1579 TUint16 burst = (TUint16)(iFailRate >> KBurstFailRateShift); |
|
1580 TBool r = EFalse; |
|
1581 switch (iFailType) |
|
1582 { |
|
1583 #ifndef __KERNEL_MODE__ |
|
1584 case ERandom: |
|
1585 case ETrueRandom: |
|
1586 if (++iFailAllocCount>=iFailRate) |
|
1587 { |
|
1588 iFailAllocCount=0; |
|
1589 if (!iFailed) // haven't failed yet after iFailRate allocations so fail now |
|
1590 return(ETrue); |
|
1591 iFailed=EFalse; |
|
1592 } |
|
1593 else |
|
1594 { |
|
1595 if (!iFailed) |
|
1596 { |
|
1597 TInt64 seed=iRand; |
|
1598 iRand=Math::Rand(seed); |
|
1599 if (iRand%iFailRate==0) |
|
1600 { |
|
1601 iFailed=ETrue; |
|
1602 return(ETrue); |
|
1603 } |
|
1604 } |
|
1605 } |
|
1606 break; |
|
1607 |
|
1608 case EBurstRandom: |
|
1609 case EBurstTrueRandom: |
|
1610 if (++iFailAllocCount < 0) |
|
1611 { |
|
1612 // We haven't started failing yet so should we now? |
|
1613 TInt64 seed = iRand; |
|
1614 iRand = Math::Rand(seed); |
|
1615 if (iRand % rate == 0) |
|
1616 {// Fail now. Reset iFailAllocCount so we fail burst times |
|
1617 iFailAllocCount = 0; |
|
1618 r = ETrue; |
|
1619 } |
|
1620 } |
|
1621 else |
|
1622 { |
|
1623 if (iFailAllocCount < burst) |
|
1624 {// Keep failing for burst times |
|
1625 r = ETrue; |
|
1626 } |
|
1627 else |
|
1628 {// We've now failed burst times so start again. |
|
1629 iFailAllocCount = -(rate - 1); |
|
1630 } |
|
1631 } |
|
1632 break; |
|
1633 #endif |
|
1634 case EDeterministic: |
|
1635 if (++iFailAllocCount%iFailRate==0) |
|
1636 { |
|
1637 r=ETrue; |
|
1638 iRand++; // Keep count of how many times we have failed |
|
1639 } |
|
1640 break; |
|
1641 |
|
1642 case EBurstDeterministic: |
|
1643 // This will fail burst number of times, every rate attempts. |
|
1644 if (++iFailAllocCount >= 0) |
|
1645 { |
|
1646 if (iFailAllocCount == burst - 1) |
|
1647 {// This is the burst time we have failed so make it the last by |
|
1648 // reseting counts so we next fail after rate attempts. |
|
1649 iFailAllocCount = -rate; |
|
1650 } |
|
1651 r = ETrue; |
|
1652 iRand++; // Keep count of how many times we have failed |
|
1653 } |
|
1654 break; |
|
1655 |
|
1656 case EFailNext: |
|
1657 if ((++iFailAllocCount%iFailRate)==0) |
|
1658 { |
|
1659 iFailType=ENone; |
|
1660 r=ETrue; |
|
1661 iRand++; // Keep count of how many times we have failed |
|
1662 } |
|
1663 break; |
|
1664 |
|
1665 case EBurstFailNext: |
|
1666 if (++iFailAllocCount >= 0) |
|
1667 { |
|
1668 if (iFailAllocCount == burst - 1) |
|
1669 {// This is the burst time we have failed so make it the last. |
|
1670 iFailType = ENone; |
|
1671 } |
|
1672 r = ETrue; |
|
1673 iRand++; // Keep count of how many times we have failed |
|
1674 } |
|
1675 break; |
|
1676 default: |
|
1677 break; |
|
1678 } |
|
1679 return r; |
|
1680 } |
|
1681 #endif // ifdef _DEBUG |
|
1682 |
|
1683 UEXPORT_C TInt RHeap::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1) |
|
1684 { |
|
1685 return RAllocator::Extension_(aExtensionId, a0, a1); |
|
1686 } |
|
1687 |
|
1688 #if defined(__HEAP_MACHINE_CODED__) && !defined(_DEBUG) |
|
1689 GLDEF_C void RHeap_PanicBadAllocatedCellSize() |
|
1690 { |
|
1691 HEAP_PANIC(ETHeapBadAllocatedCellSize); |
|
1692 } |
|
1693 |
|
1694 GLDEF_C void RHeap_PanicBadNextCell() |
|
1695 { |
|
1696 HEAP_PANIC(ETHeapFreeBadNextCell); |
|
1697 } |
|
1698 |
|
1699 GLDEF_C void RHeap_PanicBadPrevCell() |
|
1700 { |
|
1701 HEAP_PANIC(ETHeapFreeBadPrevCell); |
|
1702 } |
|
1703 |
|
1704 GLDEF_C void RHeap_PanicBadCellAddress() |
|
1705 { |
|
1706 HEAP_PANIC(ETHeapBadCellAddress); |
|
1707 } |
|
1708 #endif |
|
1709 |
|
1710 |
|
1711 |
|
1712 |
|
1713 |