diff -r 5e441a173c63 -r d9f1e5bfe28c kernel/eka/common/heap.cpp --- a/kernel/eka/common/heap.cpp Mon May 24 18:45:46 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1713 +0,0 @@ -// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of the License "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// e32\common\heap.cpp -// -// - -#include "common.h" -#ifdef __KERNEL_MODE__ -#include -#endif - -#ifdef _DEBUG -#define __SIMULATE_ALLOC_FAIL(s) if (CheckForSimulatedAllocFail()) {s} -#define __CHECK_CELL(p) CheckCell(p) -#define __ZAP_CELL(p) memset( ((TUint8*)p) + RHeap::EAllocCellSize, 0xde, p->len - RHeap::EAllocCellSize) -#define __DEBUG_SAVE(p) TInt dbgNestLevel = ((SDebugCell*)p)->nestingLevel -#define __DEBUG_RESTORE(p) ((SDebugCell*)(((TUint8*)p)-EAllocCellSize))->nestingLevel = dbgNestLevel -#else -#define __SIMULATE_ALLOC_FAIL(s) -#define __CHECK_CELL(p) -#define __ZAP_CELL(p) -#define __DEBUG_SAVE(p) -#define __DEBUG_RESTORE(p) -#endif - -#define __NEXT_CELL(p) ((SCell*)(((TUint8*)p)+p->len)) - -#define __POWER_OF_2(x) ((TUint32)((x)^((x)-1))>=(TUint32)(x)) - -#define __MEMORY_MONITOR_CHECK_CELL(p) \ - { \ - TLinAddr m = TLinAddr(iAlign-1); \ - SCell* c = (SCell*)(((TUint8*)p)-EAllocCellSize); \ - if((c->len & m) || (c->leniTop)) \ - BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)p, (TUint32)c->len-EAllocCellSize); \ - } - -/** -@SYMPatchable -@publishedPartner -@released - -Defines the minimum cell size of a heap. - -The constant can be changed at ROM build time using patchdata OBY keyword. -*/ -#ifdef __X86GCC__ // For X86GCC we dont use the proper data import attribute -#undef IMPORT_D // since the constant is not really imported. GCC doesn't -#define IMPORT_D // allow imports from self. -#endif -IMPORT_D extern const TInt KHeapMinCellSize; - -/** -@SYMPatchable -@publishedPartner -@released - -This constant defines the ratio that determines the amount of hysteresis between heap growing and heap -shrinking. -It is a 32-bit fixed point number where the radix point is defined to be -between bits 7 and 8 (where the LSB is bit 0) i.e. using standard notation, a Q8 or a fx24.8 -fixed point number. For example, for a ratio of 2.0, set KHeapShrinkHysRatio=0x200. - -The heap shrinking hysteresis value is calculated to be: -@code -KHeapShrinkHysRatio*(iGrowBy>>8) -@endcode -where iGrowBy is a page aligned value set by the argument, aGrowBy, to the RHeap constructor. -The default hysteresis value is iGrowBy bytes i.e. KHeapShrinkHysRatio=2.0. - -Memory usage may be improved by reducing the heap shrinking hysteresis -by setting 1.0 < KHeapShrinkHysRatio < 2.0. Heap shrinking hysteresis is disabled/removed -when KHeapShrinkHysRatio <= 1.0. - -The constant can be changed at ROM build time using patchdata OBY keyword. -*/ -IMPORT_D extern const TInt KHeapShrinkHysRatio; - -#pragma warning( disable : 4705 ) // statement has no effect -UEXPORT_C RHeap::RHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread) -/** -@internalComponent -*/ -// -// Constructor for fixed size heap -// - : iMinLength(aMaxLength), iMaxLength(aMaxLength), iOffset(0), iGrowBy(0), iChunkHandle(0), - iNestingLevel(0), iAllocCount(0), iFailType(ENone), iTestData(NULL) - { - iAlign = aAlign ? aAlign : ECellAlignment; - iPageSize = 0; - iFlags = aSingleThread ? (ESingleThreaded|EFixedSize) : EFixedSize; - Initialise(); - } -#pragma warning( default : 4705 ) - - - - -UEXPORT_C RHeap::RHeap(TInt aChunkHandle, TInt aOffset, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread) -/** -@internalComponent -*/ -// -// Constructor for chunk heaps. -// - : iOffset(aOffset), iChunkHandle(aChunkHandle), - iNestingLevel(0), iAllocCount(0), iFailType(ENone), iTestData(NULL) - { - TInt sz = iBase - ((TUint8*)this - iOffset); - GET_PAGE_SIZE(iPageSize); - __ASSERT_ALWAYS(iOffset>=0, HEAP_PANIC(ETHeapNewBadOffset)); - iMinLength = Max(aMinLength, sz + EAllocCellSize); - iMinLength = _ALIGN_UP(iMinLength, iPageSize); - iMaxLength = Max(aMaxLength, iMinLength); - iMaxLength = _ALIGN_UP(iMaxLength, iPageSize); - iGrowBy = _ALIGN_UP(aGrowBy, iPageSize); - iFlags = aSingleThread ? ESingleThreaded : 0; - iAlign = aAlign ? aAlign : ECellAlignment; - Initialise(); - } - - - - -UEXPORT_C TAny* RHeap::operator new(TUint aSize, TAny* aBase) __NO_THROW -/** -@internalComponent -*/ - { - __ASSERT_ALWAYS(aSize>=sizeof(RHeap), HEAP_PANIC(ETHeapNewBadSize)); - RHeap* h = (RHeap*)aBase; - h->iAlign = 0x80000000; // garbage value - h->iBase = ((TUint8*)aBase) + aSize; - return aBase; - } - -void RHeap::Initialise() -// -// Initialise the heap. -// - { - - __ASSERT_ALWAYS((TUint32)iAlign>=sizeof(TAny*) && __POWER_OF_2(iAlign), HEAP_PANIC(ETHeapNewBadAlignment)); - iCellCount = 0; - iTotalAllocSize = 0; - iBase = (TUint8*)Align(iBase + EAllocCellSize); - iBase -= EAllocCellSize; - TInt b = iBase - ((TUint8*)this - iOffset); - TInt len = _ALIGN_DOWN(iMinLength - b, iAlign); - iTop = iBase + len; - iMinLength = iTop - ((TUint8*)this - iOffset); - iMinCell = Align(KHeapMinCellSize + Max((TInt)EAllocCellSize, (TInt)EFreeCellSize)); -#ifdef _DEBUG - memset(iBase, 0xa5, len); -#endif - SCell* pM=(SCell*)iBase; // First free cell - iFree.next=pM; // Free list points to first free cell - iFree.len=0; // Stop free from joining this with a free block - pM->next=NULL; // Terminate the free list - pM->len=len; // Set the size of the free cell - } - -#ifdef _DEBUG -void RHeap::CheckCell(const SCell* aCell) const - { - TLinAddr m = TLinAddr(iAlign - 1); - - __ASSERT_DEBUG(!(aCell->len & m), HEAP_PANIC(ETHeapBadCellAddress)); - __ASSERT_DEBUG(aCell->len >= iMinCell, HEAP_PANIC(ETHeapBadCellAddress)); - __ASSERT_DEBUG((TUint8*)aCell>=iBase, HEAP_PANIC(ETHeapBadCellAddress)); - __ASSERT_DEBUG((TUint8*)__NEXT_CELL(aCell)<=iTop, HEAP_PANIC(ETHeapBadCellAddress)); - } -#endif - -UEXPORT_C RHeap::SCell* RHeap::GetAddress(const TAny* aCell) const -// -// As much as possible, check a cell address and backspace it -// to point at the cell header. -// - { - - TLinAddr m = TLinAddr(iAlign - 1); - __ASSERT_ALWAYS(!(TLinAddr(aCell)&m), HEAP_PANIC(ETHeapBadCellAddress)); - - SCell* pC = (SCell*)(((TUint8*)aCell)-EAllocCellSize); - __CHECK_CELL(pC); - - return pC; - } - - - - -UEXPORT_C TInt RHeap::AllocLen(const TAny* aCell) const -/** -Gets the length of the available space in the specified allocated cell. - -@param aCell A pointer to the allocated cell. - -@return The length of the available space in the allocated cell. - -@panic USER 42 if aCell does not point to a valid cell. -*/ - { - - SCell* pC = GetAddress(aCell); - return pC->len - EAllocCellSize; - } - - - - - -#if !defined(__HEAP_MACHINE_CODED__) || defined(_DEBUG) -RHeap::SCell* RHeap::DoAlloc(TInt aSize, SCell*& aLastFree) -// -// Allocate without growing. aSize includes cell header and alignment. -// Lock already held. -// - { - SCell* pP = &iFree; - SCell* pC = pP->next; - for (; pC; pP=pC, pC=pC->next) // Scan the free list - { - __CHECK_CELL(pC); - SCell* pE; - if (pC->len >= aSize) // Block size bigger than request - { - if (pC->len - aSize < iMinCell) // Leftover must be large enough to hold an SCell - { - aSize = pC->len; // It isn't, so take it all - pE = pC->next; // Set the next field - } - else - { - pE = (SCell*)(((TUint8*)pC)+aSize); // Take amount required - pE->len = pC->len - aSize; // Initialize new free cell - pE->next = pC->next; - } - pP->next = pE; // Update previous pointer - pC->len = aSize; // Set control size word -#if defined(_DEBUG) - ((SDebugCell*)pC)->nestingLevel = iNestingLevel; - ((SDebugCell*)pC)->allocCount = ++iAllocCount; -#endif - return pC; - } - } - aLastFree = pP; - return NULL; - } -#endif - - - - -UEXPORT_C TAny* RHeap::Alloc(TInt aSize) -/** -Allocates a cell of the specified size from the heap. - -If there is insufficient memory available on the heap from which to allocate -a cell of the required size, the function returns NULL. - -The cell is aligned according to the alignment value specified at construction, -or the default alignment value, if an explict value was not specified. - -The resulting size of the allocated cell may be rounded up to a -value greater than aSize, but is guaranteed to be not less than aSize. - -@param aSize The -size of the cell to be allocated from the heap - -@return A pointer to the allocated cell. NULL if there is insufficient memory - available. - -@panic USER 47 if the maximum unsigned value of aSize is greater than or equal - to the value of KMaxTInt/2; for example, calling Alloc(-1) raises - this panic. - -@see KMaxTInt -*/ - { - - __CHECK_THREAD_STATE; - __ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize)); - __SIMULATE_ALLOC_FAIL(return NULL;) - - TInt origSize = aSize; - aSize = Max(Align(aSize + EAllocCellSize), iMinCell); - SCell* pL = NULL; - Lock(); - SCell* pC = (SCell*)DoAlloc(aSize, pL); - if (!pC && !(iFlags & EFixedSize)) - { - // try to grow chunk heap - TInt r = TryToGrowHeap(aSize, pL); - if (r==KErrNone) - pC = DoAlloc(aSize, pL); - } - if (pC) - ++iCellCount, iTotalAllocSize += (pC->len - EAllocCellSize); - Unlock(); - if (pC) - { - TAny* result=((TUint8*)pC) + EAllocCellSize; - if (iFlags & ETraceAllocs) - { - TUint32 traceData[2]; - traceData[0] = AllocLen(result); - traceData[1] = origSize; - BTraceContextN(BTrace::EHeap, BTrace::EHeapAlloc, (TUint32)this, (TUint32)result, traceData, sizeof(traceData)); - } -#ifdef __KERNEL_MODE__ - memclr(result, pC->len - EAllocCellSize); -#endif - return result; - } - if (iFlags & ETraceAllocs) - BTraceContext8(BTrace::EHeap, BTrace::EHeapAllocFail, (TUint32)this, (TUint32)origSize); - return NULL; - } - - - - -TInt RHeap::TryToGrowHeap(TInt aSize, SCell* aLastFree) - { - TBool at_end = IsLastCell(aLastFree); - TInt extra = at_end ? aSize - aLastFree->len : aSize; - extra = (extra + iGrowBy - 1) / iGrowBy; - extra *= iGrowBy; - TInt cur_len = _ALIGN_UP(iTop - ((TUint8*)this - iOffset), iPageSize); - TInt new_len = cur_len + extra; - TInt r = KErrNoMemory; - if (new_len <= iMaxLength) - { - r = SetBrk(new_len); - if (r == KErrNone) - { - if (at_end) - aLastFree->len += extra; - else - { - SCell* pC = (SCell*)iTop; - pC->len = extra; - pC->next = NULL; - aLastFree->next = pC; - } - iTop += extra; - } - } - return r; - } - - - - -#ifndef __KERNEL_MODE__ -EXPORT_C TInt RHeap::Compress() -/** -Compresses the heap. - -The function frees excess committed space from the top -of the heap. The size of the heap is never reduced below the minimum size -specified during creation of the heap. - -@return The space reclaimed. If no space can be reclaimed, then this value - is zero. -*/ - { - - if (iFlags & EFixedSize) - return 0; - TInt r = 0; - Lock(); - SCell* pC = &iFree; - for (; pC->next; pC=pC->next) {} - if (pC!=&iFree) - { - __CHECK_CELL(pC); - if (IsLastCell(pC)) - r = Reduce(pC); - } - Unlock(); - return r; - } -#endif - - - - -#if !defined(__HEAP_MACHINE_CODED__) || defined(_DEBUG) -void RHeap::DoFree(SCell* pC) - { - __ZAP_CELL(pC); - - SCell* pP = &iFree; - SCell* pE = pP->next; - for (; pE && pEnext) {} - if (pE) // Is there a following free cell? - { - SCell* pN = __NEXT_CELL(pC); - __ASSERT_ALWAYS(pN<=pE, HEAP_PANIC(ETHeapFreeBadNextCell)); // Following cell overlaps - if (pN==pE) // Is it adjacent - { - pC->len += pE->len; // Yes - coalesce adjacent free cells - pC->next = pE->next; - } - else // pNnext = pE; // Otherwise just point to it - } - else - pC->next = NULL; // No following free cell - SCell* pN = __NEXT_CELL(pP); // pN=pP=&iFree if no preceding free cell - __ASSERT_ALWAYS(pN<=pC, HEAP_PANIC(ETHeapFreeBadPrevCell)); // Previous cell overlaps - if (pN==pC) // Is it adjacent - { - pP->len += pC->len; // Yes - coalesce adjacent free cells - pP->next = pC->next; - pC = pP; // for size reduction check - } - else // pNnext = pC; // point previous cell to the one being freed - pN = __NEXT_CELL(pC); // End of amalgamated free cell - if ((TUint8*)pN==iTop && !(iFlags & EFixedSize) && - pC->len >= KHeapShrinkHysRatio*(iGrowBy>>8)) - Reduce(pC); - } -#endif - - - - -UEXPORT_C void RHeap::Free(TAny* aCell) -/** -Frees the specified cell and returns it to the heap. - -@param aCell A pointer to a valid cell; this pointer can also be NULL, - in which case the function does nothing and just returns. - -@panic USER 42 if aCell points to an invalid cell. -*/ - { - __CHECK_THREAD_STATE; - if (!aCell) - return; - Lock(); - if (iFlags & EMonitorMemory) - __MEMORY_MONITOR_CHECK_CELL(aCell); - SCell* pC = GetAddress(aCell); - --iCellCount; - iTotalAllocSize -= (pC->len - EAllocCellSize); - DoFree(pC); - if (iFlags & ETraceAllocs) - BTraceContext8(BTrace::EHeap, BTrace::EHeapFree, (TUint32)this, (TUint32)aCell); - Unlock(); - } - - - - -TInt RHeap::Reduce(SCell* aCell) - { - TInt reduce=0; - TInt offset=((TUint8*)aCell)-((TUint8*)this - iOffset); - if (offset>=iMinLength) - reduce = aCell->len; // length of entire free cell - else - reduce = offset + aCell->len - iMinLength; // length of free cell past minimum heap size - reduce = _ALIGN_DOWN(reduce, iPageSize); // round down to page multiple - if (reduce<=0) - return 0; // can't reduce this heap - TInt new_cell_len = aCell->len - reduce; // length of last free cell after reduction - if (new_cell_len == 0) - { - // the free cell can be entirely eliminated - SCell* pP = &iFree; - for (; pP->next!=aCell; pP=pP->next) {} - pP->next = NULL; - } - else - { - if (new_cell_len < iMinCell) - { - // max reduction would leave a cell too small - reduce -= iPageSize; - new_cell_len += iPageSize; - } - aCell->len = new_cell_len; // reduce the cell length - } - iTop -= reduce; - TInt new_len = _ALIGN_UP(iTop - ((TUint8*)this - iOffset), iPageSize); - TInt r = SetBrk(new_len); - __ASSERT_ALWAYS(r==KErrNone, HEAP_PANIC(ETHeapReduceFailed)); - return reduce; - } - - - - -#ifndef __KERNEL_MODE__ -EXPORT_C void RHeap::Reset() -/** -Frees all allocated cells on this heap. -*/ - { - - Lock(); - if (!(iFlags & EFixedSize)) - { - TInt r = SetBrk(iMinLength); - __ASSERT_ALWAYS(r==KErrNone, HEAP_PANIC(ETHeapResetFailed)); - } - Initialise(); - Unlock(); - } -#endif - - - - -inline void RHeap::FindFollowingFreeCell(SCell* aCell, SCell*& aPrev, SCell*& aNext) -// -// Find the free cell that immediately follows aCell, if one exists -// If found, aNext is set to point to it, else it is set to NULL. -// aPrev is set to the free cell before aCell or the dummy free cell where there are no free cells before aCell. -// Called with lock enabled. -// - { - aPrev = &iFree; - aNext = aPrev->next; - for (; aNext && aNextnext) {} - - if (aNext) // If there is a following free cell, check its directly after aCell. - { - SCell* pNextCell = __NEXT_CELL(aCell); // end of this cell - __ASSERT_ALWAYS(pNextCell<=aNext, (Unlock(), HEAP_PANIC(ETHeapReAllocBadNextCell))); // Following free cell overlaps - if (pNextCell!=aNext) - aNext=NULL; - } - } - - - - -TInt RHeap::TryToGrowCell(SCell* aCell,SCell* aPrev, SCell* aNext, TInt aSize) -// -// Try to grow the heap cell 'aCell' in place, to size 'aSize'. -// Requires the free cell immediately after aCell (aNext), and the free cell prior to -// that (aPrev), to be provided. (As found by FindFollowingFreeCell) -// - - { - TInt extra = aSize - aCell->len; - if (aNext && (aNext->len>=extra)) // Is there a following free cell big enough? - { - if (aNext->len - extra >= iMinCell) // take part of free cell ? - { - SCell* pX = (SCell*)((TUint8*)aNext + extra); // remainder of free cell - pX->next = aNext->next; // remainder->next = original free cell->next - pX->len = aNext->len - extra; // remainder length = original free cell length - extra - aPrev->next = pX; // put remainder into free chain - } - else - { - extra = aNext->len; // Take whole free cell - aPrev->next = aNext->next; // remove from free chain - } -#ifdef __KERNEL_MODE__ - memclr(((TUint8*)aCell) + aCell->len, extra); -#endif - aCell->len += extra; // update reallocated cell length - iTotalAllocSize += extra; - return KErrNone; - } - return KErrGeneral; // No space to grow cell - } - - - - -// UEXPORT_C TAny* RHeap::ReAlloc(TAny* aCell, TInt aSize, TInt aMode) -/** -Increases or decreases the size of an existing cell in the heap. - -If the cell is being decreased in size, then it is guaranteed not to move, -and the function returns the pointer originally passed in aCell. Note that the -length of the cell will be the same if the difference between the old size -and the new size is smaller than the minimum cell size. - -If the cell is being increased in size, i.e. aSize is bigger than its -current size, then the function tries to grow the cell in place. -If successful, then the function returns the pointer originally -passed in aCell. If unsuccessful, then: - -1. if the cell cannot be moved, i.e. aMode has the ENeverMove bit set, then - the function returns NULL. -2. if the cell can be moved, i.e. aMode does not have the ENeverMove bit set, - then the function tries to allocate a new replacement cell, and, if - successful, returns a pointer to the new cell; if unsuccessful, it - returns NULL. - -Note that in debug mode, the function returns NULL if the cell cannot be grown -in place, regardless of whether the ENeverMove bit is set. - -If the reallocated cell is at a different location from the original cell, then -the content of the original cell is copied to the reallocated cell. - -If the supplied pointer, aCell is NULL, then the function attempts to allocate -a new cell, but only if the cell can be moved, i.e. aMode does not have -the ENeverMove bit set. - -Note the following general points: - -1. If reallocation fails, the content of the original cell is preserved. - -2. The resulting size of the re-allocated cell may be rounded up to a value - greater than aSize, but is guaranteed to be not less than aSize. - -@param aCell A pointer to the cell to be reallocated. This may be NULL. - -@param aSize The new size of the cell. This may be bigger or smaller than the - size of the original cell. - -@param aMode Flags controlling the reallocation. The only bit which has any - effect on this function is that defined by the enumeration - ENeverMove of the enum RAllocator::TReAllocMode. - If this is set, then any successful reallocation guarantees not - to have changed the start address of the cell. - By default, this parameter is zero. - -@return A pointer to the reallocated cell. This may be the same as the original - pointer supplied through aCell. NULL if there is insufficient memory to - reallocate the cell, or to grow it in place. - -@panic USER 42, if aCell is not NULL, and does not point to a valid cell. -@panic USER 47, if the maximum unsigned value of aSize is greater - than or equal to KMaxTInt/2. For example, - calling ReAlloc(someptr,-1) raises this panic. - -@see RAllocator::TReAllocMode -*/ -UEXPORT_C TAny* RHeap::ReAlloc(TAny* aCell, TInt aSize, TInt aMode) - { - if (aCell && iFlags&EMonitorMemory) - __MEMORY_MONITOR_CHECK_CELL(aCell); - TAny* retval = ReAllocImpl(aCell, aSize, aMode); - if (iFlags & ETraceAllocs) - { - if (retval) - { - TUint32 traceData[3]; - traceData[0] = AllocLen(retval); - traceData[1] = aSize; - traceData[2] = (TUint32)aCell; - BTraceContextN(BTrace::EHeap, BTrace::EHeapReAlloc,(TUint32)this, (TUint32)retval,traceData, sizeof(traceData)); - } - else - BTraceContext12(BTrace::EHeap, BTrace::EHeapReAllocFail, (TUint32)this, (TUint32)aCell, (TUint32)aSize); - } - return retval; - } -inline TAny* RHeap::ReAllocImpl(TAny* aCell, TInt aSize, TInt aMode) - { - __CHECK_THREAD_STATE; - if (!aCell) - return (aMode & ENeverMove) ? NULL : Alloc(aSize); - __ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize)); - Lock(); - SCell* pC = GetAddress(aCell); - TInt old_len = pC->len; - __DEBUG_SAVE(pC); - aSize = Max(Align(aSize + EAllocCellSize), iMinCell); - if (aSize > old_len) // Trying to grow cell - { - __SIMULATE_ALLOC_FAIL({ Unlock(); return NULL;}) - - // Try to grow cell in place, without reallocation - SCell* pPrev; - SCell* pNext; - FindFollowingFreeCell(pC,pPrev, pNext); - TInt r = TryToGrowCell(pC, pPrev, pNext, aSize); - - if (r==KErrNone) - { - Unlock(); - return aCell; - } - - if (!(aMode & ENeverMove)) - // If moving allowed, try re-alloc. - // If we need to extend heap,and cell is at the end, try and grow in place - { - SCell* pLastFree; - SCell* pNewCell = (SCell*)DoAlloc(aSize, pLastFree); - if (!pNewCell && !(iFlags & EFixedSize)) - // if we need to extend the heap to alloc - { - if (IsLastCell(pC) || (pNext && IsLastCell(pNext))) - // if last used Cell, try and extend heap and then cell - { - TInt r = TryToGrowHeap(aSize - old_len, pLastFree); - if (r==KErrNone) - { - r = TryToGrowCell(pC, pPrev, pPrev->next, aSize); - Unlock(); - __ASSERT_DEBUG(r == KErrNone, HEAP_PANIC(ETHeapCellDidntGrow)); - return aCell; - } - } - else - // try to grow chunk heap and Alloc on it - { - TInt r = TryToGrowHeap(aSize, pLastFree); - if (r==KErrNone) - pNewCell = DoAlloc(aSize, pLastFree); - } - } - - if (pNewCell) - // if we created a new cell, adjust tellies, copy the contents and delete old cell. - { - iCellCount++; - iTotalAllocSize += (pNewCell->len - EAllocCellSize); - - Unlock(); - TUint8* raw = ((TUint8*) pNewCell); - - memcpy(raw + EAllocCellSize, aCell, old_len - EAllocCellSize); -#ifdef __KERNEL_MODE__ - memclr(raw + old_len, pNewCell->len - old_len); -#endif - Free(aCell); - __DEBUG_RESTORE(raw + EAllocCellSize); - return raw + EAllocCellSize; - } - } - else - // No moving, but still posible to extend the heap (if heap extendable) - { - if (!(iFlags & EFixedSize) && (IsLastCell(pC) || (pNext && IsLastCell(pNext)))) - { - SCell* pLastFree = pNext ? pNext : pPrev; - TInt r = TryToGrowHeap(aSize - old_len, pLastFree); - if (r==KErrNone) - { - r = TryToGrowCell(pC, pPrev, pPrev->next, aSize); - Unlock(); - __ASSERT_DEBUG(r==KErrNone, HEAP_PANIC(ETHeapCellDidntGrow)); - return aCell; - } - } - } - Unlock(); - return NULL; - } - if (old_len - aSize >= iMinCell) - { - // cell shrinking, remainder big enough to form a new free cell - SCell* pX = (SCell*)((TUint8*)pC + aSize); // pointer to new free cell - pC->len = aSize; // update cell size - pX->len = old_len - aSize; // size of remainder - iTotalAllocSize -= pX->len; - DoFree(pX); // link new free cell into chain, shrink heap if necessary - } - Unlock(); - return aCell; - } - - - - -#ifndef __KERNEL_MODE__ - -EXPORT_C TInt RHeap::Available(TInt& aBiggestBlock) const -/** -Gets the total free space currently available on the heap and the space -available in the largest free block. - -The space available represents the total space which can be allocated. - -Note that compressing the heap may reduce the total free space available and -the space available in the largest free block. - -@param aBiggestBlock On return, contains the space available - in the largest free block on the heap. - -@return The total free space currently available on the heap. -*/ - { - - TInt total = 0; - TInt max = 0; - Lock(); - SCell* pC = iFree.next; - for (; pC; pC=pC->next) - { - TInt l = pC->len - EAllocCellSize; - if (l > max) - max = l; - total += l; - } - Unlock(); - aBiggestBlock = max; - return total; - } - - - - -EXPORT_C TInt RHeap::AllocSize(TInt& aTotalAllocSize) const -/** -Gets the number of cells allocated on this heap, and the total space -allocated to them. - -@param aTotalAllocSize On return, contains the total space allocated - to the cells. - -@return The number of cells allocated on this heap. -*/ - { - Lock(); - TInt c = iCellCount; - aTotalAllocSize = iTotalAllocSize; - Unlock(); - return c; - } - - - - -EXPORT_C RHeap* UserHeap::FixedHeap(TAny* aBase, TInt aMaxLength, TInt aAlign, TBool aSingleThread) -/** -Creates a fixed length heap at a specified location. - -On successful return from this function, aMaxLength bytes are committed by the chunk. -The heap cannot be extended. - -@param aBase A pointer to the location where the heap is to be constructed. -@param aMaxLength The length of the heap. If the supplied value is less - than KMinHeapSize, it is discarded and the value KMinHeapSize - is used instead. -@param aAlign The alignment of heap cells. -@param aSingleThread Indicates whether single threaded or not. - -@return A pointer to the new heap, or NULL if the heap could not be created. - -@panic USER 56 if aMaxLength is negative. -@panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. -*/ -// -// Force construction of the fixed memory. -// - { - - __ASSERT_ALWAYS(aMaxLength>=0, ::Panic(ETHeapMaxLengthNegative)); - if (aMaxLengthiLock.CreateLocal(); - if (r!=KErrNone) - return NULL; - h->iHandles = (TInt*)&h->iLock; - h->iHandleCount = 1; - } - return h; - } - - -/** -Constructor where minimum and maximum length of the heap can be defined. -It defaults the chunk heap to be created to have use a new local chunk, -to have a grow by value of KMinHeapGrowBy, to be unaligned, not to be -single threaded and not to have any mode flags set. - -@param aMinLength The minimum length of the heap to be created. -@param aMaxLength The maximum length to which the heap to be created can grow. - If the supplied value is less than KMinHeapSize, then it - is discarded and the value KMinHeapSize used instead. -*/ -EXPORT_C TChunkHeapCreateInfo::TChunkHeapCreateInfo(TInt aMinLength, TInt aMaxLength) : - iVersionNumber(EVersion0), iMinLength(aMinLength), iMaxLength(aMaxLength), - iAlign(0), iGrowBy(1), iSingleThread(EFalse), - iOffset(0), iPaging(EUnspecified), iMode(0), iName(NULL) - { - } - - -/** -Sets the chunk heap to create a new chunk with the specified name. - -This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or -TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object. - -@param aName The name to be given to the chunk heap to be created - If NULL, the function constructs a local chunk to host the heap. - If not NULL, a pointer to a descriptor containing the name to be - assigned to the global chunk hosting the heap. -*/ -EXPORT_C void TChunkHeapCreateInfo::SetCreateChunk(const TDesC* aName) - { - iName = (TDesC*)aName; - iChunk.SetHandle(KNullHandle); - } - - -/** -Sets the chunk heap to be created to use the chunk specified. - -This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or -TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object. - -@param aChunk A handle to the chunk to use for the heap. -*/ -EXPORT_C void TChunkHeapCreateInfo::SetUseChunk(const RChunk aChunk) - { - iName = NULL; - iChunk = aChunk; - } - - -/** -Creates a chunk heap of the type specified by the parameter aCreateInfo. - -@param aCreateInfo A reference to a TChunkHeapCreateInfo object specifying the - type of chunk heap to create. - -@return A pointer to the new heap or NULL if the heap could not be created. - -@panic USER 41 if the heap's specified minimum length is greater than the specified maximum length. -@panic USER 55 if the heap's specified minimum length is negative. -@panic USER 172 if the heap's specified alignment is not a power of 2 or is less than the size of a TAny*. -*/ -EXPORT_C RHeap* UserHeap::ChunkHeap(const TChunkHeapCreateInfo& aCreateInfo) - { - // aCreateInfo must have been configured to use a new chunk or an exiting chunk. - __ASSERT_ALWAYS(!(aCreateInfo.iMode & (TUint32)~EChunkHeapMask), ::Panic(EHeapCreateInvalidMode)); - RHeap* h = NULL; - - if (aCreateInfo.iChunk.Handle() == KNullHandle) - {// A new chunk is to be created for this heap. - __ASSERT_ALWAYS(aCreateInfo.iMinLength >= 0, ::Panic(ETHeapMinLengthNegative)); - __ASSERT_ALWAYS(aCreateInfo.iMaxLength >= aCreateInfo.iMinLength, ::Panic(ETHeapCreateMaxLessThanMin)); - - TInt maxLength = aCreateInfo.iMaxLength; - if (maxLength < KMinHeapSize) - maxLength = KMinHeapSize; - - TChunkCreateInfo chunkInfo; - chunkInfo.SetNormal(0, maxLength); - chunkInfo.SetOwner((aCreateInfo.iSingleThread)? EOwnerThread : EOwnerProcess); - if (aCreateInfo.iName) - chunkInfo.SetGlobal(*aCreateInfo.iName); - // Set the paging attributes of the chunk. - if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EPaged) - chunkInfo.SetPaging(TChunkCreateInfo::EPaged); - if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EUnpaged) - chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged); - // Create the chunk. - RChunk chunk; - if (chunk.Create(chunkInfo) != KErrNone) - return NULL; - // Create the heap using the new chunk. - TUint mode = aCreateInfo.iMode | EChunkHeapDuplicate; // Must duplicate the handle. - h = OffsetChunkHeap(chunk, aCreateInfo.iMinLength, aCreateInfo.iOffset, - aCreateInfo.iGrowBy, maxLength, aCreateInfo.iAlign, - aCreateInfo.iSingleThread, mode); - chunk.Close(); - } - else - { - h = OffsetChunkHeap(aCreateInfo.iChunk, aCreateInfo.iMinLength, aCreateInfo.iOffset, - aCreateInfo.iGrowBy, aCreateInfo.iMaxLength, aCreateInfo.iAlign, - aCreateInfo.iSingleThread, aCreateInfo.iMode); - } - return h; - } - - -EXPORT_C RHeap* UserHeap::ChunkHeap(const TDesC* aName, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread) -/** -Creates a heap in a local or global chunk. - -The chunk hosting the heap can be local or global. - -A local chunk is one which is private to the process creating it and is not -intended for access by other user processes. -A global chunk is one which is visible to all processes. - -The hosting chunk is local, if the pointer aName is NULL, otherwise -the hosting chunk is global and the descriptor *aName is assumed to contain -the name to be assigned to it. - -Ownership of the host chunk is vested in the current process. - -A minimum and a maximum size for the heap can be specified. On successful -return from this function, the size of the heap is at least aMinLength. -If subsequent requests for allocation of memory from the heap cannot be -satisfied by compressing the heap, the size of the heap is extended in -increments of aGrowBy until the request can be satisfied. Attempts to extend -the heap causes the size of the host chunk to be adjusted. - -Note that the size of the heap cannot be adjusted by more than aMaxLength. - -@param aName If NULL, the function constructs a local chunk to host - the heap. - If not NULL, a pointer to a descriptor containing the name - to be assigned to the global chunk hosting the heap. -@param aMinLength The minimum length of the heap. -@param aMaxLength The maximum length to which the heap can grow. - If the supplied value is less than KMinHeapSize, then it - is discarded and the value KMinHeapSize used instead. -@param aGrowBy The increments to the size of the host chunk. If a value is - not explicitly specified, the value KMinHeapGrowBy is taken - by default -@param aAlign The alignment of heap cells. -@param aSingleThread Indicates whether single threaded or not. - -@return A pointer to the new heap or NULL if the heap could not be created. - -@panic USER 41 if aMinLength is greater than the supplied value of aMaxLength. -@panic USER 55 if aMinLength is negative. -@panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. -*/ -// -// Allocate a Chunk of the requested size and force construction. -// - { - TChunkHeapCreateInfo createInfo(aMinLength, aMaxLength); - createInfo.SetCreateChunk(aName); - createInfo.SetGrowBy(aGrowBy); - createInfo.SetAlignment(aAlign); - createInfo.SetSingleThread(aSingleThread); - return ChunkHeap(createInfo); - } - - - - -EXPORT_C RHeap* UserHeap::ChunkHeap(RChunk aChunk, TInt aMinLength, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode) -/** -Creates a heap in an existing chunk. - -This function is intended to be used to create a heap in a user writable code -chunk as created by a call to RChunk::CreateLocalCode(). -This type of heap can be used to hold code fragments from a JIT compiler. - -The maximum length to which the heap can grow is the same as -the maximum size of the chunk. - -@param aChunk The chunk that will host the heap. -@param aMinLength The minimum length of the heap. -@param aGrowBy The increments to the size of the host chunk. -@param aMaxLength The maximum length to which the heap can grow. -@param aAlign The alignment of heap cells. -@param aSingleThread Indicates whether single threaded or not. -@param aMode Flags controlling the heap creation. This should be set - from one or more of the values in TChunkHeapCreateMode. - -@return A pointer to the new heap or NULL if the heap could not be created. - -@panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. -*/ -// -// Construct a heap in an already existing chunk -// - { - - return OffsetChunkHeap(aChunk, aMinLength, 0, aGrowBy, aMaxLength, aAlign, aSingleThread, aMode); - } - - - - -EXPORT_C RHeap* UserHeap::OffsetChunkHeap(RChunk aChunk, TInt aMinLength, TInt aOffset, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode) -/** -Creates a heap in an existing chunk, offset from the beginning of the chunk. - -This function is intended to be used to create a heap where a fixed amount of -additional data must be stored at a known location. The additional data can be -placed at the base address of the chunk, allowing it to be located without -depending on the internals of the heap structure. - -The maximum length to which the heap can grow is the maximum size of the chunk, -minus the offset. - -@param aChunk The chunk that will host the heap. -@param aMinLength The minimum length of the heap. -@param aOffset The offset from the start of the chunk, to the start of the heap. -@param aGrowBy The increments to the size of the host chunk. -@param aMaxLength The maximum length to which the heap can grow. -@param aAlign The alignment of heap cells. -@param aSingleThread Indicates whether single threaded or not. -@param aMode Flags controlling the heap creation. This should be set - from one or more of the values in TChunkHeapCreateMode. - -@return A pointer to the new heap or NULL if the heap could not be created. - -@panic USER 172 if aAlign is not a power of 2 or is less than the size of a TAny*. -*/ -// -// Construct a heap in an already existing chunk -// - { - - TInt page_size; - UserHal::PageSizeInBytes(page_size); - if (!aAlign) - aAlign = RHeap::ECellAlignment; - TInt maxLength = aChunk.MaxSize(); - TInt round_up = Max(aAlign, page_size); - TInt min_cell = _ALIGN_UP(Max((TInt)RHeap::EAllocCellSize, (TInt)RHeap::EFreeCellSize), aAlign); - aOffset = _ALIGN_UP(aOffset, 8); - if (aMaxLength && aMaxLength+aOffset=0, ::Panic(ETHeapMinLengthNegative)); - __ASSERT_ALWAYS(maxLength>=aMinLength, ::Panic(ETHeapCreateMaxLessThanMin)); - aMinLength = _ALIGN_UP(Max(aMinLength, (TInt)sizeof(RHeap) + min_cell) + aOffset, round_up); - TInt r=aChunk.Adjust(aMinLength); - if (r!=KErrNone) - return NULL; - - RHeap* h = new (aChunk.Base() + aOffset) RHeap(aChunk.Handle(), aOffset, aMinLength, maxLength, aGrowBy, aAlign, aSingleThread); - - TBool duplicateLock = EFalse; - if (!aSingleThread) - { - duplicateLock = aMode & EChunkHeapSwitchTo; - if(h->iLock.CreateLocal(duplicateLock ? EOwnerThread : EOwnerProcess)!=KErrNone) - { - h->iChunkHandle = 0; - return NULL; - } - } - - if (aMode & EChunkHeapSwitchTo) - User::SwitchHeap(h); - - h->iHandles = &h->iChunkHandle; - if (!aSingleThread) - { - // now change the thread-relative chunk/semaphore handles into process-relative handles - h->iHandleCount = 2; - if(duplicateLock) - { - RHandleBase s = h->iLock; - r = h->iLock.Duplicate(RThread()); - s.Close(); - } - if (r==KErrNone && (aMode & EChunkHeapDuplicate)) - { - r = ((RChunk*)&h->iChunkHandle)->Duplicate(RThread()); - if (r!=KErrNone) - h->iLock.Close(), h->iChunkHandle=0; - } - } - else - { - h->iHandleCount = 1; - if (aMode & EChunkHeapDuplicate) - r = ((RChunk*)&h->iChunkHandle)->Duplicate(RThread(), EOwnerThread); - } - - // return the heap address - return (r==KErrNone) ? h : NULL; - } - - - -#define UserTestDebugMaskBit(bit) (TBool)(UserSvr::DebugMask(bit>>5) & (1<<(bit&31))) - -_LIT(KLitDollarHeap,"$HEAP"); -EXPORT_C TInt UserHeap::CreateThreadHeap(SStdEpocThreadCreateInfo& aInfo, RHeap*& aHeap, TInt aAlign, TBool aSingleThread) -/** -@internalComponent -*/ -// -// Create a user-side heap -// - { - TInt page_size; - UserHal::PageSizeInBytes(page_size); - TInt minLength = _ALIGN_UP(aInfo.iHeapInitialSize, page_size); - TInt maxLength = Max(aInfo.iHeapMaxSize, minLength); - if (UserTestDebugMaskBit(96)) // 96 == KUSERHEAPTRACE in nk_trace.h - aInfo.iFlags |= ETraceHeapAllocs; - - // Create the thread's heap chunk. - RChunk c; - TChunkCreateInfo createInfo; - createInfo.SetThreadHeap(0, maxLength, KLitDollarHeap()); // Initialise with no memory committed. - - // Set the paging policy of the heap chunk based on the thread's paging policy. - TUint pagingflags = aInfo.iFlags & EThreadCreateFlagPagingMask; - switch (pagingflags) - { - case EThreadCreateFlagPaged: - createInfo.SetPaging(TChunkCreateInfo::EPaged); - break; - case EThreadCreateFlagUnpaged: - createInfo.SetPaging(TChunkCreateInfo::EUnpaged); - break; - case EThreadCreateFlagPagingUnspec: - // Leave the chunk paging policy unspecified so the process's - // paging policy is used. - break; - } - - TInt r = c.Create(createInfo); - if (r!=KErrNone) - return r; - - aHeap = ChunkHeap(c, minLength, page_size, maxLength, aAlign, aSingleThread, EChunkHeapSwitchTo|EChunkHeapDuplicate); - c.Close(); - if (!aHeap) - return KErrNoMemory; - if (aInfo.iFlags & ETraceHeapAllocs) - { - aHeap->iFlags |= RHeap::ETraceAllocs; - BTraceContext8(BTrace::EHeap, BTrace::EHeapCreate,(TUint32)aHeap, RHeap::EAllocCellSize); - TInt handle = aHeap->ChunkHandle(); - TInt chunkId = ((RHandleBase&)handle).BTraceId(); - BTraceContext8(BTrace::EHeap, BTrace::EHeapChunkCreate, (TUint32)aHeap, chunkId); - } - if (aInfo.iFlags & EMonitorHeapMemory) - aHeap->iFlags |= RHeap::EMonitorMemory; - return KErrNone; - } - -#endif // __KERNEL_MODE__ - -void RHeap::WalkCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen) - { - (void)aCell; - SHeapCellInfo& info = *(SHeapCellInfo*)aPtr; - switch(aType) - { - case EGoodAllocatedCell: - { - ++info.iTotalAlloc; - info.iTotalAllocSize += (aLen-EAllocCellSize); -#if defined(_DEBUG) - RHeap& h = *info.iHeap; - if ( ((SDebugCell*)aCell)->nestingLevel == h.iNestingLevel ) - { - if (++info.iLevelAlloc==1) - info.iStranded = (SDebugCell*)aCell; -#ifdef __KERNEL_MODE__ - if (KDebugNum(KSERVER) || KDebugNum(KTESTFAST)) - { -// __KTRACE_OPT(KSERVER,Kern::Printf("LEAKED KERNEL HEAP CELL @ %08x : len=%d", aCell, aLen)); - Kern::Printf("LEAKED KERNEL HEAP CELL @ %08x : len=%d", aCell, aLen); - TLinAddr base = ((TLinAddr)aCell)&~0x0f; - TLinAddr end = ((TLinAddr)aCell)+(TLinAddr)aLen; - while(baseiRate, fail->iBurst); - } -#endif - break; - - case RAllocator::ECheckFailure: - // iRand will be incremented for each EFailNext, EBurstFailNext, - // EDeterministic and EBurstDeterministic failure. - r = iRand; - break; - - case RAllocator::ECopyDebugInfo: - { - TInt nestingLevel = ((SDebugCell*)a1)[-1].nestingLevel; - ((SDebugCell*)a2)[-1].nestingLevel = nestingLevel; - break; - } - case RHeap::EWalk: - Walk((TWalkFunc)a1, a2); - break; - default: - return KErrNotSupported; - } - return r; - } - - - - -void RHeap::Walk(TWalkFunc aFunc, TAny* aPtr) -// -// Walk the heap calling the info function. -// - { - - Lock(); - SCell* pC = (SCell*)iBase; // allocated cells - SCell* pF = &iFree; // free cells - FOREVER - { - pF = pF->next; // next free cell - if (!pF) - pF = (SCell*)iTop; // to make size checking work - else if ( (TUint8*)pF>=iTop || (pF->next && pF->next<=pF) ) - { - if (iFlags & ETraceAllocs) - BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pF+EFreeCellSize, 0); - // free cell pointer off the end or going backwards - Unlock(); - (*aFunc)(aPtr, EBadFreeCellAddress, pF, 0); - return; - } - else - { - TInt l = pF->len; - if (llen; - if (l pF) - { - if (iFlags & ETraceAllocs) - BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pC+EAllocCellSize, l-EAllocCellSize); - // cell overlaps next free cell - Unlock(); - (*aFunc)(aPtr, EBadAllocatedCellAddress, pC, l); - return; - } - pC = pN; - } - if ((TUint8*)pF == iTop) - break; // reached end of heap - pC = __NEXT_CELL(pF); // step to next allocated cell - (*aFunc)(aPtr, EGoodFreeCell, pF, pF->len); - } - Unlock(); - } - -TInt RHeap::DoCheckHeap(SCheckInfo* aInfo) - { - (void)aInfo; - SHeapCellInfo info; - memclr(&info, sizeof(info)); - info.iHeap = this; - Walk(&WalkCheckCell, &info); -#if defined(_DEBUG) - if (!aInfo) - return KErrNone; - TInt expected = aInfo->iCount; - TInt actual = aInfo->iAll ? info.iTotalAlloc : info.iLevelAlloc; - if (actual!=expected && !iTestData) - { -#ifdef __KERNEL_MODE__ - Kern::Fault("KERN-ALLOC COUNT", (expected<<16)|actual ); -#else - User::Panic(_L("ALLOC COUNT"), (expected<<16)|actual ); -#endif - } -#endif - return KErrNone; - } - -#ifdef _DEBUG -void RHeap::DoMarkStart() - { - if (iNestingLevel==0) - iAllocCount=0; - iNestingLevel++; - } - -TUint32 RHeap::DoMarkEnd(TInt aExpected) - { - if (iNestingLevel==0) - return 0; - SHeapCellInfo info; - SHeapCellInfo* p = iTestData ? (SHeapCellInfo*)iTestData : &info; - memclr(p, sizeof(info)); - p->iHeap = this; - Walk(&WalkCheckCell, p); - if (p->iLevelAlloc != aExpected && !iTestData) - return (TUint32)(p->iStranded + 1); - if (--iNestingLevel == 0) - iAllocCount = 0; - return 0; - } - -void ResetAllocCellLevels(TAny* aPtr, RHeap::TCellType aType, TAny* aCell, TInt aLen) - { - (void)aPtr; - (void)aLen; - RHeap::SDebugCell* cell = (RHeap::SDebugCell*)aCell; - if (aType == RHeap::EGoodAllocatedCell) - { - cell->nestingLevel = 0; - } - } - -void RHeap::DoSetAllocFail(TAllocFail aType, TInt aRate) - {// Default to a burst mode of 1, as aType may be a burst type. - DoSetAllocFail(aType, aRate, 1); - } - -// Don't change as the ETHeapBadDebugFailParameter check below and the API -// documentation rely on this being 16 for RHeap. -LOCAL_D const TInt KBurstFailRateShift = 16; -LOCAL_D const TInt KBurstFailRateMask = (1 << KBurstFailRateShift) - 1; - -void RHeap::DoSetAllocFail(TAllocFail aType, TInt aRate, TUint aBurst) - { - if (aType==EReset) - { - // reset levels of all allocated cells to 0 - // this should prevent subsequent tests failing unnecessarily - iFailed = EFalse; // Reset for ECheckFailure relies on this. - Walk(&ResetAllocCellLevels, NULL); - // reset heap allocation mark as well - iNestingLevel=0; - iAllocCount=0; - aType=ENone; - } - - switch (aType) - { - case EBurstRandom: - case EBurstTrueRandom: - case EBurstDeterministic: - case EBurstFailNext: - // If the fail type is a burst type then iFailRate is split in 2: - // the 16 lsbs are the fail rate and the 16 msbs are the burst length. - if (TUint(aRate) > (TUint)KMaxTUint16 || aBurst > KMaxTUint16) - HEAP_PANIC(ETHeapBadDebugFailParameter); - - iFailed = EFalse; - iFailType = aType; - iFailRate = (aRate == 0) ? 1 : aRate; - iFailAllocCount = -iFailRate; - iFailRate = iFailRate | (aBurst << KBurstFailRateShift); - break; - - default: - iFailed = EFalse; - iFailType = aType; - iFailRate = (aRate == 0) ? 1 : aRate; // A rate of <1 is meaningless - iFailAllocCount = 0; - break; - } - - // Set up iRand for either: - // - random seed value, or - // - a count of the number of failures so far. - iRand = 0; -#ifndef __KERNEL_MODE__ - switch (iFailType) - { - case ETrueRandom: - case EBurstTrueRandom: - { - TTime time; - time.HomeTime(); - TInt64 seed = time.Int64(); - iRand = Math::Rand(seed); - break; - } - case ERandom: - case EBurstRandom: - { - TInt64 seed = 12345; - iRand = Math::Rand(seed); - break; - } - default: - break; - } -#endif - } - -TBool RHeap::CheckForSimulatedAllocFail() -// -// Check to see if the user has requested simulated alloc failure, and if so possibly -// Return ETrue indicating a failure. -// - { - // For burst mode failures iFailRate is shared - TUint16 rate = (TUint16)(iFailRate & KBurstFailRateMask); - TUint16 burst = (TUint16)(iFailRate >> KBurstFailRateShift); - TBool r = EFalse; - switch (iFailType) - { -#ifndef __KERNEL_MODE__ - case ERandom: - case ETrueRandom: - if (++iFailAllocCount>=iFailRate) - { - iFailAllocCount=0; - if (!iFailed) // haven't failed yet after iFailRate allocations so fail now - return(ETrue); - iFailed=EFalse; - } - else - { - if (!iFailed) - { - TInt64 seed=iRand; - iRand=Math::Rand(seed); - if (iRand%iFailRate==0) - { - iFailed=ETrue; - return(ETrue); - } - } - } - break; - - case EBurstRandom: - case EBurstTrueRandom: - if (++iFailAllocCount < 0) - { - // We haven't started failing yet so should we now? - TInt64 seed = iRand; - iRand = Math::Rand(seed); - if (iRand % rate == 0) - {// Fail now. Reset iFailAllocCount so we fail burst times - iFailAllocCount = 0; - r = ETrue; - } - } - else - { - if (iFailAllocCount < burst) - {// Keep failing for burst times - r = ETrue; - } - else - {// We've now failed burst times so start again. - iFailAllocCount = -(rate - 1); - } - } - break; -#endif - case EDeterministic: - if (++iFailAllocCount%iFailRate==0) - { - r=ETrue; - iRand++; // Keep count of how many times we have failed - } - break; - - case EBurstDeterministic: - // This will fail burst number of times, every rate attempts. - if (++iFailAllocCount >= 0) - { - if (iFailAllocCount == burst - 1) - {// This is the burst time we have failed so make it the last by - // reseting counts so we next fail after rate attempts. - iFailAllocCount = -rate; - } - r = ETrue; - iRand++; // Keep count of how many times we have failed - } - break; - - case EFailNext: - if ((++iFailAllocCount%iFailRate)==0) - { - iFailType=ENone; - r=ETrue; - iRand++; // Keep count of how many times we have failed - } - break; - - case EBurstFailNext: - if (++iFailAllocCount >= 0) - { - if (iFailAllocCount == burst - 1) - {// This is the burst time we have failed so make it the last. - iFailType = ENone; - } - r = ETrue; - iRand++; // Keep count of how many times we have failed - } - break; - default: - break; - } - return r; - } -#endif // ifdef _DEBUG - -UEXPORT_C TInt RHeap::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1) - { - return RAllocator::Extension_(aExtensionId, a0, a1); - } - -#if defined(__HEAP_MACHINE_CODED__) && !defined(_DEBUG) -GLDEF_C void RHeap_PanicBadAllocatedCellSize() - { - HEAP_PANIC(ETHeapBadAllocatedCellSize); - } - -GLDEF_C void RHeap_PanicBadNextCell() - { - HEAP_PANIC(ETHeapFreeBadNextCell); - } - -GLDEF_C void RHeap_PanicBadPrevCell() - { - HEAP_PANIC(ETHeapFreeBadPrevCell); - } - -GLDEF_C void RHeap_PanicBadCellAddress() - { - HEAP_PANIC(ETHeapBadCellAddress); - } -#endif - - - - -