kernel/eka/common/heap.cpp
branchRCL_3
changeset 257 3e88ff8f41d5
child 258 880ff05ad710
equal deleted inserted replaced
256:c1f20ce4abcf 257:3e88ff8f41d5
       
     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