diff -r 7fdc9a71d314 -r 8ad140f3dd41 memspy/Driver/Shared/heaputils.cpp --- a/memspy/Driver/Shared/heaputils.cpp Wed Sep 15 13:53:27 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1684 +0,0 @@ -// heaputils.cpp -// -// Copyright (c) 2010 Accenture. All rights reserved. -// This component and the accompanying materials are made available -// under the terms of the "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: -// Accenture - Initial contribution -// -#ifdef TEST_HYBRIDHEAP_ASSERTS -#define private public -#include -#include "slab.h" -#include "page_alloc.h" -#include "heap_hybrid.h" -#endif - -#include "heaputils.h" - -#ifdef __KERNEL_MODE__ - -#include -#define MEM Kern -__ASSERT_COMPILE(sizeof(LtkUtils::RKernelSideAllocatorHelper) == 10*4); -#define KERN_ENTER_CS() NKern::ThreadEnterCS() -#define KERN_LEAVE_CS() NKern::ThreadLeaveCS() -#define LOG(args...) -#define HUEXPORT_C -#else - -#include -#define MEM User -#define KERN_ENTER_CS() -#define KERN_LEAVE_CS() -//#include -//#define LOG(args...) RDebug::Printf(args) -#define LOG(args...) - -#ifdef STANDALONE_ALLOCHELPER -#define HUEXPORT_C -#else -#define HUEXPORT_C EXPORT_C -#endif - -#endif // __KERNEL_MODE__ - -using LtkUtils::RAllocatorHelper; -const TUint KPageSize = 4096; -__ASSERT_COMPILE(sizeof(RAllocatorHelper) == 9*4); - -// RAllocatorHelper - -HUEXPORT_C RAllocatorHelper::RAllocatorHelper() - : iAllocatorAddress(0), iAllocatorType(EUnknown), iInfo(NULL), iValidInfo(0), iTempSlabBitmap(NULL), iPageCache(NULL), iPageCacheAddr(0) -#ifdef __KERNEL_MODE__ - , iChunk(NULL) -#endif - { - } - -namespace LtkUtils - { - class THeapInfo - { - public: - THeapInfo() - { - ClearStats(); - } - - void ClearStats() - { - memclr(this, sizeof(THeapInfo)); - } - - TInt iAllocatedSize; // number of bytes in allocated cells (excludes free cells, cell header overhead) - TInt iCommittedSize; // amount of memory actually committed (includes cell header overhead, gaps smaller than an MMU page) - TInt iAllocationCount; // number of allocations currently - TInt iMaxCommittedSize; // or thereabouts - TInt iMinCommittedSize; - TInt iUnusedPages; - TInt iCommittedFreeSpace; - // Heap-only stats - TInt iHeapFreeCellCount; - // Hybrid-only stats - TInt iDlaAllocsSize; - TInt iDlaAllocsCount; - TInt iDlaFreeSize; - TInt iDlaFreeCount; - TInt iSlabAllocsSize; - TInt iSlabAllocsCount; - TInt iPageAllocsSize; - TInt iPageAllocsCount; - TInt iSlabFreeCellSize; - TInt iSlabFreeCellCount; - TInt iSlabFreeSlabSize; - TInt iSlabFreeSlabCount; - }; - } - -const TInt KTempBitmapSize = 256; // KMaxSlabPayload / mincellsize, technically. Close enough. - -#ifdef __KERNEL_MODE__ - -TInt RAllocatorHelper::OpenKernelHeap() - { - _LIT(KName, "SvHeap"); - NKern::ThreadEnterCS(); - DObjectCon* chunkContainer = Kern::Containers()[EChunk]; - chunkContainer->Wait(); - const TInt chunkCount = chunkContainer->Count(); - DChunk* foundChunk = NULL; - for(TInt i=0; iNameBuf() && chunk->NameBuf()->Find(KName) != KErrNotFound) - { - // Found it. No need to open it, we can be fairly confident the kernel heap isn't going to disappear from under us - foundChunk = chunk; - break; - } - } - iChunk = foundChunk; - chunkContainer->Signal(); -#ifdef __WINS__ - TInt err = OpenChunkHeap((TLinAddr)foundChunk->Base(), 0); // It looks like DChunk::iBase/DChunk::iFixedBase should both be ok for the kernel chunk -#else - // Copied from P::KernelInfo - const TRomHeader& romHdr=Epoc::RomHeader(); - const TRomEntry* primaryEntry=(const TRomEntry*)Kern::SuperPage().iPrimaryEntry; - const TRomImageHeader* primaryImageHeader=(const TRomImageHeader*)primaryEntry->iAddressLin; - TLinAddr stack = romHdr.iKernDataAddress + Kern::RoundToPageSize(romHdr.iTotalSvDataSize); - TLinAddr heap = stack + Kern::RoundToPageSize(primaryImageHeader->iStackSize); - TInt err = OpenChunkHeap(heap, 0); // aChunkMaxSize is only used for trying the middle of the chunk for hybrid allocatorness, and the kernel heap doesn't use that (thankfully). So we can safely pass in zero. - -#endif - if (!err) err = FinishConstruction(); - NKern::ThreadLeaveCS(); - return err; - } - -#else - -HUEXPORT_C TInt RAllocatorHelper::Open(RAllocator* aAllocator) - { - iAllocatorAddress = (TLinAddr)aAllocator; - TInt udeb = EuserIsUdeb(); - if (udeb < 0) return udeb; // error - - TInt err = IdentifyAllocatorType(udeb); - if (!err) - { - err = FinishConstruction(); // Allocate everything up front - } - if (!err) - { - // We always stealth our own allocations, again to avoid tripping up allocator checks - SetCellNestingLevel(iInfo, -1); - SetCellNestingLevel(iTempSlabBitmap, -1); - SetCellNestingLevel(iPageCache, -1); - } - return err; - } - -#endif - -TInt RAllocatorHelper::FinishConstruction() - { - TInt err = KErrNone; - KERN_ENTER_CS(); - if (!iInfo) - { - iInfo = new THeapInfo; - if (!iInfo) err = KErrNoMemory; - } - if (!err && !iTempSlabBitmap) - { - iTempSlabBitmap = (TUint8*)MEM::Alloc(KTempBitmapSize); - if (!iTempSlabBitmap) err = KErrNoMemory; - } - if (!err && !iPageCache) - { - iPageCache = MEM::Alloc(KPageSize); - if (!iPageCache) err = KErrNoMemory; - } - - if (err) - { - delete iInfo; - iInfo = NULL; - MEM::Free(iTempSlabBitmap); - iTempSlabBitmap = NULL; - MEM::Free(iPageCache); - iPageCache = NULL; - } - KERN_LEAVE_CS(); - return err; - } - -TInt RAllocatorHelper::ReadWord(TLinAddr aLocation, TUint32& aResult) const - { - // Check if we can satisfy the read from the cache - if (aLocation >= iPageCacheAddr) - { - TUint offset = aLocation - iPageCacheAddr; - if (offset < KPageSize) - { - aResult = ((TUint32*)iPageCache)[offset >> 2]; - return KErrNone; - } - } - - // If we reach here, not in page cache. Try and read in the new page - if (iPageCache) - { - TLinAddr pageAddr = aLocation & ~(KPageSize-1); - TInt err = ReadData(pageAddr, iPageCache, KPageSize); - if (!err) - { - iPageCacheAddr = pageAddr; - aResult = ((TUint32*)iPageCache)[(aLocation - iPageCacheAddr) >> 2]; - return KErrNone; - } - } - - // All else fails, try just reading it uncached - return ReadData(aLocation, &aResult, sizeof(TUint32)); - } - -TInt RAllocatorHelper::ReadByte(TLinAddr aLocation, TUint8& aResult) const - { - // Like ReadWord but 8-bit - - // Check if we can satisfy the read from the cache - if (aLocation >= iPageCacheAddr) - { - TUint offset = aLocation - iPageCacheAddr; - if (offset < KPageSize) - { - aResult = ((TUint8*)iPageCache)[offset]; - return KErrNone; - } - } - - // If we reach here, not in page cache. Try and read in the new page - if (iPageCache) - { - TLinAddr pageAddr = aLocation & ~(KPageSize-1); - TInt err = ReadData(pageAddr, iPageCache, KPageSize); - if (!err) - { - iPageCacheAddr = pageAddr; - aResult = ((TUint8*)iPageCache)[(aLocation - iPageCacheAddr)]; - return KErrNone; - } - } - - // All else fails, try just reading it uncached - return ReadData(aLocation, &aResult, sizeof(TUint8)); - } - - -TInt RAllocatorHelper::WriteWord(TLinAddr aLocation, TUint32 aWord) - { - // Invalidate the page cache if necessary - if (aLocation >= iPageCacheAddr && aLocation - iPageCacheAddr < KPageSize) - { - iPageCacheAddr = 0; - } - - return WriteData(aLocation, &aWord, sizeof(TUint32)); - } - -TInt RAllocatorHelper::ReadData(TLinAddr aLocation, TAny* aResult, TInt aSize) const - { - // RAllocatorHelper base class impl is for allocators in same address space, so just copy it - memcpy(aResult, (const TAny*)aLocation, aSize); - return KErrNone; - } - -TInt RAllocatorHelper::WriteData(TLinAddr aLocation, const TAny* aData, TInt aSize) - { - memcpy((TAny*)aLocation, aData, aSize); - return KErrNone; - } - -#ifdef __KERNEL_MODE__ - -LtkUtils::RKernelSideAllocatorHelper::RKernelSideAllocatorHelper() - : iThread(NULL) - {} - -void LtkUtils::RKernelSideAllocatorHelper::Close() - { - NKern::ThreadEnterCS(); - if (iThread) - { - iThread->Close(NULL); - } - iThread = NULL; - RAllocatorHelper::Close(); - NKern::ThreadLeaveCS(); - } - -TInt LtkUtils::RKernelSideAllocatorHelper::ReadData(TLinAddr aLocation, TAny* aResult, TInt aSize) const - { - return Kern::ThreadRawRead(iThread, (const TAny*)aLocation, aResult, aSize); - } - -TInt LtkUtils::RKernelSideAllocatorHelper::WriteData(TLinAddr aLocation, const TAny* aData, TInt aSize) - { - return Kern::ThreadRawWrite(iThread, (TAny*)aLocation, aData, aSize); - } - -TInt LtkUtils::RKernelSideAllocatorHelper::TryLock() - { - return KErrNotSupported; - } - -void LtkUtils::RKernelSideAllocatorHelper::TryUnlock() - { - // Not supported - } - -TInt LtkUtils::RKernelSideAllocatorHelper::OpenUserHeap(TUint aThreadId, TLinAddr aAllocatorAddress, TBool aEuserIsUdeb) - { - NKern::ThreadEnterCS(); - DObjectCon* threads = Kern::Containers()[EThread]; - threads->Wait(); - iThread = Kern::ThreadFromId(aThreadId); - if (iThread && iThread->Open() != KErrNone) - { - // Failed to open - iThread = NULL; - } - threads->Signal(); - NKern::ThreadLeaveCS(); - if (!iThread) return KErrNotFound; - iAllocatorAddress = aAllocatorAddress; - TInt err = IdentifyAllocatorType(aEuserIsUdeb); - if (err) Close(); - return err; - } - -#endif // __KERNEL_MODE__ - -TInt RAllocatorHelper::OpenChunkHeap(TLinAddr aChunkBase, TInt aChunkMaxSize) - { - iAllocatorAddress = aChunkBase; -#ifdef __KERNEL_MODE__ - // Must be in CS - // Assumes that this only ever gets called for the kernel heap. Otherwise goes through RKernelSideAllocatorHelper::OpenUserHeap. - TInt udeb = EFalse; // We can't figure this out until after we've got the heap - TBool isTheKernelHeap = ETrue; -#else - // Assumes the chunk isn't the kernel heap. It's not a good idea to try messing with the kernel heap from user side... - TInt udeb = EuserIsUdeb(); - if (udeb < 0) return udeb; // error - TBool isTheKernelHeap = EFalse; -#endif - - TInt err = IdentifyAllocatorType(udeb, isTheKernelHeap); - if (err == KErrNone && iAllocatorType == EAllocator) - { - // We've no reason to assume it's an allocator because we don't know the iAllocatorAddress actually is an RAllocator* - err = KErrNotFound; - } - if (err && aChunkMaxSize > 0) - { - TInt oldErr = err; - TAllocatorType oldType = iAllocatorType; - // Try middle of chunk, in case it's an RHybridHeap - iAllocatorAddress += aChunkMaxSize / 2; - err = IdentifyAllocatorType(udeb, isTheKernelHeap); - if (err || iAllocatorType == EAllocator) - { - // No better than before - iAllocatorAddress = aChunkBase; - iAllocatorType = oldType; - err = oldErr; - } - } -#ifdef __KERNEL_MODE__ - if (err == KErrNone) - { - // Now we know the allocator, we can figure out the udeb-ness - RAllocator* kernelAllocator = reinterpret_cast(iAllocatorAddress); - kernelAllocator->DebugFunction(RAllocator::ESetFail, (TAny*)9999, (TAny*)0); // Use an invalid fail reason - this should have no effect on the operation of the heap - TInt err = kernelAllocator->DebugFunction(7, NULL, NULL); // 7 is RAllocator::TAllocDebugOp::EGetFail - if (err == 9999) - { - // udeb new hybrid heap - udeb = ETrue; - } - else if (err == KErrNotSupported) - { - // Old heap - fall back to slightly nasty non-thread-safe method - kernelAllocator->DebugFunction(RAllocator::ESetFail, (TAny*)RAllocator::EFailNext, (TAny*)1); - TAny* res = Kern::Alloc(4); - if (!res) udeb = ETrue; - Kern::Free(res); - } - else - { - // it's new urel - } - - // Put everything back - kernelAllocator->DebugFunction(RAllocator::ESetFail, (TAny*)RAllocator::ENone, (TAny*)0); - // And update the type now we know the udeb-ness for certain - err = IdentifyAllocatorType(udeb, isTheKernelHeap); - } -#endif - return err; - } - - -// The guts of RAllocatorHelper - -enum TWhatToGet - { - ECommitted = 1, - EAllocated = 2, - ECount = 4, - EMaxSize = 8, - EUnusedPages = 16, - ECommittedFreeSpace = 32, - EMinSize = 64, - EHybridStats = 128, - }; - -class RHackAllocator : public RAllocator - { -public: - using RAllocator::iHandles; - using RAllocator::iTotalAllocSize; - using RAllocator::iCellCount; - }; - -class RHackHeap : public RHeap - { -public: - // Careful, only allowed to use things that are still in the new RHeap, and are still in the same place - using RHeap::iMaxLength; - using RHeap::iChunkHandle; - using RHeap::iLock; - using RHeap::iBase; - using RHeap::iAlign; - using RHeap::iTop; - }; - -const TInt KChunkSizeOffset = 30*4; -const TInt KPageMapOffset = 141*4; -//const TInt KDlOnlyOffset = 33*4; -const TInt KMallocStateOffset = 34*4; -const TInt KMallocStateTopSizeOffset = 3*4; -const TInt KMallocStateTopOffset = 5*4; -const TInt KMallocStateSegOffset = 105*4; -const TInt KUserHybridHeapSize = 186*4; -const TInt KSparePageOffset = 167*4; -const TInt KPartialPageOffset = 165*4; -const TInt KFullSlabOffset = 166*4; -const TInt KSlabAllocOffset = 172*4; -const TInt KSlabParentOffset = 1*4; -const TInt KSlabChild1Offset = 2*4; -const TInt KSlabChild2Offset = 3*4; -const TInt KSlabPayloadOffset = 4*4; -const TInt KSlabsetSize = 4; - -#ifdef TEST_HYBRIDHEAP_ASSERTS -__ASSERT_COMPILE(_FOFF(RHybridHeap, iChunkSize) == KChunkSizeOffset); -__ASSERT_COMPILE(_FOFF(RHybridHeap, iPageMap) == KPageMapOffset); -__ASSERT_COMPILE(_FOFF(RHybridHeap, iGlobalMallocState) == KMallocStateOffset); -__ASSERT_COMPILE(sizeof(malloc_state) == 107*4); -__ASSERT_COMPILE(_FOFF(malloc_state, iTopSize) == KMallocStateTopSizeOffset); -__ASSERT_COMPILE(_FOFF(malloc_state, iTop) == KMallocStateTopOffset); -__ASSERT_COMPILE(_FOFF(malloc_state, iSeg) == KMallocStateSegOffset); -__ASSERT_COMPILE(sizeof(RHybridHeap) == KUserHybridHeapSize); -__ASSERT_COMPILE(_FOFF(RHybridHeap, iSparePage) == KSparePageOffset); -__ASSERT_COMPILE(_FOFF(RHybridHeap, iPartialPage) == KPartialPageOffset); -__ASSERT_COMPILE(_FOFF(RHybridHeap, iSlabAlloc) == KSlabAllocOffset); -__ASSERT_COMPILE(_FOFF(slab, iParent) == KSlabParentOffset); -__ASSERT_COMPILE(_FOFF(slab, iChild1) == KSlabChild1Offset); -__ASSERT_COMPILE(_FOFF(slab, iChild2) == KSlabChild2Offset); -__ASSERT_COMPILE(_FOFF(slab, iPayload) == KSlabPayloadOffset); -__ASSERT_COMPILE(sizeof(slabset) == KSlabsetSize); -#endif - -TInt RAllocatorHelper::TryLock() - { -#ifdef __KERNEL_MODE__ - NKern::ThreadEnterCS(); - DMutex* m = *(DMutex**)(iAllocatorAddress + _FOFF(RHackHeap, iLock)); - if (m) Kern::MutexWait(*m); - return KErrNone; -#else - if (iAllocatorType != EUnknown && iAllocatorType != EAllocator) - { - RFastLock& lock = *reinterpret_cast(iAllocatorAddress + _FOFF(RHackHeap, iLock)); - lock.Wait(); - return KErrNone; - } - return KErrNotSupported; -#endif - } - -void RAllocatorHelper::TryUnlock() - { -#ifdef __KERNEL_MODE__ - DMutex* m = *(DMutex**)(iAllocatorAddress + _FOFF(RHackHeap, iLock)); - if (m) Kern::MutexSignal(*m); - NKern::ThreadLeaveCS(); -#else - if (iAllocatorType != EUnknown && iAllocatorType != EAllocator) - { - RFastLock& lock = *reinterpret_cast(iAllocatorAddress + _FOFF(RHackHeap, iLock)); - lock.Signal(); - } -#endif - } - -HUEXPORT_C void RAllocatorHelper::Close() - { - KERN_ENTER_CS(); - iAllocatorType = EUnknown; - iAllocatorAddress = 0; - delete iInfo; - iInfo = NULL; - iValidInfo = 0; - MEM::Free(iTempSlabBitmap); - iTempSlabBitmap = NULL; - MEM::Free(iPageCache); - iPageCache = NULL; - iPageCacheAddr = 0; - KERN_LEAVE_CS(); - } - -TInt RAllocatorHelper::IdentifyAllocatorType(TBool aAllocatorIsUdeb, TBool aIsTheKernelHeap) - { - iAllocatorType = EUnknown; - - TUint32 handlesPtr = 0; - TInt err = ReadWord(iAllocatorAddress + _FOFF(RHackAllocator, iHandles), handlesPtr); - - if (err) return err; - if (aIsTheKernelHeap || - handlesPtr == iAllocatorAddress + _FOFF(RHackHeap, iChunkHandle) || - handlesPtr == iAllocatorAddress + _FOFF(RHackHeap, iLock)) - { - // It's an RHeap of some kind - I doubt any other RAllocator subclass will use iHandles in this way - TUint32 base = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iBase), base); - if (err) return err; - TInt objsize = (TInt)base - (TInt)iAllocatorAddress; - if (objsize <= 32*4) - { - // Old RHeap - iAllocatorType = aAllocatorIsUdeb ? EUdebOldRHeap : EUrelOldRHeap; - } - else - { - // new hybrid heap - bigger than the old one. Likewise figure out if udeb or urel. - iAllocatorType = aAllocatorIsUdeb ? EUdebHybridHeap : EUrelHybridHeap; - } - } - else - { - iAllocatorType = EAllocator; - } - return KErrNone; - } - -HUEXPORT_C TInt RAllocatorHelper::SetCellNestingLevel(TAny* aCell, TInt aNestingLevel) - { - TInt err = KErrNone; - - switch (iAllocatorType) - { - case EUdebOldRHeap: - case EUdebHybridHeap: - // By this reckoning, they're in the same place amazingly - { - TLinAddr nestingAddr = (TLinAddr)aCell - 8; - err = WriteWord(nestingAddr, aNestingLevel); - break; - } - default: - break; - } - return err; - } - -HUEXPORT_C TInt RAllocatorHelper::GetCellNestingLevel(TAny* aCell, TInt& aNestingLevel) - { - switch (iAllocatorType) - { - case EUdebOldRHeap: - case EUdebHybridHeap: - // By this reckoning, they're in the same place amazingly - { - TLinAddr nestingAddr = (TLinAddr)aCell - 8; - return ReadWord(nestingAddr, (TUint32&)aNestingLevel); - } - default: - return KErrNotSupported; - } - } - -TInt RAllocatorHelper::RefreshDetails(TUint aMask) - { - TInt err = FinishConstruction(); - if (err) return err; - - // Invalidate the page cache - iPageCacheAddr = 0; - - TryLock(); - err = DoRefreshDetails(aMask); - TryUnlock(); - return err; - } - -const TInt KHeapWalkStatsForOldHeap = (EUnusedPages|ECommittedFreeSpace); -const TInt KHeapWalkStatsForNewHeap = (EAllocated|ECount|EUnusedPages|ECommittedFreeSpace|EHybridStats); - -TInt RAllocatorHelper::DoRefreshDetails(TUint aMask) - { - TInt err = KErrNotSupported; - switch (iAllocatorType) - { - case EUrelOldRHeap: - case EUdebOldRHeap: - { - if (aMask & ECommitted) - { - // The old RHeap::Size() used to use iTop - iBase, which was effectively chunkSize - sizeof(RHeap) - // I think that for CommittedSize we should include the size of the heap object, just as it includes - // the size of heap cell metadata and overhead. Plus it makes sure the committedsize is a multiple of the page size - TUint32 top = 0; - //TUint32 base = 0; - //err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iBase), base); - //if (err) return err; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iTop), top); - if (err) return err; - - //iInfo->iCommittedSize = top - base; - iInfo->iCommittedSize = top - iAllocatorAddress; - iValidInfo |= ECommitted; - } - if (aMask & EAllocated) - { - TUint32 allocSize = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackAllocator, iTotalAllocSize), allocSize); - if (err) return err; - iInfo->iAllocatedSize = allocSize; - iValidInfo |= EAllocated; - } - if (aMask & ECount) - { - TUint32 count = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackAllocator, iCellCount), count); - if (err) return err; - iInfo->iAllocationCount = count; - iValidInfo |= ECount; - } - if (aMask & EMaxSize) - { - TUint32 maxlen = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iMaxLength), maxlen); - if (err) return err; - iInfo->iMaxCommittedSize = maxlen; - iValidInfo |= EMaxSize; - } - if (aMask & EMinSize) - { - TUint32 minlen = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iMaxLength) - 4, minlen); // This isn't a typo! iMinLength is 4 bytes before iMaxLength, on old heap ONLY - if (err) return err; - iInfo->iMinCommittedSize = minlen; - iValidInfo |= EMinSize; - } - if (aMask & KHeapWalkStatsForOldHeap) - { - // Need a heap walk - iInfo->ClearStats(); - iValidInfo = 0; - err = DoWalk(&WalkForStats, NULL); - if (err == KErrNone) iValidInfo |= KHeapWalkStatsForOldHeap; - } - return err; - } - case EUrelHybridHeap: - case EUdebHybridHeap: - { - TBool needWalk = EFalse; - if (aMask & ECommitted) - { - // RAllocator::Size uses iChunkSize - sizeof(RHybridHeap); - // We can't do exactly the same, because we can't calculate sizeof(RHybridHeap), only ROUND_UP(sizeof(RHybridHeap), iAlign) - // And if fact we don't bother and just use iChunkSize - TUint32 chunkSize = 0; - err = ReadWord(iAllocatorAddress + KChunkSizeOffset, chunkSize); - if (err) return err; - //TUint32 baseAddr = 0; - //err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iBase), baseAddr); - //if (err) return err; - iInfo->iCommittedSize = chunkSize; // - (baseAddr - iAllocatorAddress); - iValidInfo |= ECommitted; - } - if (aMask & (EAllocated|ECount)) - { - if (iAllocatorType == EUdebHybridHeap) - { - // Easy, just get them from the counter - TUint32 totalAlloc = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackAllocator, iTotalAllocSize), totalAlloc); - if (err) return err; - iInfo->iAllocatedSize = totalAlloc; - iValidInfo |= EAllocated; - - TUint32 cellCount = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackAllocator, iCellCount), cellCount); - if (err) return err; - iInfo->iAllocationCount = cellCount; - iValidInfo |= ECount; - } - else - { - // A heap walk is needed - needWalk = ETrue; - } - } - if (aMask & EMaxSize) - { - TUint32 maxlen = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iMaxLength), maxlen); - if (err) return err; - iInfo->iMaxCommittedSize = maxlen; - iValidInfo |= EMaxSize; - } - if (aMask & EMinSize) - { - TUint32 minlen = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iAlign) + 4*4, minlen); // iMinLength is in different place to old RHeap - if (err) return err; - iInfo->iMinCommittedSize = minlen; - iValidInfo |= EMinSize; - } - if (aMask & (EUnusedPages|ECommittedFreeSpace|EHybridStats)) - { - // EAllocated and ECount have already been taken care of above - needWalk = ETrue; - } - - if (needWalk) - { - iInfo->ClearStats(); - iValidInfo = 0; - err = DoWalk(&WalkForStats, NULL); - if (err == KErrNone) iValidInfo |= KHeapWalkStatsForNewHeap; - } - return err; - } - default: - return KErrNotSupported; - } - } - -TInt RAllocatorHelper::CheckValid(TUint aMask) - { - if ((iValidInfo & aMask) == aMask) - { - return KErrNone; - } - else - { - return RefreshDetails(aMask); - } - } - -HUEXPORT_C TInt RAllocatorHelper::CommittedSize() - { - TInt err = CheckValid(ECommitted); - if (err) return err; - return iInfo->iCommittedSize; - } - -HUEXPORT_C TInt RAllocatorHelper::AllocatedSize() - { - TInt err = CheckValid(EAllocated); - if (err) return err; - return iInfo->iAllocatedSize; - } - -HUEXPORT_C TInt RAllocatorHelper::AllocationCount() - { - TInt err = CheckValid(ECount); - if (err) return err; - return iInfo->iAllocationCount; - } - -HUEXPORT_C TInt RAllocatorHelper::RefreshDetails() - { - return RefreshDetails(iValidInfo); - } - -HUEXPORT_C TInt RAllocatorHelper::MaxCommittedSize() - { - TInt err = CheckValid(EMaxSize); - if (err) return err; - return iInfo->iMaxCommittedSize; - } - -HUEXPORT_C TInt RAllocatorHelper::MinCommittedSize() - { - TInt err = CheckValid(EMinSize); - if (err) return err; - return iInfo->iMinCommittedSize; - } - -HUEXPORT_C TInt RAllocatorHelper::AllocCountForCell(TAny* aCell) const - { - TUint32 allocCount = 0; - switch (iAllocatorType) - { - case EUdebOldRHeap: - case EUdebHybridHeap: // Both are in the same place, amazingly - { - TLinAddr allocCountAddr = (TLinAddr)aCell - 4; - TInt err = ReadWord(allocCountAddr, allocCount); - if (err) return err; - return (TInt)allocCount; - } - default: - return KErrNotSupported; - } - } - -struct SContext3 - { - RAllocatorHelper::TWalkFunc3 iOrigWalkFn; - TAny* iOrigContext; - }; - -TBool RAllocatorHelper::DispatchClientWalkCallback(RAllocatorHelper& aHelper, TAny* aContext, RAllocatorHelper::TExtendedCellType aCellType, TLinAddr aCellPtr, TInt aCellLength) - { - WalkForStats(aHelper, NULL, aCellType, aCellPtr, aCellLength); - SContext3* context = static_cast(aContext); - return (*context->iOrigWalkFn)(aHelper, context->iOrigContext, aCellType, aCellPtr, aCellLength); - } - -HUEXPORT_C TInt RAllocatorHelper::Walk(TWalkFunc3 aCallbackFn, TAny* aContext) - { - // Might as well take the opportunity of updating our stats at the same time as walking the heap for the client - SContext3 context = { aCallbackFn, aContext }; - - TInt err = FinishConstruction(); // In case this hasn't been done yet - if (err) return err; - - TryLock(); - err = DoWalk(&DispatchClientWalkCallback, &context); - TryUnlock(); - return err; - } - -TInt RAllocatorHelper::DoWalk(TWalkFunc3 aCallbackFn, TAny* aContext) - { - TInt err = KErrNotSupported; - switch (iAllocatorType) - { - case EUdebOldRHeap: - case EUrelOldRHeap: - err = OldSkoolWalk(aCallbackFn, aContext); - break; - case EUrelHybridHeap: - case EUdebHybridHeap: - err = NewHotnessWalk(aCallbackFn, aContext); - break; - default: - err = KErrNotSupported; - break; - } - return err; - } - -struct SContext - { - RAllocatorHelper::TWalkFunc iOrigWalkFn; - TAny* iOrigContext; - }; - -struct SContext2 - { - RAllocatorHelper::TWalkFunc2 iOrigWalkFn; - TAny* iOrigContext; - }; - -#define New2Old(aNew) (((aNew)&RAllocatorHelper::EAllocationMask) ? RAllocatorHelper::EAllocation : ((aNew)&RAllocatorHelper::EFreeMask) ? RAllocatorHelper::EFreeSpace : RAllocatorHelper::EBadness) - -TBool DispatchOldTWalkFuncCallback(RAllocatorHelper& /*aHelper*/, TAny* aContext, RAllocatorHelper::TExtendedCellType aCellType, TLinAddr aCellPtr, TInt aCellLength) - { - SContext* context = static_cast(aContext); - return (*context->iOrigWalkFn)(context->iOrigContext, New2Old(aCellType), aCellPtr, aCellLength); - } - -TBool DispatchOldTWalk2FuncCallback(RAllocatorHelper& aHelper, TAny* aContext, RAllocatorHelper::TExtendedCellType aCellType, TLinAddr aCellPtr, TInt aCellLength) - { - SContext2* context = static_cast(aContext); - return (*context->iOrigWalkFn)(aHelper, context->iOrigContext, New2Old(aCellType), aCellPtr, aCellLength); - } - -HUEXPORT_C TInt RAllocatorHelper::Walk(TWalkFunc aCallbackFn, TAny* aContext) - { - // For backwards compatability insert a compatability callback to map between the different types of callback that clients requested - SContext context = { aCallbackFn, aContext }; - return Walk(&DispatchOldTWalkFuncCallback, &context); - } - -HUEXPORT_C TInt RAllocatorHelper::Walk(TWalkFunc2 aCallbackFn, TAny* aContext) - { - SContext2 context = { aCallbackFn, aContext }; - return Walk(&DispatchOldTWalk2FuncCallback, &context); - } - - -TInt RAllocatorHelper::OldSkoolWalk(TWalkFunc3 aCallbackFn, TAny* aContext) - { - TLinAddr pC = 0; - TInt err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iBase), pC); // pC = iBase; // allocated cells - if (err) return err; - TLinAddr pF = iAllocatorAddress + _FOFF(RHackHeap, iAlign) + 3*4; // pF = &iFree; // free cells - - TLinAddr top = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iTop), top); - if (err) return err; - const TInt KAllocatedCellHeaderSize = iAllocatorType == EUdebOldRHeap ? 12 : 4; - TInt minCell = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iAlign) + 4, (TUint32&)minCell); - if (err) return err; - TInt align = 0; - err = ReadWord(iAllocatorAddress + _FOFF(RHackHeap, iAlign), (TUint32&)align); - if (err) return err; - - FOREVER - { - err = ReadWord(pF+4, pF); // pF = pF->next; // next free cell - if (err) return err; - TLinAddr pFnext = 0; - if (pF) err = ReadWord(pF + 4, pFnext); - if (err) return err; - - if (!pF) - { - pF = top; // to make size checking work - } - else if (pF>=top || (pFnext && pFnext<=pF) ) - { - // free cell pointer off the end or going backwards - //Unlock(); - (*aCallbackFn)(*this, aContext, EHeapBadFreeCellAddress, pF, 0); - return KErrCorrupt; - } - else - { - TInt l; // = pF->len - err = ReadWord(pF, (TUint32&)l); - if (err) return err; - if (llen; - err = ReadWord(pC, (TUint32&)l); - if (err) return err; - if (l pF) - { - // cell overlaps next free cell - //Unlock(); - (*aCallbackFn)(*this, aContext, EHeapBadAllocatedCellAddress, pC, l); - return KErrCorrupt; - } - pC = pN; - } - if (pF == top) - break; // reached end of heap - TInt pFlen = 0; - err = ReadWord(pF, (TUint32&)pFlen); - if (err) return err; - pC = pF + pFlen; // pC = __NEXT_CELL(pF); // step to next allocated cell - TBool shouldContinue = (*aCallbackFn)(*this, aContext, EHeapFreeCell, pF, pFlen); - if (!shouldContinue) return KErrNone; - } - return KErrNone; - } - -HUEXPORT_C TInt RAllocatorHelper::CountUnusedPages() - { - TInt err = CheckValid(EUnusedPages); - if (err) return err; - return iInfo->iUnusedPages; - } - -HUEXPORT_C TInt RAllocatorHelper::CommittedFreeSpace() - { - TInt err = CheckValid(ECommittedFreeSpace); - if (err) return err; - return iInfo->iCommittedFreeSpace; - } - -#define ROUND_DOWN(val, pow2) ((val) & ~((pow2)-1)) -#define ROUND_UP(val, pow2) ROUND_DOWN((val) + (pow2) - 1, (pow2)) - -HUEXPORT_C TLinAddr RAllocatorHelper::AllocatorAddress() const - { - return iAllocatorAddress; - } - -TBool RAllocatorHelper::WalkForStats(RAllocatorHelper& aSelf, TAny* /*aContext*/, TExtendedCellType aType, TLinAddr aCellPtr, TInt aCellLength) - { - //ASSERT(aCellLength >= 0); - THeapInfo& info = *aSelf.iInfo; - - TInt pagesSpanned = 0; // The number of pages that fit entirely inside the payload of this cell - if ((TUint)aCellLength > KPageSize) - { - TLinAddr nextPageAlignedAddr = ROUND_UP(aCellPtr, KPageSize); - pagesSpanned = ROUND_DOWN(aCellPtr + aCellLength - nextPageAlignedAddr, KPageSize) / KPageSize; - } - - if (aSelf.iAllocatorType == EUrelOldRHeap || aSelf.iAllocatorType == EUdebOldRHeap) - { - if (aType & EFreeMask) - { - info.iUnusedPages += pagesSpanned; - info.iCommittedFreeSpace += aCellLength; - info.iHeapFreeCellCount++; - } - } - else - { - if (aType & EAllocationMask) - { - info.iAllocatedSize += aCellLength; - info.iAllocationCount++; - } - else if (aType & EFreeMask) - { - // I *think* that DLA will decommit pages from inside free cells... - TInt committedLen = aCellLength - (pagesSpanned * KPageSize); - info.iCommittedFreeSpace += committedLen; - } - - switch (aType) - { - case EDlaAllocation: - info.iDlaAllocsSize += aCellLength; - info.iDlaAllocsCount++; - break; - case EPageAllocation: - info.iPageAllocsSize += aCellLength; - info.iPageAllocsCount++; - break; - case ESlabAllocation: - info.iSlabAllocsSize += aCellLength; - info.iSlabAllocsCount++; - break; - case EDlaFreeCell: - info.iDlaFreeSize += aCellLength; - info.iDlaFreeCount++; - break; - case ESlabFreeCell: - info.iSlabFreeCellSize += aCellLength; - info.iSlabFreeCellCount++; - break; - case ESlabFreeSlab: - info.iSlabFreeSlabSize += aCellLength; - info.iSlabFreeSlabCount++; - break; - default: - break; - } - } - - return ETrue; - } - -#define PAGESHIFT 12 - -TUint RAllocatorHelper::PageMapOperatorBrackets(unsigned ix, TInt& err) const - { - //return 1U&(iBase[ix>>3] >> (ix&7)); - TUint32 basePtr = 0; - err = ReadWord(iAllocatorAddress + KPageMapOffset, basePtr); - if (err) return 0; - - TUint8 res = 0; - err = ReadByte(basePtr + (ix >> 3), res); - if (err) return 0; - - return 1U&(res >> (ix&7)); - } - - -TInt RAllocatorHelper::PageMapFind(TUint start, TUint bit, TInt& err) - { - TUint32 iNbits = 0; - err = ReadWord(iAllocatorAddress + KPageMapOffset + 4, iNbits); - if (err) return 0; - - if (start>= 1; - if (bits == 0) - return 1; - bits = PageMapBits(pos+2,2,err); - if (err) return 0; - if ((bits & 1) == 0) - return 2 + (bits>>1); - else if ((bits>>1) == 0) - { - return PageMapBits(pos+4, 4,err); - } - else - { - return PageMapBits(pos+4, 18,err); - } - } - -TUint RAllocatorHelper::PageMapBits(unsigned ix, unsigned len, TInt& err) - { - int l=len; - unsigned val=0; - unsigned bit=0; - while (--l>=0) - { - //val |= (*this)[ix++]<= 0 && err == KErrNone;) - { - int npage = PagedDecode(ix, err); - if (err) return err; - // Introduce paged buffer to the walk function - TLinAddr bfr = membase + (1 << (PAGESHIFT-1))*ix; - int len = npage << PAGESHIFT; - if ( (TUint)len > KPageSize ) - { // If buffer is not larger than one page it must be a slab page mapped into bitmap - if (iAllocatorType == EUdebHybridHeap) - { - bfr += 8; - len -= 8; - } - shouldContinue = (*aCallbackFn)(*this, aContext, EPageAllocation, bfr, len); - if (!shouldContinue) return KErrNone; - } - ix += (npage<<1); - } - if (err) return err; - - // Slab - TUint32 sparePage = 0; - err = ReadWord(iAllocatorAddress + KSparePageOffset, sparePage); - if (err) return err; - if (sparePage) - { - //Walk(wi, iSparePage, iPageSize, EGoodFreeCell, ESlabSpare); // Introduce Slab spare page to the walk function - // This counts as 4 spare slabs - for (TInt i = 0; i < 4; i++) - { - shouldContinue = (*aCallbackFn)(*this, aContext, ESlabFreeSlab, sparePage + SLABSIZE*i, SLABSIZE); - if (!shouldContinue) return KErrNone; - } - } - - //TreeWalk(&iFullSlab, &SlabFullInfo, i, wi); - TInt err = TreeWalk(iAllocatorAddress + KFullSlabOffset, ESlabFullInfo, aCallbackFn, aContext, shouldContinue); - if (err || !shouldContinue) return err; - for (int ix = 0; ix < (MAXSLABSIZE>>2); ++ix) - { - TUint32 partialAddr = iAllocatorAddress + KSlabAllocOffset + ix*KSlabsetSize; - //TreeWalk(&iSlabAlloc[ix].iPartial, &SlabPartialInfo, i, wi); - err = TreeWalk(partialAddr, ESlabPartialInfo, aCallbackFn, aContext, shouldContinue); - if (err || !shouldContinue) return err; - } - //TreeWalk(&iPartialPage, &SlabEmptyInfo, i, wi); - TreeWalk(iAllocatorAddress + KPartialPageOffset, ESlabEmptyInfo, aCallbackFn, aContext, shouldContinue); - } - - // DLA -#define CHUNK_OVERHEAD (sizeof(TUint)) -#define CHUNK_ALIGN_MASK (7) -#define CHUNK2MEM(p) ((TLinAddr)(p) + 8) -#define MEM2CHUNK(mem) ((TLinAddr)(p) - 8) -/* chunk associated with aligned address A */ -#define ALIGN_OFFSET(A)\ - ((((TLinAddr)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ - ((8 - ((TLinAddr)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) -#define ALIGN_AS_CHUNK(A) ((A) + ALIGN_OFFSET(CHUNK2MEM(A))) -#define CINUSE_BIT 2 -#define INUSE_BITS 3 - - TUint32 topSize = 0; - err = ReadWord(iAllocatorAddress + KMallocStateOffset + KMallocStateTopSizeOffset, topSize); - if (err) return err; - - TUint32 top = 0; - err = ReadWord(iAllocatorAddress + KMallocStateOffset + KMallocStateTopOffset, top); - if (err) return err; - - TInt max = ((topSize-1) & ~CHUNK_ALIGN_MASK) - CHUNK_OVERHEAD; - if ( max < 0 ) - max = 0; - - TBool shouldContinue = (*aCallbackFn)(*this, aContext, EDlaFreeCell, top, max); - if (!shouldContinue) return KErrNone; - - TUint32 mallocStateSegBase = 0; - err = ReadWord(iAllocatorAddress + KMallocStateOffset + KMallocStateSegOffset, mallocStateSegBase); - if (err) return err; - - for (TLinAddr q = ALIGN_AS_CHUNK(mallocStateSegBase); q != top; /*q = NEXT_CHUNK(q)*/) - { - TUint32 qhead = 0; - err = ReadWord(q + 4, qhead); - if (err) return err; - //TInt sz = CHUNKSIZE(q); - TInt sz = qhead & ~(INUSE_BITS); - if (!(qhead & CINUSE_BIT)) - { - //Walk(wi, CHUNK2MEM(q), sz, EGoodFreeCell, EDougLeaAllocator); // Introduce DL free buffer to the walk function - shouldContinue = (*aCallbackFn)(*this, aContext, EDlaFreeCell, CHUNK2MEM(q), sz); - if (!shouldContinue) return KErrNone; - } - else - { - //Walk(wi, CHUNK2MEM(q), (sz- CHUNK_OVERHEAD), EGoodAllocatedCell, EDougLeaAllocator); // Introduce DL allocated buffer to the walk function - TLinAddr addr = CHUNK2MEM(q); - TInt size = sz - CHUNK_OVERHEAD; - if (iAllocatorType == EUdebHybridHeap) - { - size -= 8; - addr += 8; - } - shouldContinue = (*aCallbackFn)(*this, aContext, EDlaAllocation, addr, size); - if (!shouldContinue) return KErrNone; - } - // This is q = NEXT_CHUNK(q) expanded - q = q + sz; - } - return KErrNone; - } - -TInt RAllocatorHelper::TreeWalk(TUint32 aSlabRoot, TInt aSlabType, TWalkFunc3 aCallbackFn, TAny* aContext, TBool& shouldContinue) - { - const TSlabType type = (TSlabType)aSlabType; - - TUint32 s = 0; - TInt err = ReadWord(aSlabRoot, s); - if (err) return err; - //slab* s = *root; - if (!s) - return KErrNone; - - for (;;) - { - //slab* c; - //while ((c = s->iChild1) != 0) - // s = c; // walk down left side to end - TUint32 c; - for(;;) - { - err = ReadWord(s + KSlabChild1Offset, c); - if (err) return err; - if (c == 0) break; - else s = c; - } - for (;;) - { - //TODOf(s, i, wi); - //TODO __HEAP_CORRUPTED_TEST_STATIC - TUint32 h; - err = ReadWord(s, h); // = aSlab->iHeader; - if (err) return err; - TUint32 size = (h&0x0003f000)>>12; //SlabHeaderSize(h); - TUint debugheadersize = 0; - if (iAllocatorType == EUdebHybridHeap) debugheadersize = 8; - TUint32 usedCount = (((h&0x0ffc0000)>>18) + 4) / size; // (SlabHeaderUsedm4(h) + 4) / size; - switch (type) - { - case ESlabFullInfo: - { - TUint32 count = usedCount; - TUint32 i = 0; - while ( i < count ) - { - TUint32 addr = s + KSlabPayloadOffset + i*size; //&aSlab->iPayload[i*size]; - shouldContinue = (*aCallbackFn)(*this, aContext, ESlabAllocation, addr + debugheadersize, size - debugheadersize); - if (!shouldContinue) return KErrNone; - i++; - } - break; - } - case ESlabPartialInfo: - { - //TODO __HEAP_CORRUPTED_TEST_STATIC - TUint32 count = KMaxSlabPayload / size; - TUint32 freeOffset = (h & 0xff) << 2; - if (freeOffset == 0) - { - // TODO Shouldn't happen for a slab on the partial list - } - memset(iTempSlabBitmap, 1, KTempBitmapSize); // Everything defaults to in use - TUint wildernessCount = count - usedCount; - while (freeOffset) - { - wildernessCount--; - TInt idx = (freeOffset-KSlabPayloadOffset)/size; - LOG("iTempSlabBitmap freeOffset %d index %d", freeOffset, idx); - iTempSlabBitmap[idx] = 0; // Mark it as free - - TUint32 addr = s + freeOffset; - TUint8 nextCell = 0; - err = ReadByte(addr, nextCell); - if (err) return err; - freeOffset = ((TUint32)nextCell) << 2; - } - memset(iTempSlabBitmap + count - wildernessCount, 0, wildernessCount); // Mark the wilderness as free - for (TInt i = 0; i < count; i++) - { - TLinAddr addr = s + KSlabPayloadOffset + i*size; - if (iTempSlabBitmap[i]) - { - // In use - shouldContinue = (*aCallbackFn)(*this, aContext, ESlabAllocation, addr + debugheadersize, size - debugheadersize); - } - else - { - // Free - shouldContinue = (*aCallbackFn)(*this, aContext, ESlabFreeCell, addr, size); - } - if (!shouldContinue) return KErrNone; - } - break; - } - case ESlabEmptyInfo: - { - // Check which slabs of this page are empty - TUint32 pageAddr = ROUND_DOWN(s, KPageSize); - TUint32 headerForPage = 0; - err = ReadWord(pageAddr, headerForPage); - if (err) return err; - TUint32 slabHeaderPageMap = (headerForPage & 0x00000f00)>>8; // SlabHeaderPagemap(unsigned h) - for (TInt slabIdx = 0; slabIdx < 4; slabIdx++) - { - if (slabHeaderPageMap & (1<iPayload[i*size]; - shouldContinue = (*aCallbackFn)(*this, aContext, ESlabFreeSlab, addr, KMaxSlabPayload); - if (!shouldContinue) return KErrNone; - } - } - break; - } - } - - //c = s->iChild2; - err = ReadWord(s + KSlabChild2Offset, c); - if (err) return err; - - if (c) - { // one step down right side, now try and walk down left - s = c; - break; - } - for (;;) - { // loop to walk up right side - TUint32 pp = 0; - err = ReadWord(s + KSlabParentOffset, pp); - if (err) return err; - //slab** pp = s->iParent; - if (pp == aSlabRoot) - return KErrNone; -#define SlabFor(x) ROUND_DOWN(x, SLABSIZE) - s = SlabFor(pp); - //if (pp == &s->iChild1) - if (pp == s + KSlabChild1Offset) - break; - } - } - } - } - -// Really should be called TotalSizeForCellType(...) -HUEXPORT_C TInt RAllocatorHelper::SizeForCellType(TExtendedCellType aType) - { - if (aType & EBadnessMask) return KErrArgument; - if (aType == EAllocationMask) return AllocatedSize(); - - if (iAllocatorType == EUdebOldRHeap || iAllocatorType == EUrelOldRHeap) - { - switch (aType) - { - case EHeapAllocation: - return AllocatedSize(); - case EHeapFreeCell: - case EFreeMask: - return CommittedFreeSpace(); - default: - return KErrNotSupported; - } - } - else if (iAllocatorType == EUrelHybridHeap || iAllocatorType == EUdebHybridHeap) - { - TInt err = CheckValid(EHybridStats); - if (err) return err; - - switch (aType) - { - case EHeapAllocation: - case EHeapFreeCell: - return KErrNotSupported; - case EDlaAllocation: - return iInfo->iDlaAllocsSize; - case EPageAllocation: - return iInfo->iPageAllocsSize; - case ESlabAllocation: - return iInfo->iSlabAllocsSize; - case EDlaFreeCell: - return iInfo->iDlaFreeSize; - case ESlabFreeCell: - return iInfo->iSlabFreeCellSize; - case ESlabFreeSlab: - return iInfo->iSlabFreeSlabSize; - case EFreeMask: - // Note this isn't the same as asking for CommittedFreeSpace(). SizeForCellType(EFreeMask) may include decommitted pages that lie inside a free cell - return iInfo->iDlaFreeSize + iInfo->iSlabFreeCellSize + iInfo->iSlabFreeSlabSize; - default: - return KErrNotSupported; - } - } - else - { - return KErrNotSupported; - } - } - -HUEXPORT_C TInt RAllocatorHelper::CountForCellType(TExtendedCellType aType) - { - if (aType & EBadnessMask) return KErrArgument; - if (aType == EAllocationMask) return AllocationCount(); - - if (iAllocatorType == EUdebOldRHeap || iAllocatorType == EUrelOldRHeap) - { - switch (aType) - { - case EHeapAllocation: - return AllocationCount(); - case EHeapFreeCell: - case EFreeMask: - { - TInt err = CheckValid(ECommittedFreeSpace); - if (err) return err; - return iInfo->iHeapFreeCellCount; - } - default: - return KErrNotSupported; - } - } - else if (iAllocatorType == EUrelHybridHeap || iAllocatorType == EUdebHybridHeap) - { - TInt err = CheckValid(EHybridStats); - if (err) return err; - - switch (aType) - { - case EHeapAllocation: - case EHeapFreeCell: - return KErrNotSupported; - case EDlaAllocation: - return iInfo->iDlaAllocsCount; - case EPageAllocation: - return iInfo->iPageAllocsCount; - case ESlabAllocation: - return iInfo->iSlabAllocsCount; - case EDlaFreeCell: - return iInfo->iDlaFreeCount; - case ESlabFreeCell: - return iInfo->iSlabFreeCellCount; - case ESlabFreeSlab: - return iInfo->iSlabFreeSlabCount; - case EFreeMask: - // This isn't a hugely meaningful value, but if that's what they asked for... - return iInfo->iDlaFreeCount + iInfo->iSlabFreeCellCount + iInfo->iSlabFreeSlabCount; - default: - return KErrNotSupported; - } - } - else - { - return KErrNotSupported; - } - } - -HUEXPORT_C TBool LtkUtils::RAllocatorHelper::AllocatorIsUdeb() const - { - return iAllocatorType == EUdebOldRHeap || iAllocatorType == EUdebHybridHeap; - } - - -HUEXPORT_C const TDesC& LtkUtils::RAllocatorHelper::Description() const - { - _LIT(KRHeap, "RHeap"); - _LIT(KRHybridHeap, "RHybridHeap"); - _LIT(KUnknown, "Unknown"); - switch (iAllocatorType) - { - case EUrelOldRHeap: - case EUdebOldRHeap: - return KRHeap; - case EUrelHybridHeap: - case EUdebHybridHeap: - return KRHybridHeap; - case EAllocator: - case EUnknown: - default: - return KUnknown; - } - } - -#ifdef __KERNEL_MODE__ - -DChunk* LtkUtils::RAllocatorHelper::OpenUnderlyingChunk() - { - // Enter and leave in CS and with no locks held. On exit the returned DChunk has been Open()ed. - TInt err = iChunk->Open(); - if (err) return NULL; - return iChunk; - } - -DChunk* LtkUtils::RKernelSideAllocatorHelper::OpenUnderlyingChunk() - { - if (iAllocatorType != EUrelOldRHeap && iAllocatorType != EUdebOldRHeap && iAllocatorType != EUrelHybridHeap && iAllocatorType != EUdebHybridHeap) return NULL; - // Note RKernelSideAllocatorHelper doesn't use or access RAllocatorHelper::iChunk, because we figure out the chunk handle in a different way. - // It is for this reason that iChunk is private, to remove temptation - - // Enter and leave in CS and with no locks held. On exit the returned DChunk has been Open()ed. - TUint32 chunkHandle = 0; - TInt err = ReadData(iAllocatorAddress + _FOFF(RHackHeap, iChunkHandle), &chunkHandle, sizeof(TUint32)); - if (err) return NULL; - - NKern::LockSystem(); - DChunk* result = (DChunk*)Kern::ObjectFromHandle(iThread, chunkHandle, EChunk); - if (result && result->Open() != KErrNone) - { - result = NULL; - } - NKern::UnlockSystem(); - return result; - } - -LtkUtils::RAllocatorHelper::TType LtkUtils::RAllocatorHelper::GetType() const - { - switch (iAllocatorType) - { - case EUrelOldRHeap: - case EUdebOldRHeap: - return ETypeRHeap; - case EUrelHybridHeap: - case EUdebHybridHeap: - return ETypeRHybridHeap; - case EAllocator: - case EUnknown: - default: - return ETypeUnknown; - } - } - -#else - -TInt LtkUtils::RAllocatorHelper::EuserIsUdeb() - { - TAny* buf = User::Alloc(4096); - if (!buf) return KErrNoMemory; - RAllocator* dummyHeap = UserHeap::FixedHeap(buf, 4096, 4, ETrue); - if (!dummyHeap) return KErrNoMemory; // Don't think this can happen - - dummyHeap->__DbgSetAllocFail(RAllocator::EFailNext, 1); - TAny* ptr = dummyHeap->Alloc(4); - // Because we specified singleThreaded=ETrue we can allow dummyHeap to just go out of scope here - User::Free(buf); - - if (ptr) - { - // Clearly the __DbgSetAllocFail had no effect so we must be urel - // We don't need to free ptr because it came from the dummy heap - return EFalse; - } - else - { - return ETrue; - } - } - -#ifndef STANDALONE_ALLOCHELPER - -#include -HUEXPORT_C void LtkUtils::MakeHeapCellInvisible(TAny* aCell) - { - RAllocatorHelper helper; - TInt err = helper.Open(&User::Allocator()); - if (err == KErrNone) - { - helper.SetCellNestingLevel(aCell, -1); - helper.Close(); - } - } -#endif // STANDALONE_ALLOCHELPER - -#endif