--- a/kernel/eka/common/heap.cpp Thu Aug 19 11:14:22 2010 +0300
+++ /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 <kernel/kern_priv.h>
-#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->len<iMinCell) || ((TUint8*)c<iBase) || ((TUint8*)__NEXT_CELL(c)>iTop)) \
- 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 && pE<pC; pP=pE, pE=pE->next) {}
- 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 // pN<pE, non-adjacent free cells
- pC->next = 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 // pN<pC, non-adjacent free cells
- pP->next = 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 && aNext<aCell; aPrev=aNext, aNext=aNext->next) {}
-
- 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 (aMaxLength<KMinHeapSize)
- aMaxLength=KMinHeapSize;
- RHeap* h = new(aBase) RHeap(aMaxLength, aAlign, aSingleThread);
- if (!aSingleThread)
- {
- TInt r = h->iLock.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<maxLength)
- maxLength = _ALIGN_UP(aMaxLength+aOffset, round_up);
- __ASSERT_ALWAYS(aMinLength>=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(base<end)
- {
- const TUint32* p = (const TUint32*)base;
- Kern::Printf("%08x: %08x %08x %08x %08x", p, p[0], p[1], p[2], p[3]);
- base += 16;
- }
- }
-#endif
- }
-#endif
- break;
- }
- case EGoodFreeCell:
- ++info.iTotalFree;
- break;
- case EBadAllocatedCellSize:
- HEAP_PANIC(ETHeapBadAllocatedCellSize);
- case EBadAllocatedCellAddress:
- HEAP_PANIC(ETHeapBadAllocatedCellAddress);
- case EBadFreeCellAddress:
- HEAP_PANIC(ETHeapBadFreeCellAddress);
- case EBadFreeCellSize:
- HEAP_PANIC(ETHeapBadFreeCellSize);
- default:
- HEAP_PANIC(ETHeapWalkBadCellType);
- }
- }
-
-TInt RHeap::DoCountAllocFree(TInt& aFree)
- {
- SHeapCellInfo info;
- memclr(&info, sizeof(info));
- info.iHeap = this;
- Walk(&WalkCheckCell, &info);
- aFree = info.iTotalFree;
- return info.iTotalAlloc;
- }
-
-
-UEXPORT_C TInt RHeap::DebugFunction(TInt aFunc, TAny* a1, TAny* a2)
-/**
-@internalComponent
-*/
- {
- TInt r = KErrNone;
- switch(aFunc)
- {
- case RAllocator::ECount:
- r = DoCountAllocFree(*(TInt*)a1);
- break;
- case RAllocator::EMarkStart:
- __DEBUG_ONLY(DoMarkStart());
- break;
- case RAllocator::EMarkEnd:
- __DEBUG_ONLY( r = DoMarkEnd((TInt)a1) );
- break;
- case RAllocator::ECheck:
- r = DoCheckHeap((SCheckInfo*)a1);
- break;
- case RAllocator::ESetFail:
- __DEBUG_ONLY(DoSetAllocFail((TAllocFail)(TInt)a1, (TInt)a2));
- break;
- case RAllocator::ESetBurstFail:
-#if _DEBUG
- {
- SRAllocatorBurstFail* fail = (SRAllocatorBurstFail*) a2;
- DoSetAllocFail((TAllocFail)(TInt)a1, fail->iRate, 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 (l<iMinCell || (l & (iAlign-1)))
- {
- if (iFlags & ETraceAllocs)
- BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pF+EFreeCellSize, l-EFreeCellSize);
- // free cell length invalid
- Unlock();
- (*aFunc)(aPtr, EBadFreeCellSize, pF, l);
- return;
- }
- }
- while (pC!=pF) // walk allocated cells up to next free cell
- {
- TInt l = pC->len;
- if (l<iMinCell || (l & (iAlign-1)))
- {
- if (iFlags & ETraceAllocs)
- BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)pC+EAllocCellSize, l-EAllocCellSize);
- // allocated cell length invalid
- Unlock();
- (*aFunc)(aPtr, EBadAllocatedCellSize, pC, l);
- return;
- }
- (*aFunc)(aPtr, EGoodAllocatedCell, pC, l);
- SCell* pN = __NEXT_CELL(pC);
- if (pN > 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
-
-
-
-
-