Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// Copyright (c) 2002-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:
// e32test\heap\t_heap2.cpp
// Overview:
// Tests RHeap class, including a stress test and a "grow in place"
// ReAlloc test.
// API Information:
// RHeap
// Details:
// - Test allocation on fixed length heaps in local, disconnected chunks for
// different heap sizes and alignments. Assumes knowledge of heap
// implementation.
// - Test allocation, free, reallocation and compression on chunk heaps with
// different maximum and minimum lengths and alignments. Assumes knowledge
// of heap implementation.
// - Stress test heap implementation with a single thread that allocates, frees
// and reallocates cells, and checks the heap.
// - Stress test heap implementation with two threads that run concurrently.
// - Create a chunk heap, test growing in place by allocating a cell and
// then reallocating additional space until failure, verify that the cell
// did not move and the size was increased.
// - The heap is checked to verify that no cells remain allocated after the
// tests are complete.
// Platforms/Drives/Compatibility:
// All
// Assumptions/Requirement/Pre-requisites:
// Failures and causes:
// Base Port information:
//
//
#include <e32test.h>
#include <e32hal.h>
#include <e32def.h>
#include <e32def_private.h>
// Needed for KHeapShrinkHysRatio which is now ROM 'patchdata'
#include "TestRHeapShrink.h"
#define DECL_GET(T,x) inline T x() const {return i##x;}
#define DECL_GET2(T,x,y) inline T y() const {return i##x;}
#ifdef __EABI__
IMPORT_D extern const TInt KHeapMinCellSize;
#else
const TInt KHeapMinCellSize = 0;
#endif
RTest test(_L("T_HEAP2"));
#define TEST_ALIGN(p,a) test((TLinAddr(p)&((a)-1))==0)
struct STestCell
{
enum {EMagic = 0xb8aa3b29};
TUint32 iLength;
TUint32 iData[1];
void Set(TInt aLength);
void Verify(TInt aLength);
void Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength);
};
void STestCell::Set(TInt aLength)
{
TInt i;
TUint32 x = (TUint32)this ^ (TUint32)aLength ^ (TUint32)EMagic;
aLength -= RHeap::EAllocCellSize;
if (aLength==0)
return;
iLength = x;
aLength /= sizeof(TUint32);
for (i=0; i<aLength-1; ++i)
{
x *= 69069;
x += 41;
iData[i] = x;
}
}
void STestCell::Verify(TInt aLength)
{
Verify(this, aLength, aLength);
}
void STestCell::Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength)
{
TInt i;
TUint32 x = (TUint32)aInitPtr ^ (TUint32)aInitLength ^ (TUint32)EMagic;
aLength -= RHeap::EAllocCellSize;
if (aLength==0)
return;
test(iLength == x);
aLength /= sizeof(TUint32);
for (i=0; i<aLength-1; ++i)
{
x *= 69069;
x += 41;
test(iData[i] == x);
}
}
class RTestHeap : public RHeap
{
public:
DECL_GET(TInt,AccessCount)
DECL_GET(TInt,HandleCount)
DECL_GET(TInt*,Handles)
DECL_GET(TUint32,Flags)
DECL_GET(TInt,CellCount)
DECL_GET(TInt,TotalAllocSize)
DECL_GET(TInt,MinLength)
DECL_GET(TInt,Offset)
DECL_GET(TInt,GrowBy)
DECL_GET(TInt,ChunkHandle)
DECL_GET2(const RFastLock&,Lock,LockRef)
DECL_GET(TUint8*,Top)
DECL_GET(TInt,Align)
DECL_GET(TInt,MinCell)
DECL_GET(TInt,PageSize)
DECL_GET2(const SCell&,Free,FreeRef)
public:
TInt CheckAllocatedCell(const TAny* aCell) const;
void FullCheckAllocatedCell(const TAny* aCell) const;
TAny* TestAlloc(TInt aSize);
void TestFree(TAny* aPtr);
TAny* TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0);
void FullCheck();
static void WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen);
TInt FreeCellLen(const TAny* aPtr) const;
static RTestHeap* FixedHeap(TInt aMaxLength, TInt aAlign=0, TBool aSingleThread=ETrue);
void TakeChunkOwnership(RChunk aChunk);
TInt LastFreeCellLen(void) const;
TInt CalcComp(TInt aCompSize);
void ForceCompress(TInt aFreed);
};
TInt RTestHeap::CheckAllocatedCell(const TAny* aCell) const
{
SCell* pC = GetAddress(aCell);
TInt len = pC->len;
TUint8* pEnd = (TUint8*)pC + len;
TEST_ALIGN(aCell, iAlign);
TEST_ALIGN(len, iAlign);
test(len >= iMinCell);
test((TUint8*)pC>=iBase && pEnd<=iTop);
return len;
}
void RTestHeap::FullCheckAllocatedCell(const TAny* aCell) const
{
((STestCell*)aCell)->Verify(CheckAllocatedCell(aCell));
}
TAny* RTestHeap::TestAlloc(TInt aSize)
{
TAny* p = Alloc(aSize);
if (p)
{
TInt len = CheckAllocatedCell(p);
test((len-RHeap::EAllocCellSize)>=aSize);
((STestCell*)p)->Set(len);
}
return p;
}
void RTestHeap::TestFree(TAny* aPtr)
{
if (aPtr)
FullCheckAllocatedCell(aPtr);
Free(aPtr);
}
TAny* RTestHeap::TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode)
{
TInt old_len = aPtr ? CheckAllocatedCell(aPtr) : 0;
if (aPtr)
((STestCell*)aPtr)->Verify(old_len);
TAny* p = ReAlloc(aPtr, aSize, aMode);
if (!p)
{
((STestCell*)aPtr)->Verify(old_len);
return p;
}
TInt new_len = CheckAllocatedCell(p);
test((new_len-RHeap::EAllocCellSize)>=aSize);
if (p == aPtr)
{
((STestCell*)p)->Verify(p, old_len, Min(old_len, new_len));
if (new_len != old_len)
((STestCell*)p)->Set(new_len);
return p;
}
test(!(aMode & ENeverMove));
test((new_len > old_len) || (aMode & EAllowMoveOnShrink));
if (old_len)
((STestCell*)p)->Verify(aPtr, old_len, Min(old_len, new_len));
if (new_len != old_len)
((STestCell*)p)->Set(new_len);
return p;
}
struct SHeapCellInfo
{
RTestHeap* iHeap;
TInt iTotalAlloc;
TInt iTotalAllocSize;
TInt iTotalFree;
TUint8* iNextCell;
};
void RTestHeap::WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen)
{
(void)aCell;
::SHeapCellInfo& info = *(::SHeapCellInfo*)aPtr;
switch(aType)
{
case EGoodAllocatedCell:
{
test(aCell == info.iNextCell);
TInt len = ((SCell*)aCell)->len;
test(len == aLen);
info.iNextCell += len;
++info.iTotalAlloc;
info.iTotalAllocSize += (aLen-EAllocCellSize);
STestCell* pT = (STestCell*)((TUint8*)aCell + EAllocCellSize);
pT->Verify(len);
break;
}
case EGoodFreeCell:
{
test(aCell == info.iNextCell);
TInt len = ((SCell*)aCell)->len;
test(len == aLen);
info.iNextCell += len;
++info.iTotalFree;
break;
}
default:
test.Printf(_L("TYPE=%d ??\n"),aType);
test(0);
break;
}
}
void RTestHeap::FullCheck()
{
::SHeapCellInfo info;
Mem::FillZ(&info, sizeof(info));
info.iHeap = this;
info.iNextCell = iBase;
DebugFunction(EWalk, (TAny*)&WalkFullCheckCell, &info);
test(info.iNextCell == iTop);
test(info.iTotalAlloc == iCellCount);
test(info.iTotalAllocSize == iTotalAllocSize);
}
TInt RTestHeap::FreeCellLen(const TAny* aPtr) const
{
SCell* p = iFree.next;
SCell* q = (SCell*)((TUint8*)aPtr - EAllocCellSize);
for (; p && p!=q; p = p->next) {}
if (p == q)
return p->len - EAllocCellSize;
return -1;
}
TInt RTestHeap::LastFreeCellLen(void) const
{
SCell* p = iFree.next;
if (p==NULL)
return -1;
for (; p->next; p=p->next){}
return p->len;
}
/** Checks whether a call to Compress() will actually perform a reduction
of the heap.
Relies on the free last cell on the heap being cell that has just been freed
plus any extra.
Intended for use by t_heap2.cpp - DoTest4().
@param aFreedSize The size in bytes of the cell that was freed
*/
TInt RTestHeap::CalcComp(TInt aFreedSize)
{
TInt largestCell=0;
largestCell = LastFreeCellLen();
// if the largest cell is too small or it would have been compressed by the
// free operation then return 0.
if (largestCell < iPageSize || aFreedSize >= KHeapShrinkHysRatio*(iGrowBy>>8))
{
return 0;
}
else
{
return _ALIGN_DOWN(aFreedSize,iPageSize);
}
}
/** compress the heap if the KHeapShrinkRatio is too large for what we are
expecting in DoTest4().
*/
void RTestHeap::ForceCompress(TInt aFreed)
{
if (aFreed < KHeapShrinkHysRatio*(iGrowBy>>8))
{
Compress();
}
}
RTestHeap* RTestHeap::FixedHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread)
{
RChunk c;
TInt bottom = 0x40000;
TInt top = bottom + aMaxLength;
TInt r = c.CreateDisconnectedLocal(bottom, top, top + bottom, EOwnerThread);
if (r!=KErrNone)
return NULL;
TUint8* base = c.Base() + bottom;
RTestHeap* h = (RTestHeap*)UserHeap::FixedHeap(base, aMaxLength, aAlign, aSingleThread);
if (!aAlign)
aAlign = RHeap::ECellAlignment;
test((TUint8*)h == base);
test(h->AccessCount() == 1);
test(h->HandleCount() == (aSingleThread ? 0 : 1));
test(h->Handles() == (aSingleThread ? NULL : (TInt*)&h->LockRef()));
test(h->Flags() == TUint32(RAllocator::EFixedSize | (aSingleThread ? RAllocator::ESingleThreaded : 0)));
test(h->CellCount() == 0);
test(h->TotalAllocSize() == 0);
test(h->MaxLength() == aMaxLength);
test(h->MinLength() == h->Top() - (TUint8*)h);
test(h->Offset() == 0);
test(h->GrowBy() == 0);
test(h->ChunkHandle() == 0);
test(h->Align() == aAlign);
TInt min_cell = _ALIGN_UP((KHeapMinCellSize + Max((TInt)RHeap::EAllocCellSize, (TInt)RHeap::EFreeCellSize)), aAlign);
TInt hdr_len = _ALIGN_UP(sizeof(RHeap) + RHeap::EAllocCellSize, aAlign) - RHeap::EAllocCellSize;
TInt user_len = _ALIGN_DOWN(aMaxLength - hdr_len, aAlign);
test(h->Base() == base + hdr_len);
test(h->MinCell() == min_cell);
test(h->Top() - h->Base() == user_len);
test(h->FreeRef().next == (RHeap::SCell*)h->Base());
h->TakeChunkOwnership(c);
return h;
}
void RTestHeap::TakeChunkOwnership(RChunk aChunk)
{
iChunkHandle = aChunk.Handle();
++iHandleCount;
iHandles = &iChunkHandle;
}
#define ACCESS_COUNT(h) (((RTestHeap*)h)->AccessCount())
#define HANDLE_COUNT(h) (((RTestHeap*)h)->HandleCount())
#define HANDLES(h) (((RTestHeap*)h)->Handles())
#define FLAGS(h) (((RTestHeap*)h)->Flags())
#define CELL_COUNT(h) (((RTestHeap*)h)->CellCount())
#define TOTAL_ALLOC_SIZE(h) (((RTestHeap*)h)->TotalAllocSize())
#define MIN_LENGTH(h) (((RTestHeap*)h)->MinLength())
#define OFFSET(h) (((RTestHeap*)h)->Offset())
#define GROW_BY(h) (((RTestHeap*)h)->GrowBy())
#define CHUNK_HANDLE(h) (((RTestHeap*)h)->ChunkHandle())
#define LOCK_REF(h) (((RTestHeap*)h)->LockRef())
#define TOP(h) (((RTestHeap*)h)->Top())
#define ALIGN(h) (((RTestHeap*)h)->Align())
#define MIN_CELL(h) (((RTestHeap*)h)->MinCell())
#define PAGE_SIZE(h) (((RTestHeap*)h)->PageSize())
#define FREE_REF(h) (((RTestHeap*)h)->FreeRef())
void DoTest1(RHeap* aH)
{
RTestHeap* h = (RTestHeap*)aH;
test.Printf(_L("Test Alloc: min=%x max=%x align=%d growby=%d\n"),
h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
TInt l;
TAny* p = NULL;
TUint8* next = h->Base();
TUint8* top = h->Top();
TUint8* limit = (TUint8*)h + h->MaxLength();
TBool fixed = h->Flags() & RAllocator::EFixedSize;
for (l=1; l<=1024; ++l)
{
TInt remain1 = top - next;
TInt xl1 = _ALIGN_UP(Max((l+RHeap::EAllocCellSize), h->MinCell()), h->Align());
p = h->TestAlloc(l);
if ( (fixed && remain1 < xl1) || (next + xl1 > limit) )
{
test(p == NULL);
test(top == h->Top());
test.Printf(_L("Alloc failed at l=%d next=%08x\n"), l, next);
break;
}
test(p == next + RHeap::EAllocCellSize);
if (xl1 > remain1)
{
// no room for this cell
TInt g = h->GrowBy();
while (xl1 > remain1)
{
top += g;
remain1 += g;
}
}
test(top == h->Top());
if (xl1 + h->MinCell() > remain1)
{
// this cell fits but remainder is too small or nonexistent
xl1 = top - next;
next = top;
test(h->FreeRef().next == NULL);
}
else
{
// this cell fits and remainder can be reused
next += xl1;
}
test(aH->AllocLen(p) == xl1 - RHeap::EAllocCellSize);
}
h->FullCheck();
}
void DoTest2(RHeap* aH)
{
RTestHeap* h = (RTestHeap*)aH;
test.Printf(_L("Test Free: min=%x max=%x align=%d growby=%d\n"),
h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
TInt al;
TInt min = h->MinCell();
TBool pad = EFalse;
for (al=1; al<256; (void)((pad=!pad)!=0 || (al+=al+1)) )
{
TAny* p[32];
TInt last_len = 0;
TAny* last = NULL;
TInt i;
test.Printf(_L("al=%d pad=%d\n"), al, pad);
TUint8* top=0;
TAny* spare=0;
TBool heapReduced = EFalse;
for (i=0; i<32; ++i)
{
// Check whether the cell created for the allocation of al would end up
// including extra bytes from the last free cell that aren't enough
// to create a new free cell.
top = h->Top();
TInt freeLen=h->LastFreeCellLen();
TInt actualAllocBytes = Max(_ALIGN_UP(al + RHeap::EAllocCellSize, h->Align()), min);
TInt remainingBytes = freeLen - actualAllocBytes;
if (remainingBytes < min)
{
// Force the heap to grow so that once this allocation is freed
// the free cell left will be large enough to include the al allocation
// and to create a new free cell if necessary.
actualAllocBytes = _ALIGN_UP(actualAllocBytes + min, h->Align());
TAny* q = h->TestAlloc(actualAllocBytes);
// Check heap has grown
test(top < h->Top());
top = h->Top();
test(q!=NULL);
// Have grown the heap so allocate a cell as a place holder to stop
// the heap being shrunk and the actual cell we want to allocate from being the
// wrong size
spare=h->TestAlloc(8);
h->TestFree(q);
// Ensure heap wasn't shrunk after free
test(top == h->Top());
}
top = h->Top();
// Allocate the new
p[i] = h->TestAlloc(al);
test(p[i]!=NULL);
if (remainingBytes < min)
{// now safe to free any padding as p[i] now allocated and its size can't change
h->TestFree(spare);
}
TInt tmp1=h->AllocLen(p[i]);
TInt tmp2=Max(_ALIGN_UP(al+RHeap::EAllocCellSize,h->Align()), min)-RHeap::EAllocCellSize;
test(tmp1 == tmp2);
}
last = (TUint8*)p[31] + _ALIGN_UP(Max((al + RHeap::EAllocCellSize), min), h->Align());
last_len = h->FreeCellLen(last);
test(last_len > 0);
if (pad)
{
test(h->TestAlloc(last_len) == last);
test(h->FreeRef().next == NULL);
}
else
last = NULL;
top = h->Top();
for (i=0,heapReduced=EFalse; i<32; ++i)
{
h->TestFree(p[i]);
TInt fl = h->FreeCellLen(p[i]);
TInt xfl = _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
{
top = h->Top();
heapReduced = ETrue;
}
if (i < 31 || pad)
test(fl == xfl);
else
{
if (!heapReduced)
test(fl == xfl + RHeap::EAllocCellSize + last_len);
else
{
heapReduced = EFalse;
}
}
test(h->TestAlloc(al)==p[i]);
}
for (i=0,heapReduced=EFalse; i<31; ++i)
{
TInt j = i+1;
TUint8* q;
// Free to adjacent cells and check that the free cell left is the combined
// size of the 2 adjacent cells just freed
h->TestFree(p[i]);
h->TestFree(p[j]);
TInt fl = h->FreeCellLen(p[i]);
if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
{
top = h->Top();
heapReduced = ETrue;
}
TInt xfl = 2 * _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
if (j < 31 || pad)
test(fl == xfl);
else
{
if (!heapReduced)
test(fl == xfl + RHeap::EAllocCellSize + last_len);
else
{
heapReduced = EFalse;
}
}
test(h->FreeCellLen(p[j]) < 0);
test(h->TestAlloc(fl)==p[i]);
test(h->Top() == top);
h->TestFree(p[i]);
test(h->FreeCellLen(p[i]) == fl);
// test when you alloc a cell that is larger than cells just freed
// that its position is not the same as the freed cells
// will hold for all cells except top/last one
if (j < 31 && !pad && fl < last_len)
{
q = (TUint8*)h->TestAlloc(fl+1);
if (h->Top() > top)
top = h->Top();
test(h->Top() == top);
test(q > p[i]);
h->TestFree(q);
if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
{
top = h->Top();
heapReduced = ETrue;
}
}
// check cell that is just smaller than space but not small enough
// for a new free cell to be created, is the size of whole free cell
test(h->TestAlloc(fl-min+1)==p[i]);
test(h->Top() == top);
test(h->AllocLen(p[i])==fl);
h->TestFree(p[i]);
// Check cell that is small enough for new free cell and alloc'd cell to be
// created at p[i] cell is created at p[i]
test(h->TestAlloc(fl-min)==p[i]);
test(h->Top() == top);
// check free cell is at expected position
q = (TUint8*)p[i] + fl - min + RHeap::EAllocCellSize;
test(h->FreeCellLen(q) == min - RHeap::EAllocCellSize);
// alloc 0 length cell at q, will work as new cell of min length will be created
test(h->TestAlloc(0) == q);
test(h->Top() == top);
h->TestFree(p[i]);
test(h->FreeCellLen(p[i]) == fl - min);
h->TestFree(q);
// again check free cells are combined
test(h->FreeCellLen(q) < 0);
test(h->FreeCellLen(p[i]) == fl);
// check reallocating the cells places them back to same positions
test(h->TestAlloc(al)==p[i]);
test(h->Top() == top);
test(h->TestAlloc(al)==p[j]);
test(h->Top() == top);
if (pad)
test(h->FreeRef().next == NULL);
}
for (i=0,heapReduced=EFalse; i<30; ++i)
{
TInt j = i+1;
TInt k = i+2;
TUint8* q;
// Free 3 adjacent cells and check free cell created is combined size
h->TestFree(p[i]);
h->TestFree(p[k]);
h->TestFree(p[j]);
h->FullCheck();
if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
{
top = h->Top();
heapReduced = ETrue;
}
TInt fl = h->FreeCellLen(p[i]);
TInt xfl = 3 * _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
if (k < 31 || pad)
test(fl == xfl);
else
{
if (!heapReduced)
test(fl == xfl + RHeap::EAllocCellSize + last_len);
else
{
heapReduced = EFalse;
}
}
test(h->FreeCellLen(p[j]) < 0);
test(h->FreeCellLen(p[k]) < 0);
//ensure created free cell is allocated to new cell of free cell size
test(h->TestAlloc(fl)==p[i]);
test(h->Top() == top);
h->TestFree(p[i]);
test(h->FreeCellLen(p[i]) == fl);
if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
top = h->Top();
if (k < 31 && !pad && fl < last_len)
{
// Test new cell one larger than free cell size is allocated somewhere else
q = (TUint8*)h->TestAlloc(fl+1);
if (h->Top() > top)
top = h->Top();
test(h->Top() == top);
test(q > p[i]);
h->TestFree(q);
if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
{
top = h->Top();
heapReduced = ETrue;
}
}
// check allocating cell just smaller than free cell size but
// too large for neew free cell to be created, is size of whole free cell
test(h->TestAlloc(fl-min+1)==p[i]);
test(h->Top() == top);
test(h->AllocLen(p[i])==fl);
h->TestFree(p[i]);
// ensure free cell is created this time as well as alloc'd cell
test(h->TestAlloc(fl-min)==p[i]);
test(h->Top() == top);
q = (TUint8*)p[i] + fl - min + RHeap::EAllocCellSize;
test(h->FreeCellLen(q) == min - RHeap::EAllocCellSize);
test(h->TestAlloc(0) == q);
test(h->Top() == top);
h->TestFree(p[i]);
test(h->FreeCellLen(p[i]) == fl - min);
h->TestFree(q);
test(h->FreeCellLen(q) < 0);
test(h->FreeCellLen(p[i]) == fl);
// realloc all cells and check heap not expanded
test(h->TestAlloc(al)==p[i]);
test(h->Top() == top);
test(h->TestAlloc(al)==p[j]);
test(h->Top() == top);
test(h->TestAlloc(al)==p[k]);
test(h->Top() == top);
// If padding than no space should left on heap
if (pad)
test(h->FreeRef().next == NULL);
}
// when padding this will free padding from top of heap
h->TestFree(last);
}
h->FullCheck();
}
void DoTest3(RHeap* aH)
{
RTestHeap* h = (RTestHeap*)aH;
test.Printf(_L("Test ReAlloc: min=%x max=%x align=%d growby=%d\n"),
h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
// allocate continuous heap cell, then free them and reallocate again
TInt al;
for (al=1; al<256; al+=al+1)
{
TAny* p0 = h->TestAlloc(al);
TInt al0 = h->AllocLen(p0);
h->TestFree(p0);
TAny* p1 = h->TestReAlloc(NULL, al, 0);
TInt al1 = h->AllocLen(p1);
test(p1 == p0);
test(al1 == al0);
h->TestFree(p1);
TAny* p2 = h->TestAlloc(1);
TAny* p3 = h->TestReAlloc(p2, al, 0);
test(p3 == p0);
TInt al3 = h->AllocLen(p3);
test(al3 == al0);
h->TestFree(p3);
TAny* p4 = h->TestAlloc(1024);
TAny* p5 = h->TestReAlloc(p4, al, 0);
test(p5 == p0);
TInt al5 = h->AllocLen(p5);
test(al5 == al0);
h->TestFree(p5);
}
TInt i;
TInt j;
for (j=0; j<30; j+=3)
{
TAny* p[30];
TInt ala[30];
TInt fla[30];
h->Reset();
for (i=0; i<30; ++i)
{
p[i] = h->TestAlloc(8*i*i);
ala[i] = h->AllocLen(p[i]);
fla[i] = 0;
}
for (i=1; i<30; i+=3)
{
h->TestFree(p[i]);
fla[i] = h->FreeCellLen(p[i]);
test(fla[i] == ala[i]);
test(h->FreeCellLen(p[i-1]) < 0);
test(h->FreeCellLen(p[i+1]) < 0);
}
h->FullCheck();
TInt al1 = _ALIGN_UP(Max((RHeap::EAllocCellSize + 1), h->MinCell()), h->Align());
// adjust al1 for some case when reallocated heap cell will not be shrinked because remainder will not big enough
// to form a new free cell due to a big KHeapMinCellSize value
TInt alaj = ala[j] + RHeap::EAllocCellSize;
if (al1 < alaj && alaj - al1 < h->MinCell())
al1 = alaj;
TAny* p1 = h->TestReAlloc(p[j], 1, RHeap::ENeverMove);
test(p1 == p[j]);
test(h->AllocLen(p1) == al1 - RHeap::EAllocCellSize);
TAny* p1b = (TUint8*)p1 + al1;
test(h->FreeCellLen(p1b) == fla[j+1] + RHeap::EAllocCellSize + ala[j] - al1);
TInt l2 = ala[j] + fla[j+1] + RHeap::EAllocCellSize; // max without moving
TInt l3 = l2 - h->MinCell();
TAny* p3 = h->TestReAlloc(p[j], l3, RHeap::ENeverMove);
test(p3 == p[j]);
TAny* p3b = (TUint8*)p3 + h->AllocLen(p3) + RHeap::EAllocCellSize;
test(h->FreeCellLen(p3b) == h->MinCell() - RHeap::EAllocCellSize);
TAny* p2 = h->TestReAlloc(p[j], l2, RHeap::ENeverMove);
test(p2 == p[j]);
test(h->AllocLen(p2) == l2);
TAny* p4 = h->TestReAlloc(p[j], l2+1, RHeap::ENeverMove);
test(p4 == NULL);
test(h->AllocLen(p2) == l2);
TAny* p5 = h->TestReAlloc(p[j], l2+1, 0);
TInt k = 0;
for (; k<30 && fla[k] <= l2; ++k) {}
if (k < 30)
test(p5 == p[k]);
else
test(p5 >= (TUint8*)p[29] + ala[29]);
test(h->FreeCellLen(p2) == ala[j] + ala[j+1] + RHeap::EAllocCellSize);
TInt ali = _ALIGN_UP(RHeap::EAllocCellSize,h->Align());
TAny* p6b = (TUint8*)p[j+2] + ala[j+2] - ali + RHeap::EAllocCellSize;
test(h->FreeCellLen(p6b) < 0);
TAny* p6 = h->TestReAlloc(p[j+2], ala[j+2] - ali , 0);
test(p6 == p[j+2]);
if (h->AllocLen(p6) != ala[j+2]) // allocated heap cell size changed
test(h->FreeCellLen(p6b) == h->MinCell() - RHeap::EAllocCellSize);
TInt g = h->GrowBy();
TAny* p7 = h->TestReAlloc(p5, 8*g, 0);
test(p7 >= p5);
TUint8* p8 = (TUint8*)p7 - RHeap::EAllocCellSize + al1;
TUint8* p9 = (TUint8*)_ALIGN_UP(TLinAddr(p8), h->PageSize());
if (p9-p8 < h->MinCell())
p9 += h->PageSize();
TAny* p7b = h->TestReAlloc(p7, 1, 0);
test(p7b == p7);
test(h->Top() + (RHeap::EAllocCellSize & (h->Align()-1)) == p9);
h->FullCheck();
}
}
// Test compression
// {1 free cell, >1 free cell} x {reduce cell, eliminate cell, reduce cell but too small}
//
void DoTest4(RHeap* aH)
{
RTestHeap* h = (RTestHeap*)aH;
test.Printf(_L("Test Compress: min=%x max=%x align=%d growby=%d\n"),
h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
TInt page_size;
UserHal::PageSizeInBytes(page_size);
test(page_size == h->PageSize());
TInt g = h->GrowBy();
TEST_ALIGN(g, page_size);
test(g >= page_size);
RChunk c;
c.SetHandle(h->ChunkHandle());
TInt align = h->Align();
TInt minc = h->MinCell();
TInt orig_size = c.Size();
TUint8* orig_top = h->Top();
// size in bytes that last free cell on the top of the heap must be
// before the heap will be shrunk, size must include the no of bytes to
// store the cell data/header i.e RHeap::EAllocCellSize
TInt shrinkThres = KHeapShrinkHysRatio*(g>>8);
TInt pass;
for (pass=0; pass<2; ++pass)
{
TUint8* p0 = (TUint8*)h->TestAlloc(4);
test(p0 == h->Base() + RHeap::EAllocCellSize);
TInt l1 = h->Top() - (TUint8*)h->FreeRef().next;
TEST_ALIGN(l1, align);
l1 -= RHeap::EAllocCellSize;
TUint8* p1;
// Grow heap by 2*iGrowBy bytes
p1 = (TUint8*)h->TestAlloc(l1 + 2*g);
test(p1 == p0 + h->AllocLen(p0) + RHeap::EAllocCellSize);
test(h->Top() - orig_top == 2*g);
test(c.Size() - orig_size == 2*g);
// May compress heap, may not
h->TestFree(p1);
h->ForceCompress(2*g);
test(h->Top() == orig_top);
test(c.Size() == orig_size);
test((TUint8*)h->FreeRef().next == p1 - RHeap::EAllocCellSize);
h->FullCheck();
//if KHeapShrinkHysRatio is > 2.0 then heap compression will occur here
test(h->Compress() == 0);
test(h->TestAlloc(l1) == p1);
test(h->FreeRef().next == NULL);
if (pass)
h->TestFree(p0); // leave another free cell on second pass
TInt l2 = g - RHeap::EAllocCellSize;
// Will grow heap by iGrowBy bytes
TUint8* p2 = (TUint8*)h->TestAlloc(l2);
test(p2 == orig_top + RHeap::EAllocCellSize);
test(h->Top() - orig_top == g);
test(c.Size() - orig_size == g);
// may or may not compress heap
h->TestFree(p2);
if (l2+RHeap::EAllocCellSize >= shrinkThres)
{
// When KHeapShrinkRatio small enough heap will have been compressed
test(h->Top() == orig_top);
if (pass)
{
test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
test((TUint8*)h->FreeRef().next->next == NULL);
}
else
test((TUint8*)h->FreeRef().next == NULL);
}
else
{
test(h->Top() - orig_top == g);
if (pass)
{
test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
test((TUint8*)h->FreeRef().next->next == orig_top);
}
else
test((TUint8*)h->FreeRef().next == orig_top);
}
// this compress will only do anything if the KHeapShrinkRatio is large
// enough to introduce hysteresis otherwise the heap would have been compressed
// by the free operation itself
TInt tmp1,tmp2;
tmp2=h->CalcComp(g);
tmp1=h->Compress();
test(tmp1 == tmp2);
test(h->Top() == orig_top);
test(c.Size() == orig_size);
h->FullCheck();
// shouldn't compress heap as already compressed
test(h->Compress() == 0);
//grow heap by iGrowBy bytes
test(h->TestAlloc(l2) == p2);
//grow heap by iGrowBy bytes
TUint8* p3 = (TUint8*)h->TestAlloc(l2);
test(p3 == p2 + g);
test(h->Top() - orig_top == 2*g);
test(c.Size() - orig_size == 2*g);
// may or may not reduce heap
h->TestFree(p2);
// may or may not reduce heap
h->TestFree(p3);
h->ForceCompress(2*g);
test(h->Top() == orig_top);
test(c.Size() == orig_size);
h->FullCheck();
if (pass)
{
test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
test((TUint8*)h->FreeRef().next->next == NULL);
}
else
test((TUint8*)h->FreeRef().next == NULL);
//grow heap by iGrowBy bytes
test(h->TestAlloc(l2) == p2);
//grow heap by iGrowBy*2 + page size bytes
test(h->TestAlloc(l2 + g + page_size) == p3);
test(h->Top() - orig_top == 4*g);
test(c.Size() - orig_size == 4*g);
// will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatioDflt
test(h->TestReAlloc(p3, page_size - RHeap::EAllocCellSize, 0) == p3);
h->ForceCompress(g+page_size);
test(h->Top() - orig_top == g + page_size);
test(c.Size() - orig_size == g + page_size);
h->FullCheck();
// will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatio1
h->TestFree(p2);
// will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatio1 && g<=page_size
// or KHeapShrinkHysRatio >= 2.0 and g==page_size
h->TestFree(p3);
// may or may not perform further compression
tmp1=h->CalcComp(g+page_size);
tmp2=h->Compress();
test(tmp1 == tmp2);
test(h->Top() == orig_top);
test(c.Size() == orig_size);
h->FullCheck();
test(h->TestAlloc(l2 - minc) == p2);
test(h->TestAlloc(l2 + g + page_size + minc) == p3 - minc);
test(h->Top() - orig_top == 4*g);
test(c.Size() - orig_size == 4*g);
h->TestFree(p3 - minc);
h->ForceCompress(l2 + g + page_size + minc);
test(h->Top() - orig_top == g);
test(c.Size() - orig_size == g);
h->FullCheck();
if (pass)
{
test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
test((TUint8*)h->FreeRef().next->next == p3 - minc - RHeap::EAllocCellSize);
}
else
test((TUint8*)h->FreeRef().next == p3 - minc - RHeap::EAllocCellSize);
h->TestFree(p2);
if (l2+RHeap::EAllocCellSize >= shrinkThres)
{
// When KHeapShrinkRatio small enough heap will have been compressed
test(h->Top() == orig_top);
test(c.Size() - orig_size == 0);
}
else
{
test(h->Top() - orig_top == g);
test(c.Size() - orig_size == g);
}
h->FullCheck();
if ( ((TLinAddr)orig_top & (align-1)) == 0)
{
TAny* free;
TEST_ALIGN(p2 - RHeap::EAllocCellSize, page_size);
// will have free space of g-minc
test(h->TestAlloc(l2 + minc) == p2);
test(h->Top() - orig_top == 2*g);
test(c.Size() - orig_size == 2*g);
free = pass ? h->FreeRef().next->next : h->FreeRef().next;
test(free != NULL);
test(h->TestReAlloc(p2, l2 - 4, 0) == p2);
TInt freeSp = g-minc + (l2+minc - (l2-4));
TInt adjust = 0;
if (freeSp >= shrinkThres && freeSp-page_size >= minc)
{
// if page_size is less than growBy (g) then heap will be shrunk
// by less than a whole g.
adjust = g-((page_size<g)?page_size:0);
}
test(h->Top() - orig_top == 2*g - adjust);
test(c.Size() - orig_size == 2*g - adjust);
free = pass ? h->FreeRef().next->next : h->FreeRef().next;
test(free != NULL);
TEST_ALIGN(TLinAddr(free)+4, page_size);
test(h->TestAlloc(l2 + g + page_size + 4) == p3 - 4);
test(h->Top() - orig_top == 4*g - adjust);
test(c.Size() - orig_size == 4*g - adjust);
h->TestFree(p3 - 4);
h->ForceCompress(l2 + g + page_size + 4);
test(h->Top() - orig_top == g + page_size);
test(c.Size() - orig_size == g + page_size);
h->FullCheck();
h->TestFree(p2);
h->ForceCompress(l2-4);
test(h->Compress() == 0);
// check heap is grown, will have free space of g-minc
test(h->TestAlloc(l2 + minc) == p2);
test(h->Top() - orig_top == 2*g);
test(c.Size() - orig_size == 2*g);
free = pass ? h->FreeRef().next->next : h->FreeRef().next;
test(free != NULL);
// may shrink heap as will now have g+minc free bytes
test(h->TestReAlloc(p2, l2 - minc, 0) == p2);
if (g+minc >= shrinkThres)
{
test(h->Top() - orig_top == g);
test(c.Size() - orig_size == g);
}
else
{
test(h->Top() - orig_top == 2*g);
test(c.Size() - orig_size == 2*g);
}
free = pass ? h->FreeRef().next->next : h->FreeRef().next;
test(free != NULL);
TEST_ALIGN(TLinAddr(free)+minc, page_size);
test(h->TestAlloc(l2 + g + page_size + minc) == p3 - minc);
test(h->Top() - orig_top == 4*g);
test(c.Size() - orig_size == 4*g);
h->TestFree(p3 - minc);
h->ForceCompress(l2 + g + page_size + minc);
test(h->Top() - orig_top == g);
test(c.Size() - orig_size == g);
h->FullCheck();
h->TestFree(p2);
}
h->TestFree(p1);
if (pass == 0)
h->TestFree(p0);
h->Compress();
}
h->FullCheck();
}
void Test1()
{
RHeap* h;
h = RTestHeap::FixedHeap(0x1000, 0);
test(h != NULL);
DoTest1(h);
h->Close();
h = RTestHeap::FixedHeap(0x1000, 0, EFalse);
test(h != NULL);
DoTest1(h);
h->Close();
h = RTestHeap::FixedHeap(0x10000, 64);
test(h != NULL);
DoTest1(h);
h->Close();
h = RTestHeap::FixedHeap(0x100000, 4096);
test(h != NULL);
DoTest1(h);
h->Close();
h = RTestHeap::FixedHeap(0x100000, 8192);
test(h != NULL);
DoTest1(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x1000, 0x1000, 4);
test(h != NULL);
DoTest1(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x10000, 0x1000, 4);
test(h != NULL);
DoTest1(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4096);
test(h != NULL);
DoTest1(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4);
test(h != NULL);
DoTest1(h);
h->Reset();
DoTest2(h);
h->Reset();
DoTest3(h);
h->Reset();
DoTest4(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 8);
test(h != NULL);
DoTest1(h);
h->Reset();
DoTest2(h);
h->Reset();
DoTest3(h);
h->Reset();
DoTest4(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 16);
test(h != NULL);
DoTest1(h);
h->Reset();
DoTest2(h);
h->Reset();
DoTest3(h);
h->Reset();
DoTest4(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 32);
test(h != NULL);
DoTest1(h);
h->Reset();
DoTest2(h);
h->Reset();
DoTest3(h);
h->Reset();
DoTest4(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x3000, 0x100000, 0x3000, 4);
test(h != NULL);
DoTest1(h);
h->Reset();
DoTest2(h);
h->Reset();
DoTest3(h);
h->Reset();
DoTest4(h);
h->Close();
}
struct SHeapStress
{
RThread iThread;
volatile TBool iStop;
TInt iAllocs;
TInt iFailedAllocs;
TInt iFrees;
TInt iReAllocs;
TInt iFailedReAllocs;
TInt iChecks;
TUint32 iSeed;
RAllocator* iAllocator;
TUint32 Random();
};
TUint32 SHeapStress::Random()
{
iSeed *= 69069;
iSeed += 41;
return iSeed;
}
TInt RandomLength(TUint32 aRandom)
{
TUint8 x = (TUint8)aRandom;
if (x & 0x80)
return (x & 0x7f) << 7;
return x & 0x7f;
}
TInt HeapStress(TAny* aPtr)
{
SHeapStress& hs = *(SHeapStress*)aPtr;
RTestHeap* h = (RTestHeap*)&User::Allocator();
TUint8* cell[256];
TInt len[256];
Mem::FillZ(cell, sizeof(cell));
Mem::FillZ(len, sizeof(len));
RThread::Rendezvous(KErrNone);
while (!hs.iStop)
{
// allocate all cells
TInt i;
for (i=0; i<256; ++i)
{
if (!cell[i])
{
++hs.iAllocs;
cell[i] = (TUint8*)h->TestAlloc(RandomLength(hs.Random()));
if (cell[i])
len[i] = h->AllocLen(cell[i]);
else
++hs.iFailedAllocs;
}
}
// free some cells
TInt n = 64 + (hs.Random() & 127);
while (--n)
{
i = hs.Random() & 0xff;
if (cell[i])
{
test(h->AllocLen(cell[i]) == len[i]);
h->TestFree(cell[i]);
cell[i] = NULL;
len[i] = 0;
++hs.iFrees;
}
}
// realloc some cells
n = 64 + (hs.Random() & 127);
while (--n)
{
TUint32 rn = hs.Random();
i = (rn >> 8) & 0xff;
TInt new_len = RandomLength(rn);
if (cell[i])
{
test(h->AllocLen(cell[i]) == len[i]);
++hs.iReAllocs;
TUint8* p = (TUint8*)h->TestReAlloc(cell[i], new_len, rn >> 16);
if (p)
{
cell[i] = p;
len[i] = h->AllocLen(p);
}
else
++hs.iFailedReAllocs;
}
}
// check the heap
h->Check();
++hs.iChecks;
}
return 0;
}
void CreateStressThread(SHeapStress& aInfo)
{
Mem::FillZ(&aInfo, _FOFF(SHeapStress, iSeed));
RThread& t = aInfo.iThread;
TInt r = t.Create(KNullDesC(), &HeapStress, 0x2000, aInfo.iAllocator, &aInfo);
test(r==KErrNone);
t.SetPriority(EPriorityLess);
TRequestStatus s;
t.Rendezvous(s);
test(s == KRequestPending);
t.Resume();
User::WaitForRequest(s);
test(s == KErrNone);
test(t.ExitType() == EExitPending);
t.SetPriority(EPriorityMuchLess);
}
void StopStressThread(SHeapStress& aInfo)
{
RThread& t = aInfo.iThread;
TRequestStatus s;
t.Logon(s);
aInfo.iStop = ETrue;
User::WaitForRequest(s);
const TDesC& exitCat = t.ExitCategory();
TInt exitReason = t.ExitReason();
TInt exitType = t.ExitType();
test.Printf(_L("Exit type %d,%d,%S\n"), exitType, exitReason, &exitCat);
test(exitType == EExitKill);
test(exitReason == KErrNone);
test(s == KErrNone);
test.Printf(_L("Total Allocs : %d\n"), aInfo.iAllocs);
test.Printf(_L("Failed Allocs : %d\n"), aInfo.iFailedAllocs);
test.Printf(_L("Total Frees : %d\n"), aInfo.iFrees);
test.Printf(_L("Total ReAllocs : %d\n"), aInfo.iReAllocs);
test.Printf(_L("Failed ReAllocs : %d\n"), aInfo.iFailedReAllocs);
test.Printf(_L("Heap checks : %d\n"), aInfo.iChecks);
}
void DoStressTest1(RAllocator* aAllocator)
{
RTestHeap* h = (RTestHeap*)aAllocator;
test.Printf(_L("Test Stress 1: min=%x max=%x align=%d growby=%d\n"),
h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
SHeapStress hs;
hs.iSeed = 0xb504f334;
hs.iAllocator = aAllocator;
CreateStressThread(hs);
User::After(10*1000000);
StopStressThread(hs);
CLOSE_AND_WAIT(hs.iThread);
h->FullCheck();
}
void DoStressTest2(RAllocator* aAllocator)
{
RTestHeap* h = (RTestHeap*)aAllocator;
test.Printf(_L("Test Stress 2: min=%x max=%x align=%d growby=%d\n"),
h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
SHeapStress hs1;
SHeapStress hs2;
hs1.iSeed = 0xb504f334;
hs1.iAllocator = aAllocator;
hs2.iSeed = 0xddb3d743;
hs2.iAllocator = aAllocator;
CreateStressThread(hs1);
CreateStressThread(hs2);
User::After(20*1000000);
StopStressThread(hs1);
StopStressThread(hs2);
CLOSE_AND_WAIT(hs1.iThread);
CLOSE_AND_WAIT(hs2.iThread);
h->FullCheck();
}
void StressTests()
{
RHeap* h;
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4);
test(h != NULL);
DoStressTest1(h);
h->Reset();
DoStressTest2(h);
h->Close();
h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 8);
test(h != NULL);
DoStressTest1(h);
h->Reset();
DoStressTest2(h);
h->Close();
}
TInt TestHeapGrowInPlace(TInt aMode)
{
TBool reAllocs=EFalse;
TBool heapGrew=EFalse;
RHeap* myHeap;
myHeap = UserHeap::ChunkHeap(NULL,0x1000,0x4000,0x1000);
TAny *testBuffer,*testBuffer2;
// Start size chosen so that 1st realloc will use up exactly all the heap.
// Later iterations wont, and there will be a free cell at the end of the heap.
TInt currentSize = ((0x800) - sizeof(RHeap)) - RHeap::EAllocCellSize;
TInt growBy = 0x800;
TInt newSpace, space;
testBuffer2 = myHeap->Alloc(currentSize);
newSpace = myHeap->Size();
do
{
space = newSpace;
testBuffer = testBuffer2;
currentSize+=growBy;
testBuffer2 = myHeap->ReAlloc(testBuffer,currentSize,aMode);
newSpace = myHeap->Size();
if (testBuffer2)
{
if (testBuffer!=testBuffer2)
reAllocs = ETrue;
if (newSpace>space)
heapGrew = ETrue;
}
growBy-=16;
} while (testBuffer2);
currentSize-=growBy;
myHeap->Free(testBuffer);
myHeap->Close();
// How did we do?
if (reAllocs)
{
test.Printf(_L("Failure - Memory was moved!\n"));
return -100;
}
if (!heapGrew)
{
test.Printf(_L("Failure - Heap Never Grew!\n"));
return -200;
}
if (currentSize<= 0x3000)
{
test.Printf(_L("Failed to grow by a reasonable amount!\n"));
return -300;
}
return KErrNone;
}
void ReAllocTests()
{
test.Next(_L("Testing Grow In Place"));
test(TestHeapGrowInPlace(0)==KErrNone);
test(TestHeapGrowInPlace(RHeap::ENeverMove)==KErrNone);
}
RHeap* TestDEF078391Heap = 0;
TInt TestDEF078391ThreadFunction(TAny*)
{
TestDEF078391Heap = UserHeap::ChunkHeap(NULL,0x1000,0x100000,KMinHeapGrowBy,0,EFalse);
return TestDEF078391Heap ? KErrNone : KErrGeneral;
}
void TestDEF078391()
{
// Test that creating a multithreaded heap with UserHeap::ChunkHeap
// doesn't create any reference counts on the creating thread.
// This is done by creating a heap in a named thread, then exiting
// the thread and re-creating it with the same name.
// This will fail with KErrAlreadyExists if the orinal thread has
// not died because of an unclosed reference count.
test.Next(_L("Test that creating a multithreaded heap doesn't open references of creator"));
_LIT(KThreadName,"ThreadName");
RThread t;
TInt r=t.Create(KThreadName,TestDEF078391ThreadFunction,0x1000,0x1000,0x100000,NULL);
test(r==KErrNone);
TRequestStatus status;
t.Logon(status);
t.Resume();
User::WaitForRequest(status);
test(status==KErrNone);
test(t.ExitType()==EExitKill);
test(t.ExitReason()==KErrNone);
CLOSE_AND_WAIT(t);
test(TestDEF078391Heap!=0);
User::After(1000000); // give more opportunity for thread cleanup to happen
// create thread a second time
r=t.Create(KThreadName,TestDEF078391ThreadFunction,0x1000,0x1000,0x100000,NULL);
test(r==KErrNone);
t.Kill(0);
CLOSE_AND_WAIT(t);
// close the heap that got created earlier
TestDEF078391Heap->Close();
}
TInt E32Main()
{
test.Title();
__KHEAP_MARK;
test.Start(_L("Testing heaps"));
TestDEF078391();
Test1();
StressTests();
ReAllocTests();
test.End();
__KHEAP_MARKEND;
return 0;
}