os/kernelhwsrv/kerneltest/e32test/heap/t_heap.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32test\heap\t_heap.cpp
sl@0
    15
// Overview:
sl@0
    16
// Tests RHeap class.
sl@0
    17
// API Information:
sl@0
    18
// RHeap
sl@0
    19
// Details:
sl@0
    20
// - Test that the expected methods are in the DLL by calling each one.
sl@0
    21
// - Test heap auto expansion and compression by calling Alloc and Compress
sl@0
    22
// and verifying the results are as expected.
sl@0
    23
// - Verify the heap dump Base, Size, MinLength, Top and len values.
sl@0
    24
// - Test the RHeap AllocSize, Alloc, AllocLen, Count and Free methods. Verify
sl@0
    25
// results are as expected. Check heap object and confirm Invariant status.
sl@0
    26
// - For an RHeap object, test and verify the results of: allocate some cells, 
sl@0
    27
// free them with Reset, allocate some cells again, free them with Free, 
sl@0
    28
// allocate some cells again, free them backwards, allocate again, free the 
sl@0
    29
// odd cells then the even cells, allocate again, free one half then the other.
sl@0
    30
// Check heap object and confirm Invariant status.
sl@0
    31
// - For an RHeap object, test and verify the results of: attempt to resize a
sl@0
    32
// block above the space available, resize the block to 0, resize positively, 
sl@0
    33
// allocate a block, fill with data, allocate another block or two then resize
sl@0
    34
// the original block such that it has to be moved in memory, then check the 
sl@0
    35
// blocks' contents, test data was copied on reallocation, resize blocks and
sl@0
    36
// verify data integrity, expand and shrink, verify data.
sl@0
    37
// Check heap object and confirm Invariant status.
sl@0
    38
// - For an RHeap object, test and verify the results of: Alloc some cells,
sl@0
    39
// verify the Count, Check the object, Free some cells, verify the Count, 
sl@0
    40
// Check and Reset the object, corrupt the heap data and reset the object.
sl@0
    41
// - Test the leaving methods: AllocL and ReAllocL. Verify the results are as
sl@0
    42
// expected.
sl@0
    43
// - Test the RHeap methods: Alloc, Count, Size, Free and Close. Verify results
sl@0
    44
// are as expected.
sl@0
    45
// - Test sharing a chunk heap between two separate threads.  Each thread
sl@0
    46
// accesses the shared heap in a timed loop, to ensure that some true
sl@0
    47
// concurrency.
sl@0
    48
// - Test sharing a chunk heap between two separate threads. Run each thread in
sl@0
    49
// a timed loop, to ensure that some true concurrency. Each thread accesses
sl@0
    50
// the shared heap and results are verified.  The heap size is used to verify
sl@0
    51
// no leaks and that the largest available space is still available. The heap
sl@0
    52
// is checked to verify that no cells remain allocated after the tests are
sl@0
    53
// complete.
sl@0
    54
// - Test sharing a heap between two threads.  The thread whose heap it was is
sl@0
    55
// killed first.  Each thread accesses the shared heap and results are
sl@0
    56
// verified.
sl@0
    57
// Platforms/Drives/Compatibility:
sl@0
    58
// All
sl@0
    59
// Assumptions/Requirement/Pre-requisites:
sl@0
    60
// Failures and causes:
sl@0
    61
// Base Port information:
sl@0
    62
// 
sl@0
    63
//
sl@0
    64
sl@0
    65
#include <e32test.h>
sl@0
    66
#include <e32hal.h>
sl@0
    67
#include <e32def.h>
sl@0
    68
#include <e32def_private.h>
sl@0
    69
sl@0
    70
// Sets data for Test6
sl@0
    71
#define SetData(size)	pHeap->Reset();\
sl@0
    72
						Cell1=pHeap->Alloc(size);\
sl@0
    73
						Cell2=pHeap->Alloc(size);\
sl@0
    74
						Cell3=pHeap->Alloc(size);\
sl@0
    75
						for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+pHeap->AllocLen(Cell1); *pC++='x');\
sl@0
    76
						for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+pHeap->AllocLen(Cell2); *pC++='y');\
sl@0
    77
						for(pC=(TText8*)Cell3; pC<(TText8*)Cell3+pHeap->AllocLen(Cell3); *pC++='z');\
sl@0
    78
						OrigLen=pHeap->AllocLen(Cell2);			
sl@0
    79
sl@0
    80
// Tests cell contents for Test6
sl@0
    81
#define TestCells(Cell2Len)	for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+pHeap->AllocLen(Cell1); test(*pC++=='x'));\
sl@0
    82
							for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+Cell2Len; test(*pC++=='y'));\
sl@0
    83
							for(pC=(TText8*)Cell3; pC<(TText8*)Cell3+pHeap->AllocLen(Cell3); test(*pC++=='z'));\
sl@0
    84
							pHeap->Check();
sl@0
    85
sl@0
    86
#ifdef __EABI__
sl@0
    87
	IMPORT_D extern const TInt KHeapMinCellSize;
sl@0
    88
#else
sl@0
    89
    const TInt KHeapMinCellSize = 0;
sl@0
    90
#endif
sl@0
    91
sl@0
    92
const TInt KHeadSize = (TInt)RHeap::EAllocCellSize;
sl@0
    93
const TInt KAlign = _FOFF(RHeap::_s_align, d);
sl@0
    94
const TInt KMinCellLength = _ALIGN_UP((KHeapMinCellSize + Max(TInt(RHeap::EFreeCellSize),TInt(RHeap::EAllocCellSize))),KAlign) - RHeap::EAllocCellSize;
sl@0
    95
const TInt KMinFreeSize = _ALIGN_UP((KHeapMinCellSize + Max(TInt(RHeap::EFreeCellSize),TInt(RHeap::EAllocCellSize))),KAlign);
sl@0
    96
sl@0
    97
TInt PageSize;
sl@0
    98
sl@0
    99
class RTestHeap : public RHeap
sl@0
   100
	{
sl@0
   101
public:
sl@0
   102
	void __DbgTest(void* pRHeapDump) const;
sl@0
   103
	};
sl@0
   104
sl@0
   105
struct RHeapDump
sl@0
   106
	{
sl@0
   107
	TUint				iMinLength;
sl@0
   108
	RChunk				iChunk;
sl@0
   109
	TUint8				*iBase;
sl@0
   110
	TUint8				*iTop;
sl@0
   111
	RHeap::SCell		iFree;
sl@0
   112
	};
sl@0
   113
sl@0
   114
#pragma warning ( disable :4705 ) // statement has no effect
sl@0
   115
RHeapDump OrigDump;
sl@0
   116
#pragma warning ( default :4705 )
sl@0
   117
sl@0
   118
#if defined(_DEBUG)
sl@0
   119
void RTestHeap::__DbgTest(void* aPtr) const
sl@0
   120
	{
sl@0
   121
	RHeapDump& d = *(RHeapDump*)aPtr;
sl@0
   122
	d.iMinLength=iMinLength;
sl@0
   123
	d.iChunk.SetHandle(iChunkHandle);
sl@0
   124
	d.iBase=iBase;
sl@0
   125
	d.iTop=iTop;
sl@0
   126
	d.iFree=iFree;
sl@0
   127
	}
sl@0
   128
#endif
sl@0
   129
sl@0
   130
sl@0
   131
#if defined(_DEBUG)
sl@0
   132
TBool Invariant(RHeap* aHeap)
sl@0
   133
	{
sl@0
   134
	RHeapDump dump;
sl@0
   135
	((RTestHeap*)aHeap)->__DbgTest(&dump);
sl@0
   136
	if(dump.iMinLength!=OrigDump.iMinLength) 		return(EFalse);
sl@0
   137
	// Note: iChunk is a class
sl@0
   138
	if(dump.iBase!=OrigDump.iBase)			return(EFalse);
sl@0
   139
	if(*dump.iBase!=*OrigDump.iBase)		return(EFalse);
sl@0
   140
	if(dump.iTop!=OrigDump.iTop)			return(EFalse);
sl@0
   141
	if(dump.iTop[-1]!=OrigDump.iTop[-1])	return(EFalse);	
sl@0
   142
	if(dump.iFree.len!=OrigDump.iFree.len)	return(EFalse);
sl@0
   143
	// iFree.Next changes during allocation/freeing etc.
sl@0
   144
	return(ETrue);
sl@0
   145
	}
sl@0
   146
#define INV(x) x;
sl@0
   147
#else
sl@0
   148
#define INV(x)
sl@0
   149
#endif
sl@0
   150
sl@0
   151
LOCAL_D RTest test(_L("T_HEAP"));
sl@0
   152
LOCAL_D TInt heapCount=1;
sl@0
   153
LOCAL_D RHeap *gHeapPtr;
sl@0
   154
LOCAL_D RHeap *gHeapPtr2;
sl@0
   155
sl@0
   156
class TestRHeap
sl@0
   157
	{
sl@0
   158
public:
sl@0
   159
	void Test1(void);
sl@0
   160
	void Test2(void);
sl@0
   161
	void Test3(void);
sl@0
   162
	void Test4(void);
sl@0
   163
	void Test5(void);
sl@0
   164
	void Test7(void);
sl@0
   165
	void Test8(void);
sl@0
   166
	void TestCompressAll(void);
sl@0
   167
	void TestOffset(void);
sl@0
   168
private:
sl@0
   169
	TInt RHeapCalcReduce(TInt aCellSize, TInt aGrowBy);
sl@0
   170
	};
sl@0
   171
sl@0
   172
LOCAL_C RHeap* allocHeap(TInt aSize)
sl@0
   173
//
sl@0
   174
// Allocate a chunk heap with max size aSize
sl@0
   175
//
sl@0
   176
	{
sl@0
   177
sl@0
   178
	TName n;
sl@0
   179
	n.Format(_L("TESTHEAP%d"),heapCount++);
sl@0
   180
	return(User::ChunkHeap(&n,aSize,aSize));
sl@0
   181
	}
sl@0
   182
sl@0
   183
////////////////////////////////////////////////////////////////////////////////////////
sl@0
   184
// Test that methods are in the DLL
sl@0
   185
////////////////////////////////////////////////////////////////////////////////////////
sl@0
   186
void TestRHeap::Test1(void)
sl@0
   187
	{ 
sl@0
   188
	TAny* aCell;
sl@0
   189
	TInt aVar;
sl@0
   190
	RHeap* pHeap=allocHeap(3000); // tests first constructor indirectly 
sl@0
   191
	// constructor with Chunk not tested
sl@0
   192
	pHeap->Base();
sl@0
   193
	pHeap->Size();
sl@0
   194
	pHeap->Available(aVar);
sl@0
   195
	pHeap->Check();
sl@0
   196
	pHeap->Count();												 	
sl@0
   197
	pHeap->Count(aVar);
sl@0
   198
	aCell=pHeap->Alloc(50);
sl@0
   199
	pHeap->Free(aCell);
sl@0
   200
	aCell=pHeap->AllocL(50);
sl@0
   201
	pHeap->AllocLen(aCell);
sl@0
   202
	pHeap->ReAlloc(aCell, 100);
sl@0
   203
	pHeap->ReAllocL(aCell, 150);
sl@0
   204
	pHeap->Reset();
sl@0
   205
	pHeap->Close();
sl@0
   206
	}
sl@0
   207
sl@0
   208
///////////////////////////////////////////////////////////////////////////////
sl@0
   209
// Test Assorted Methods 1
sl@0
   210
//////////////////////////////////////////////////////////////////////////////
sl@0
   211
void TestRHeap::Test2(void)
sl@0
   212
	{
sl@0
   213
#if defined(_DEBUG)
sl@0
   214
	RHeapDump dump;
sl@0
   215
	RHeap* pHeap=allocHeap(3000);
sl@0
   216
sl@0
   217
	((RTestHeap*)pHeap)->__DbgTest(&OrigDump);
sl@0
   218
	((RTestHeap*)pHeap)->__DbgTest(&dump);
sl@0
   219
	test(dump.iBase==pHeap->Base());
sl@0
   220
	test((dump.iTop-dump.iBase)==pHeap->Size());
sl@0
   221
	pHeap->Check();
sl@0
   222
	test(Invariant(pHeap));
sl@0
   223
	pHeap->Close();
sl@0
   224
#endif
sl@0
   225
	}
sl@0
   226
sl@0
   227
///////////////////////////////////////////////////////////////////////////////
sl@0
   228
// Test Assorted Methods 2
sl@0
   229
//////////////////////////////////////////////////////////////////////////////		 
sl@0
   230
void TestRHeap::Test3(void)
sl@0
   231
	{  
sl@0
   232
	TInt CellLen;
sl@0
   233
	TInt OrigBiggestBlock, BiggestBlock;
sl@0
   234
	TAny* aCell;
sl@0
   235
	TInt FreeCount, AllocCount, AllocSize;
sl@0
   236
	RHeap* pHeap=allocHeap(5000);
sl@0
   237
sl@0
   238
#if defined(_DEBUG)
sl@0
   239
	((RTestHeap*)pHeap)->__DbgTest(&OrigDump);
sl@0
   240
#endif
sl@0
   241
sl@0
   242
	// test AllocSize
sl@0
   243
	AllocCount=pHeap->Count(FreeCount);
sl@0
   244
	test(pHeap->AllocSize(AllocSize)==pHeap->Count());
sl@0
   245
	test(AllocSize==0);
sl@0
   246
	test(AllocCount==pHeap->Count());
sl@0
   247
	test(AllocCount==0);
sl@0
   248
	test(FreeCount==1);
sl@0
   249
sl@0
   250
	TAny* p1=pHeap->Alloc(1);
sl@0
   251
	test(pHeap->AllocSize(AllocSize)==1);
sl@0
   252
	test(AllocSize==pHeap->AllocLen(p1));
sl@0
   253
	 
sl@0
   254
	TAny* p2=pHeap->Alloc(8);
sl@0
   255
	test(pHeap->AllocSize(AllocSize)==2);
sl@0
   256
	test(AllocSize==pHeap->AllocLen(p1)+pHeap->AllocLen(p2));
sl@0
   257
sl@0
   258
	TAny* p3=pHeap->Alloc(127);
sl@0
   259
	test(pHeap->AllocSize(AllocSize)==3);
sl@0
   260
	test(AllocSize==pHeap->AllocLen(p1)+pHeap->AllocLen(p2)+pHeap->AllocLen(p3));
sl@0
   261
sl@0
   262
	pHeap->Free(p2);
sl@0
   263
	test(pHeap->AllocSize(AllocSize)==2);
sl@0
   264
	test(AllocSize==pHeap->AllocLen(p1)+pHeap->AllocLen(p3));
sl@0
   265
sl@0
   266
	pHeap->Free(p1);
sl@0
   267
	test(pHeap->AllocSize(AllocSize)==1);
sl@0
   268
	test(AllocSize==pHeap->AllocLen(p3));
sl@0
   269
sl@0
   270
	pHeap->Free(p3);
sl@0
   271
	test(pHeap->AllocSize(AllocSize)==0);
sl@0
   272
	test(AllocSize==0);
sl@0
   273
sl@0
   274
	pHeap->Available(OrigBiggestBlock);
sl@0
   275
sl@0
   276
	// Request too large a block 
sl@0
   277
	test((aCell=pHeap->Alloc(OrigBiggestBlock+1))==NULL);
sl@0
   278
	AllocCount=pHeap->Count(FreeCount);
sl@0
   279
	test(AllocCount==0);
sl@0
   280
	test(FreeCount==1);
sl@0
   281
sl@0
   282
sl@0
   283
	// Request block same size as that available
sl@0
   284
	test((aCell=pHeap->Alloc(OrigBiggestBlock))!=NULL);
sl@0
   285
	test(pHeap->Available(BiggestBlock)==0);  
sl@0
   286
	test(BiggestBlock==0);
sl@0
   287
	test(pHeap->AllocLen(aCell)==OrigBiggestBlock);
sl@0
   288
	AllocCount=pHeap->Count(FreeCount);
sl@0
   289
	test(AllocCount==pHeap->Count());
sl@0
   290
	test(AllocCount==1);
sl@0
   291
	test(FreeCount==0);
sl@0
   292
	pHeap->Check();
sl@0
   293
	// Free the block
sl@0
   294
	pHeap->FreeZ(aCell);
sl@0
   295
	test(aCell==NULL);
sl@0
   296
	pHeap->Available(BiggestBlock);
sl@0
   297
	test(BiggestBlock==OrigBiggestBlock);
sl@0
   298
	AllocCount=pHeap->Count(FreeCount);
sl@0
   299
	test(AllocCount==0);
sl@0
   300
	test(FreeCount==1);
sl@0
   301
sl@0
   302
sl@0
   303
	// Request a block much smaller than that available
sl@0
   304
	test((aCell=pHeap->Alloc(1))!=NULL);
sl@0
   305
	CellLen=pHeap->AllocLen(aCell);
sl@0
   306
	pHeap->Available(BiggestBlock);
sl@0
   307
	test(pHeap->Available(BiggestBlock)==BiggestBlock);
sl@0
   308
	test((BiggestBlock+CellLen+KHeadSize)==OrigBiggestBlock);
sl@0
   309
	// NOTE: if a block of 1000 was initially available, getting a cell of length 100 DOES NOT
sl@0
   310
	// leave 900 available as some of the 1000(KHeadSize) is used up storing the length of the
sl@0
   311
	// allocated block
sl@0
   312
	AllocCount=pHeap->Count(FreeCount);
sl@0
   313
	test(AllocCount==1);
sl@0
   314
	test(FreeCount==1);
sl@0
   315
	pHeap->Check();
sl@0
   316
	// Free the block
sl@0
   317
	pHeap->Free(aCell);
sl@0
   318
	test(aCell!=NULL);
sl@0
   319
	pHeap->Available(BiggestBlock);
sl@0
   320
	test(BiggestBlock==OrigBiggestBlock);
sl@0
   321
	AllocCount=pHeap->Count(FreeCount);
sl@0
   322
	test(AllocCount==0);
sl@0
   323
	test(FreeCount==1);
sl@0
   324
sl@0
   325
sl@0
   326
	// Request a block only just smaller than that available
sl@0
   327
	test((aCell=pHeap->Alloc(OrigBiggestBlock-1))!=NULL);
sl@0
   328
	CellLen=pHeap->AllocLen(aCell);
sl@0
   329
	AllocCount=pHeap->Count(FreeCount);
sl@0
   330
	test(AllocCount==1);
sl@0
   331
	test(FreeCount==0);
sl@0
   332
	pHeap->Check();
sl@0
   333
	// Free the block
sl@0
   334
	pHeap->Free(aCell);
sl@0
   335
	pHeap->Available(BiggestBlock);
sl@0
   336
	test(BiggestBlock==OrigBiggestBlock);
sl@0
   337
	AllocCount=pHeap->Count(FreeCount);
sl@0
   338
	test(AllocCount==0);
sl@0
   339
	test(FreeCount==1);
sl@0
   340
sl@0
   341
sl@0
   342
	//Request a block of 0 size	   Note: 0 may not necessarily be allocated (probably will be 4)
sl@0
   343
	test((aCell=pHeap->Alloc(0))!=NULL);
sl@0
   344
	pHeap->Available(BiggestBlock);
sl@0
   345
	AllocCount=pHeap->Count(FreeCount);
sl@0
   346
	test(AllocCount==1);
sl@0
   347
	test(FreeCount==1);
sl@0
   348
	pHeap->Check();
sl@0
   349
	//Free the block
sl@0
   350
	pHeap->Free(aCell);
sl@0
   351
	pHeap->Available(BiggestBlock);
sl@0
   352
	test(BiggestBlock==OrigBiggestBlock);	 
sl@0
   353
	AllocCount=pHeap->Count(FreeCount);
sl@0
   354
	test(AllocCount==0);
sl@0
   355
	test(FreeCount==1);
sl@0
   356
	pHeap->Check();
sl@0
   357
	INV(test(Invariant(pHeap)));
sl@0
   358
sl@0
   359
	// close heap so we don't exceed chunk limit
sl@0
   360
	pHeap->Close();
sl@0
   361
	}
sl@0
   362
sl@0
   363
///////////////////////////////////////////////////////////////////////////////
sl@0
   364
// Test Assorted Methods 3 - Here we go loopy loo, here we go loopy li
sl@0
   365
//////////////////////////////////////////////////////////////////////////////				  
sl@0
   366
void TestRHeap::Test4(void)
sl@0
   367
	{ 
sl@0
   368
	TInt OrigBiggestBlock, BiggestBlock, FreeCount, AllocCount;
sl@0
   369
	RHeap* pHeap=allocHeap(5000);
sl@0
   370
sl@0
   371
	pHeap->Available(OrigBiggestBlock);
sl@0
   372
#if defined(_DEBUG)
sl@0
   373
	((RTestHeap*)pHeap)->__DbgTest(&OrigDump);
sl@0
   374
#endif
sl@0
   375
	
sl@0
   376
	for(TInt ArraySize=1; ArraySize<=100; ArraySize++)
sl@0
   377
		{	  
sl@0
   378
		TAny** ArrayOfCells;
sl@0
   379
		ArrayOfCells= new TAny*[ArraySize];
sl@0
   380
		TInt ArrayIndex;
sl@0
   381
	
sl@0
   382
		// Allocate some cells
sl@0
   383
		for(ArrayIndex=0; ArrayIndex<ArraySize;ArrayIndex++)
sl@0
   384
			ArrayOfCells[ArrayIndex]=pHeap->Alloc(OrigBiggestBlock/(ArraySize*3)); 
sl@0
   385
		pHeap->Available(BiggestBlock);
sl@0
   386
		test(BiggestBlock!=OrigBiggestBlock);
sl@0
   387
		AllocCount=pHeap->Count(FreeCount);
sl@0
   388
		test((TInt)AllocCount==ArraySize);
sl@0
   389
		test(FreeCount==1);
sl@0
   390
		pHeap->Check();
sl@0
   391
		// Now free them with Reset
sl@0
   392
		pHeap->Reset();
sl@0
   393
		pHeap->Available(BiggestBlock);
sl@0
   394
		test(BiggestBlock==OrigBiggestBlock);
sl@0
   395
		AllocCount=pHeap->Count(FreeCount);
sl@0
   396
		test(AllocCount==0);
sl@0
   397
		test(FreeCount==1);
sl@0
   398
	
sl@0
   399
	
sl@0
   400
		// Allocate some cells again	 
sl@0
   401
		for(ArrayIndex=0; ArrayIndex<ArraySize;ArrayIndex++)
sl@0
   402
			ArrayOfCells[ArrayIndex]=pHeap->Alloc(OrigBiggestBlock/(ArraySize*3)); 
sl@0
   403
		pHeap->Available(BiggestBlock);
sl@0
   404
		test(BiggestBlock!=OrigBiggestBlock);
sl@0
   405
		AllocCount=pHeap->Count(FreeCount);
sl@0
   406
		test((TInt)AllocCount==ArraySize);
sl@0
   407
		test(FreeCount==1);
sl@0
   408
		pHeap->Check();
sl@0
   409
		// Free them with Free
sl@0
   410
		for(ArrayIndex=0; ArrayIndex<ArraySize;ArrayIndex++)
sl@0
   411
			pHeap->Free(ArrayOfCells[ArrayIndex]);
sl@0
   412
		pHeap->Available(BiggestBlock);
sl@0
   413
		test(BiggestBlock==OrigBiggestBlock);
sl@0
   414
		AllocCount=pHeap->Count(FreeCount);
sl@0
   415
		test(AllocCount==0);
sl@0
   416
		test(FreeCount==1);
sl@0
   417
	
sl@0
   418
	
sl@0
   419
		// Allocate some cells again	 
sl@0
   420
		for(ArrayIndex=0; ArrayIndex<ArraySize;ArrayIndex++)
sl@0
   421
			ArrayOfCells[ArrayIndex]=pHeap->Alloc(OrigBiggestBlock/(ArraySize*3));
sl@0
   422
		pHeap->Available(BiggestBlock);
sl@0
   423
		test(BiggestBlock!=OrigBiggestBlock); 
sl@0
   424
		AllocCount=pHeap->Count(FreeCount);
sl@0
   425
		test((TInt)AllocCount==ArraySize);
sl@0
   426
		test(FreeCount==1);
sl@0
   427
		pHeap->Check();
sl@0
   428
		// Free them backwards
sl@0
   429
		for(ArrayIndex=ArraySize-1; ArrayIndex>=0; ArrayIndex--)
sl@0
   430
			pHeap->Free(ArrayOfCells[ArrayIndex]);
sl@0
   431
		pHeap->Available(BiggestBlock);
sl@0
   432
		test(BiggestBlock==OrigBiggestBlock);
sl@0
   433
		AllocCount=pHeap->Count(FreeCount);
sl@0
   434
		test(AllocCount==0);
sl@0
   435
		test(FreeCount==1);
sl@0
   436
sl@0
   437
sl@0
   438
		// Allocate some cells again	 
sl@0
   439
		for(ArrayIndex=0; ArrayIndex<ArraySize;ArrayIndex++)
sl@0
   440
			ArrayOfCells[ArrayIndex]=pHeap->Alloc(OrigBiggestBlock/(ArraySize*3));
sl@0
   441
		pHeap->Available(BiggestBlock);
sl@0
   442
		test(BiggestBlock!=OrigBiggestBlock);
sl@0
   443
		AllocCount=pHeap->Count(FreeCount);
sl@0
   444
		test((TInt)AllocCount==ArraySize);
sl@0
   445
		test(FreeCount==1);
sl@0
   446
		pHeap->Check();
sl@0
   447
		// Free the odd cells then the even cells
sl@0
   448
		for(ArrayIndex=0; ArrayIndex<ArraySize; ArrayIndex+=2)
sl@0
   449
			pHeap->Free(ArrayOfCells[ArrayIndex]);
sl@0
   450
		pHeap->Check();
sl@0
   451
		for(ArrayIndex=1; ArrayIndex<ArraySize; ArrayIndex+=2)
sl@0
   452
			pHeap->Free(ArrayOfCells[ArrayIndex]);
sl@0
   453
		pHeap->Check();
sl@0
   454
		pHeap->Available(BiggestBlock);
sl@0
   455
		test(BiggestBlock==OrigBiggestBlock);
sl@0
   456
		AllocCount=pHeap->Count(FreeCount);
sl@0
   457
		test(AllocCount==0);
sl@0
   458
		test(FreeCount==1);
sl@0
   459
	
sl@0
   460
	
sl@0
   461
		// Allocate some cells again	 
sl@0
   462
		for(ArrayIndex=0; ArrayIndex<ArraySize;ArrayIndex++)
sl@0
   463
			ArrayOfCells[ArrayIndex]=pHeap->Alloc(OrigBiggestBlock/(ArraySize*3));
sl@0
   464
		pHeap->Available(BiggestBlock);
sl@0
   465
		test(BiggestBlock!=OrigBiggestBlock);
sl@0
   466
		AllocCount=pHeap->Count(FreeCount);
sl@0
   467
		test((TInt)AllocCount==ArraySize);
sl@0
   468
		test(FreeCount==1);
sl@0
   469
		pHeap->Check();
sl@0
   470
		// Free one half then the other
sl@0
   471
		for(ArrayIndex=ArraySize-1; ArrayIndex>=ArraySize/2; ArrayIndex--)
sl@0
   472
			pHeap->Free(ArrayOfCells[ArrayIndex]);
sl@0
   473
		for(ArrayIndex=0; ArrayIndex<ArraySize/2; ArrayIndex++)
sl@0
   474
			pHeap->Free(ArrayOfCells[ArrayIndex]);
sl@0
   475
		AllocCount=pHeap->Count(FreeCount);
sl@0
   476
		test(AllocCount==0);
sl@0
   477
		test(FreeCount==1);
sl@0
   478
	
sl@0
   479
		delete [] ArrayOfCells;
sl@0
   480
		pHeap->Check();
sl@0
   481
		INV(test(Invariant(pHeap)))
sl@0
   482
		}
sl@0
   483
sl@0
   484
	// close heap so we don't exceed chunk limit
sl@0
   485
	pHeap->Close();
sl@0
   486
	}
sl@0
   487
sl@0
   488
	
sl@0
   489
///////////////////////////////////////////////////////////////////////////////
sl@0
   490
// Test ReAlloc
sl@0
   491
//////////////////////////////////////////////////////////////////////////////
sl@0
   492
void TestRHeap::Test5(void)
sl@0
   493
	{
sl@0
   494
	TInt BiggestBlock, CellSize;
sl@0
   495
sl@0
   496
	RHeap* pHeap=allocHeap(5000);
sl@0
   497
#if defined(_DEBUG)
sl@0
   498
	((RTestHeap*)pHeap)->__DbgTest(&OrigDump);
sl@0
   499
#endif
sl@0
   500
	pHeap->Available(BiggestBlock);
sl@0
   501
	TAny* aCell=pHeap->Alloc(BiggestBlock);
sl@0
   502
sl@0
   503
	// Attempt to resize the block above the space available
sl@0
   504
	test(pHeap->ReAlloc(aCell, BiggestBlock*2)==NULL);
sl@0
   505
sl@0
   506
	// Resize the block to 0
sl@0
   507
	aCell=pHeap->ReAlloc(aCell, 0);
sl@0
   508
	CellSize=pHeap->AllocLen(aCell);  // test?
sl@0
   509
sl@0
   510
	// Resize positively
sl@0
   511
	for(TInt aSize=0; aSize<=BiggestBlock; aSize++, pHeap->Available(BiggestBlock))
sl@0
   512
		{
sl@0
   513
		test(pHeap->ReAlloc(aCell, aSize)!=NULL); 
sl@0
   514
		CellSize=pHeap->AllocLen(aCell);
sl@0
   515
		test(CellSize>=aSize);
sl@0
   516
		if (aSize<KMinCellLength)
sl@0
   517
			test(CellSize==KMinCellLength);
sl@0
   518
		else
sl@0
   519
			test(CellSize<aSize+KAlign);
sl@0
   520
		}
sl@0
   521
sl@0
   522
	// Note: when increasing a cell size the size is rounded up to the nearest 4 but when 
sl@0
   523
	// decreasing a cell the size is rounded down to the nearest 8 - this is due to the fact
sl@0
   524
	// that when memory is released its size must be big enough to hold a free cell header which
sl@0
   525
	// is greater(8) than an allocated header(4)
sl@0
   526
	// i.e. size = 16, resize to 17 => result  is 20. But resize to 15 stays as 16, resize to 9
sl@0
   527
	// stays as 16 but resize as 8 will resize to 8
sl@0
   528
sl@0
   529
	for(TInt aSize2=(TInt)pHeap->AllocLen(aCell); aSize2>=0; aSize2--)
sl@0
   530
		{
sl@0
   531
		test(pHeap->ReAlloc(aCell, aSize2)!=NULL);
sl@0
   532
		test(((TInt)pHeap->AllocLen(aCell)>=aSize2)&&((TInt)pHeap->AllocLen(aCell)<=aSize2+KMinFreeSize));
sl@0
   533
		}
sl@0
   534
  
sl@0
   535
	pHeap->Check();
sl@0
   536
	pHeap->Reset();
sl@0
   537
	// Allocate a block, fill with data, allocate another block or two then resize the original
sl@0
   538
	// block such that it has to be moved in memory, then check the blocks' contents 
sl@0
   539
	TAny* Cell1=pHeap->Alloc(16);
sl@0
   540
	TText8* pC;
sl@0
   541
	TInt Cell1Size=pHeap->AllocLen(Cell1);
sl@0
   542
	for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+Cell1Size; *pC++='x')
sl@0
   543
		;
sl@0
   544
	TAny* Cell2=pHeap->Alloc(16);
sl@0
   545
	TInt Cell2Size=pHeap->AllocLen(Cell2);
sl@0
   546
	for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+pHeap->AllocLen(Cell2); *pC++='y')
sl@0
   547
		;
sl@0
   548
	Cell1=pHeap->ReAlloc(Cell1, 128);
sl@0
   549
	// Test data was copied on reallocation
sl@0
   550
	for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+Cell1Size; test(*pC++=='x'))
sl@0
   551
		; 
sl@0
   552
	// Test other data wasn't corrupted
sl@0
   553
	for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+pHeap->AllocLen(Cell2); test(*pC++=='y'))
sl@0
   554
		;
sl@0
   555
sl@0
   556
	// Allocate another block
sl@0
   557
	TAny* Cell3=pHeap->Alloc(8);
sl@0
   558
	for(pC=(TText8*)Cell3; pC<(TText8*)Cell3+pHeap->AllocLen(Cell3); *pC++='z')
sl@0
   559
		;
sl@0
   560
	// test existing blocks to be safe
sl@0
   561
	for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+Cell1Size; test(*pC++=='x'))
sl@0
   562
		;
sl@0
   563
	for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+Cell2Size; test(*pC++=='y'))
sl@0
   564
		;
sl@0
   565
	// Resize previous blocks
sl@0
   566
	Cell1=pHeap->ReAlloc(Cell1, 16); // Shrink previously expanded block
sl@0
   567
	Cell2=pHeap->ReAlloc(Cell2, 64); 
sl@0
   568
	// Now test data
sl@0
   569
	for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+Cell1Size; test(*pC++=='x'))
sl@0
   570
		;
sl@0
   571
	for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+Cell2Size; test(*pC++=='y'))
sl@0
   572
		;
sl@0
   573
	for(pC=(TText8*)Cell3; pC<(TText8*)Cell3+pHeap->AllocLen(Cell3); test(*pC++=='z'))
sl@0
   574
		;
sl@0
   575
sl@0
   576
	// Re-expand Cell1
sl@0
   577
	Cell1=pHeap->ReAlloc(Cell1, 1028);
sl@0
   578
	for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+Cell1Size; test(*pC++=='x'))
sl@0
   579
		;
sl@0
   580
	for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+Cell2Size; test(*pC++=='y'))
sl@0
   581
		;
sl@0
   582
	for(pC=(TText8*)Cell3; pC<(TText8*)Cell3+pHeap->AllocLen(Cell3); test(*pC++=='z'))
sl@0
   583
		;
sl@0
   584
sl@0
   585
	// Shrink cells back to original size
sl@0
   586
	Cell1=pHeap->ReAlloc(Cell1, Cell1Size);
sl@0
   587
	Cell2=pHeap->ReAlloc(Cell2, Cell2Size);  
sl@0
   588
	for(pC=(TText8*)Cell1; pC<(TText8*)Cell1+Cell1Size; test(*pC++=='x'))
sl@0
   589
		;
sl@0
   590
	for(pC=(TText8*)Cell2; pC<(TText8*)Cell2+Cell2Size; test(*pC++=='y'))
sl@0
   591
		;
sl@0
   592
	for(pC=(TText8*)Cell3; pC<(TText8*)Cell3+pHeap->AllocLen(Cell3); test(*pC++=='z'))
sl@0
   593
		;
sl@0
   594
sl@0
   595
	pHeap->Check();
sl@0
   596
	INV(test(Invariant(pHeap)));
sl@0
   597
sl@0
   598
	// close heap so we don't exceed chunk limit
sl@0
   599
	pHeap->Close();
sl@0
   600
	}
sl@0
   601
sl@0
   602
sl@0
   603
///////////////////////////////////////////////////////////////////////////////
sl@0
   604
// Test walking methods (more thoroughly than previously)
sl@0
   605
//////////////////////////////////////////////////////////////////////////////				  
sl@0
   606
void TestRHeap::Test7(void)
sl@0
   607
	{ 
sl@0
   608
	TInt NumAllocated=0, NumFree=1, i;
sl@0
   609
	RHeap* pHeap=allocHeap(5000);
sl@0
   610
sl@0
   611
	TAny** ArrayOfCells;
sl@0
   612
	ArrayOfCells= new TAny*[100];
sl@0
   613
sl@0
   614
	for(i=0; i<100; i++)
sl@0
   615
		{
sl@0
   616
		ArrayOfCells[i]=pHeap->Alloc(8);
sl@0
   617
		NumAllocated++;
sl@0
   618
		test(NumAllocated==pHeap->Count(NumFree));
sl@0
   619
		test(NumFree==1);
sl@0
   620
		}
sl@0
   621
	pHeap->Check();
sl@0
   622
sl@0
   623
	for(i=0; i<100; i+=2)
sl@0
   624
		{
sl@0
   625
		TInt temp;
sl@0
   626
		pHeap->Free(ArrayOfCells[i]);
sl@0
   627
		NumAllocated--;
sl@0
   628
		NumFree++;
sl@0
   629
		test(NumAllocated==pHeap->Count(temp));
sl@0
   630
		test(NumFree==temp);
sl@0
   631
		}
sl@0
   632
	pHeap->Check();
sl@0
   633
	pHeap->Reset();
sl@0
   634
sl@0
   635
sl@0
   636
	///////////////////////////////////////////
sl@0
   637
	// Corrupt data and see what happens
sl@0
   638
	///////////////////////////////////////////
sl@0
   639
	// Corrupt  allocated cell header
sl@0
   640
	ArrayOfCells[0]=pHeap->Alloc(32);
sl@0
   641
	TUint32* pC=(TUint32*)ArrayOfCells[0]-KHeadSize; 
sl@0
   642
	*pC=0xa5a5a5a5u; 
sl@0
   643
	// pHeap->Check();
sl@0
   644
sl@0
   645
	// Corrupt free cell header 
sl@0
   646
	pHeap->Reset();
sl@0
   647
	ArrayOfCells[0]=pHeap->Alloc(32);
sl@0
   648
	pC=(TUint32*)ArrayOfCells[0]+(pHeap->AllocLen(ArrayOfCells[0])>>2);
sl@0
   649
	*pC=0xa1a1a1a1u;	
sl@0
   650
	//pHeap->Check();	 // Check doesn't pick it up but an access violation is generated
sl@0
   651
sl@0
   652
	// Write past end of heap
sl@0
   653
	pHeap->Reset();
sl@0
   654
	TInt Avail;
sl@0
   655
	ArrayOfCells[0]=pHeap->Alloc(pHeap->Available(Avail));
sl@0
   656
	pC=(TUint32*)ArrayOfCells[0]+(pHeap->AllocLen(ArrayOfCells[0])>>2);
sl@0
   657
	//*pC=0xa1a1a1a1u;	// This line isn't picked up by Check (wouldn't expect it to) but the call
sl@0
   658
	//pHeap->Check();	// to delete below consequently crashes 
sl@0
   659
sl@0
   660
	delete [] ArrayOfCells;
sl@0
   661
sl@0
   662
	// close heap so we don't exceed chunk limit
sl@0
   663
	pHeap->Close();
sl@0
   664
	}
sl@0
   665
sl@0
   666
//////////////////////////////////////
sl@0
   667
// Test the leave methods
sl@0
   668
//////////////////////////////////////
sl@0
   669
void TestRHeap::Test8(void)
sl@0
   670
	{ 
sl@0
   671
sl@0
   672
	TAny* aCell=NULL;
sl@0
   673
	RHeap* pHeap=allocHeap(1000); 
sl@0
   674
	TRAPD(ret,aCell=pHeap->AllocL(100))
sl@0
   675
	test(ret==KErrNone);
sl@0
   676
	TRAP(ret,aCell=pHeap->AllocL(PageSize))
sl@0
   677
   	test(ret==KErrNoMemory);
sl@0
   678
	TRAP(ret,aCell=pHeap->ReAllocL(aCell,32))
sl@0
   679
	test(ret==KErrNone);
sl@0
   680
	TRAP(ret,aCell=pHeap->ReAllocL(NULL,10000))
sl@0
   681
	test(ret==KErrNoMemory);
sl@0
   682
sl@0
   683
	// close heap so we don't exceed chunk limit
sl@0
   684
	pHeap->Close();
sl@0
   685
	}
sl@0
   686
sl@0
   687
class RMyHeap : public RHeap
sl@0
   688
	{
sl@0
   689
public:
sl@0
   690
	void MyCompressAll(){}
sl@0
   691
private:
sl@0
   692
	RMyHeap();
sl@0
   693
	};
sl@0
   694
sl@0
   695
#include "TestRHeapShrink.h"
sl@0
   696
sl@0
   697
/**
sl@0
   698
	Calculates whether or not the heap with iGrowBy=aGrowBy will be reduced if a 
sl@0
   699
	cell of size aCellSize bytes is the top free cell.
sl@0
   700
	It must be calculated as both the page size and min cell size could vary
sl@0
   701
	between different platforms/builds.  Also, KHeapMinCellSize is 'patchdata' and can be
sl@0
   702
	different for particular ROM builds
sl@0
   703
	ASSUMPTIONS:-
sl@0
   704
		1 - The cell of aCellSize starts past the RHeap's iMinLength (i.e. all of it can be 
sl@0
   705
		removed without the RHeap becoming smaller than iMinLength
sl@0
   706
		2 - The default value of aAlign was passed to RHeap contructor
sl@0
   707
	These should be safe as this is onl used by t_heap TestRHeap::CompressAll()
sl@0
   708
	@return The number of bytes the heap will be reduced by
sl@0
   709
*/
sl@0
   710
TInt TestRHeap::RHeapCalcReduce(TInt aCellSize, TInt aGrowBy)
sl@0
   711
	{
sl@0
   712
	TInt ret = 0;
sl@0
   713
	TInt pageSize = 0;
sl@0
   714
	test(UserHal::PageSizeInBytes(pageSize)==KErrNone);
sl@0
   715
	
sl@0
   716
	// adjust aGrowBy to match what RHeap would have aligned its iGrowBy to 
sl@0
   717
	// see RHeap::RHeap()
sl@0
   718
	aGrowBy = _ALIGN_UP(aGrowBy, pageSize);
sl@0
   719
	if (aCellSize >= KHeapShrinkHysRatio*(aGrowBy>>8))
sl@0
   720
		{
sl@0
   721
		//calc for amount to reduce heap from RHeap::Reduce()
sl@0
   722
		// assumes that cell of aCellSize starts past the RHeap's iMinLength
sl@0
   723
		ret=_ALIGN_DOWN(aCellSize, pageSize);
sl@0
   724
		}
sl@0
   725
	return ret;
sl@0
   726
	}
sl@0
   727
sl@0
   728
void TestRHeap::TestCompressAll()
sl@0
   729
	{
sl@0
   730
sl@0
   731
	TPtrC myHeapName=_L("MyHeap");
sl@0
   732
	// myHeap will have default GrowBy of KMinHeapGrowBy
sl@0
   733
	RMyHeap* myHeap=(RMyHeap*)User::ChunkHeap(&myHeapName,0x100,0x2000);
sl@0
   734
const TInt KnormHeapGrowBy = 0x2000;
sl@0
   735
	RHeap* normHeap=User::ChunkHeap(NULL,0x100,0x20000,KnormHeapGrowBy);
sl@0
   736
sl@0
   737
	TAny* ptrMy1=myHeap->Alloc(0x102);
sl@0
   738
	test(ptrMy1!=NULL);
sl@0
   739
	TAny* ptrMy2=myHeap->Alloc(0x1001);
sl@0
   740
	test(ptrMy2!=NULL);
sl@0
   741
	TInt r=myHeap->Count();
sl@0
   742
	test(r==2);
sl@0
   743
sl@0
   744
	TAny* ptrNorm1=normHeap->Alloc(0x8002);
sl@0
   745
	test(ptrNorm1!=NULL);
sl@0
   746
	TAny* ptrNorm2=normHeap->Alloc(0x12fff);
sl@0
   747
	test(ptrNorm2!=NULL);
sl@0
   748
	TAny* ptrNorm3=normHeap->Alloc(0x334f);
sl@0
   749
	test(ptrNorm3!=NULL);
sl@0
   750
	r=normHeap->Count();
sl@0
   751
	test(r==3);
sl@0
   752
sl@0
   753
	TInt oldMyHeapSize=myHeap->Size(); 	
sl@0
   754
	TInt oldNormHeapSize=normHeap->Size();
sl@0
   755
	 	
sl@0
   756
	myHeap->MyCompressAll();
sl@0
   757
sl@0
   758
	r=myHeap->Count();
sl@0
   759
	test(r==2);
sl@0
   760
	r=myHeap->Size();
sl@0
   761
	test(r==oldMyHeapSize);
sl@0
   762
	r=normHeap->Count();
sl@0
   763
	test(r==3);
sl@0
   764
	r=normHeap->Size();
sl@0
   765
	test(r==oldNormHeapSize);
sl@0
   766
sl@0
   767
	// Remove the cell on the top of the normHeap
sl@0
   768
	normHeap->Free(ptrNorm3);
sl@0
   769
	// check myHeap unaffected
sl@0
   770
	r=myHeap->Count();
sl@0
   771
	test(r==2);
sl@0
   772
	r=myHeap->Size();
sl@0
   773
	test(r==oldMyHeapSize);
sl@0
   774
	//check normHeap updated after free of top cell
sl@0
   775
	r=normHeap->Count();
sl@0
   776
	test(r==2);
sl@0
   777
	r=normHeap->Size();
sl@0
   778
sl@0
   779
	// Calc the amount, if any, the overall size of normHeap will have been shrunk by
sl@0
   780
	// will depend on value of KHeapShrinkHysRatio.
sl@0
   781
	// 1st calc current total size of the allocated cells
sl@0
   782
	TInt normAllocdSize = 	normHeap->AllocLen(ptrNorm1)+RHeap::EAllocCellSize +
sl@0
   783
							normHeap->AllocLen(ptrNorm2)+RHeap::EAllocCellSize;
sl@0
   784
	TInt normReduce = RHeapCalcReduce(oldNormHeapSize-normAllocdSize,KnormHeapGrowBy);
sl@0
   785
	oldNormHeapSize -= normReduce;
sl@0
   786
	test(r==oldNormHeapSize);
sl@0
   787
sl@0
   788
	normHeap->Free(ptrNorm2);
sl@0
   789
	myHeap->Free(ptrMy2);
sl@0
   790
	r=myHeap->Count();
sl@0
   791
	test(r==1);
sl@0
   792
	r=myHeap->Size();
sl@0
   793
sl@0
   794
	// Calc the current total size of the allocated cells
sl@0
   795
	TInt myAllocdSize = myHeap->AllocLen(ptrMy1)+RHeap::EAllocCellSize;
sl@0
   796
	TInt myReduce=RHeapCalcReduce(oldMyHeapSize-myAllocdSize,1);
sl@0
   797
	oldMyHeapSize -= myReduce;
sl@0
   798
	test(r==oldMyHeapSize);
sl@0
   799
sl@0
   800
	r=normHeap->Count();
sl@0
   801
	test(r==1);
sl@0
   802
	r=normHeap->Size();
sl@0
   803
sl@0
   804
	// cell represented by ptrNorm3 may have already caused the heap
sl@0
   805
	// size to be reduced so ensure normReduce is factored into calcs
sl@0
   806
	test(r==oldNormHeapSize-(0x16000-normReduce));
sl@0
   807
sl@0
   808
	myHeap->Close();
sl@0
   809
	normHeap->Close();
sl@0
   810
	}
sl@0
   811
sl@0
   812
sl@0
   813
void TestRHeap::TestOffset()
sl@0
   814
	{
sl@0
   815
	TInt size = 0x100000;
sl@0
   816
	const TInt offset = 0x8;
sl@0
   817
	const TUint8 magic = 0x74; // arbitrary magic value
sl@0
   818
	RChunk chunk;
sl@0
   819
	RHeap* heap;
sl@0
   820
	
sl@0
   821
	chunk.CreateLocal(0, size);
sl@0
   822
	size = chunk.MaxSize();	// X86 has 4MB chunk size
sl@0
   823
	
sl@0
   824
	// try and create a heap with a large offset - no room to make RHeap, should fail
sl@0
   825
	heap = UserHeap::OffsetChunkHeap(chunk, 0, size);
sl@0
   826
	test(heap==NULL);
sl@0
   827
	
sl@0
   828
	// write some magic numbers into the offset-reserved area
sl@0
   829
	chunk.Adjust(offset);
sl@0
   830
	TUint8* reserved = chunk.Base();
sl@0
   831
	TUint8* limit = reserved + offset;
sl@0
   832
	for (; reserved<limit; reserved++)
sl@0
   833
		*reserved = magic;
sl@0
   834
	
sl@0
   835
	// make a heap with an offset
sl@0
   836
	heap = UserHeap::OffsetChunkHeap(chunk, 0, offset);
sl@0
   837
	test(heap!=NULL);
sl@0
   838
	test(chunk.Base() + offset == (TUint8*)heap);
sl@0
   839
	TInt origsize = heap->Size();
sl@0
   840
sl@0
   841
	// force the heap to grow to the maximum size by allocating 1kb blocks
sl@0
   842
	// and then allocating whatever is left. Check this really is the end
sl@0
   843
	// of the chunk.
sl@0
   844
	TUint8* temp = NULL;
sl@0
   845
	TUint8* last = NULL;
sl@0
   846
	do
sl@0
   847
		{
sl@0
   848
		last = temp;
sl@0
   849
		temp = (TUint8*)heap->Alloc(1024);
sl@0
   850
		}
sl@0
   851
	while (temp != NULL);
sl@0
   852
	TInt biggestblock, space;
sl@0
   853
	space = heap->Available(biggestblock);
sl@0
   854
	if (space>0)
sl@0
   855
		{
sl@0
   856
		last = (TUint8*)heap->Alloc(space);
sl@0
   857
		test(last!=NULL);
sl@0
   858
		// Check that the last allocation doesn't pass the end of the chunk
sl@0
   859
		test(last+space <= chunk.Base()+size);
sl@0
   860
		// but that it is within the alignment requirement, as less than this
sl@0
   861
		// would be short of the end
sl@0
   862
		test(last+space > chunk.Base()+size-RHeap::ECellAlignment);
sl@0
   863
		}
sl@0
   864
	else
sl@0
   865
		{
sl@0
   866
		test(last+1024 == chunk.Base()+size);
sl@0
   867
		}
sl@0
   868
	
sl@0
   869
	// try writing at the top end of it to make sure it's backed
sl@0
   870
	*(chunk.Base()+size-1) = 1;
sl@0
   871
	
sl@0
   872
	// test resetting the heap
sl@0
   873
	heap->Reset();
sl@0
   874
	test(origsize == heap->Size());
sl@0
   875
	
sl@0
   876
	// check reducing the heap works
sl@0
   877
	last = (TUint8*)heap->Alloc(size>>2);
sl@0
   878
	TInt midsize = heap->Size();
sl@0
   879
	temp = (TUint8*)heap->Alloc(size>>2);
sl@0
   880
	heap->Free(temp);
sl@0
   881
	heap->Compress();
sl@0
   882
	test(midsize == heap->Size());
sl@0
   883
	heap->Free(last);
sl@0
   884
	heap->Compress();
sl@0
   885
	test(origsize == heap->Size());
sl@0
   886
	
sl@0
   887
	// check the magic numbers are still there
sl@0
   888
	for (reserved = chunk.Base(); reserved<limit; reserved++)
sl@0
   889
		test(*reserved==magic);
sl@0
   890
	
sl@0
   891
	heap->Close();
sl@0
   892
	}
sl@0
   893
sl@0
   894
sl@0
   895
RSemaphore sem;
sl@0
   896
LOCAL_C void syncThreads(TAny* anArg)
sl@0
   897
//
sl@0
   898
// get the threads both running at the same time
sl@0
   899
//
sl@0
   900
	{
sl@0
   901
	if ((TInt)anArg==1)
sl@0
   902
		sem.Wait();
sl@0
   903
	else
sl@0
   904
		sem.Signal();
sl@0
   905
	}
sl@0
   906
sl@0
   907
TInt comeInNumber=0;
sl@0
   908
LOCAL_C TInt sharedHeapTest1(TAny* anArg)
sl@0
   909
//
sl@0
   910
// Shared heap test thread.
sl@0
   911
//
sl@0
   912
	{
sl@0
   913
sl@0
   914
	RHeap* pH = (RHeap*)&User::Allocator();
sl@0
   915
	if (gHeapPtr && pH!=gHeapPtr)
sl@0
   916
		return(KErrGeneral);
sl@0
   917
	gHeapPtr2 = pH;
sl@0
   918
sl@0
   919
	syncThreads(anArg);
sl@0
   920
sl@0
   921
	TAny* a[0x100];
sl@0
   922
	TInt mod=((TInt)anArg)*3;
sl@0
   923
sl@0
   924
	// Run in a timed loop, to ensure that we get some true concurrency
sl@0
   925
	RTimer timer;
sl@0
   926
	TTime now;
sl@0
   927
	TRequestStatus done;
sl@0
   928
	test(timer.CreateLocal()==KErrNone);
sl@0
   929
	now.HomeTime();
sl@0
   930
	timer.At(done,now+TTimeIntervalSeconds(20));
sl@0
   931
sl@0
   932
	while (done==KRequestPending && comeInNumber!=(TInt)anArg)
sl@0
   933
		{
sl@0
   934
		TInt i=0;
sl@0
   935
		for (;i<0x100;i++)
sl@0
   936
			{
sl@0
   937
			a[i]=User::Alloc(0x10);
sl@0
   938
			test(a[i]!=NULL);
sl@0
   939
			Mem::Fill(a[i],0x10,(((TInt)anArg)<<4)|(i&0x0F));	// marker
sl@0
   940
			if ((i%mod)==0)
sl@0
   941
				pH->Check();
sl@0
   942
			}
sl@0
   943
		for (i=0;i<0x100;i++)
sl@0
   944
			{
sl@0
   945
			User::Free(a[i]);
sl@0
   946
			if ((i%mod)==0)
sl@0
   947
				pH->Check();
sl@0
   948
			}
sl@0
   949
		}
sl@0
   950
	timer.Cancel();
sl@0
   951
	return((TInt)anArg);
sl@0
   952
	}
sl@0
   953
sl@0
   954
LOCAL_C void bumpKernelGranularity()
sl@0
   955
//
sl@0
   956
// Push up the kernels granularities
sl@0
   957
//
sl@0
   958
	{
sl@0
   959
sl@0
   960
	RThread t[4];
sl@0
   961
	TInt r;
sl@0
   962
	TUint i=0;
sl@0
   963
	for (;i<4;i++)
sl@0
   964
		{
sl@0
   965
		TName n;
sl@0
   966
		n.Format(_L("Temp%d"),i);
sl@0
   967
		r=t[i].Create(n,sharedHeapTest1,KDefaultStackSize,NULL,NULL);
sl@0
   968
		test(r==KErrNone);
sl@0
   969
		}
sl@0
   970
	for (i=0;i<4;i++)
sl@0
   971
		{
sl@0
   972
		t[i].Kill(KErrNone);
sl@0
   973
		t[i].Close();
sl@0
   974
		}
sl@0
   975
	}
sl@0
   976
sl@0
   977
LOCAL_C void createTestThreads(TThreadFunction aFunction,RHeap* aHeap)
sl@0
   978
//
sl@0
   979
// Create two test threads using the supplied entry point and heap
sl@0
   980
//
sl@0
   981
	{
sl@0
   982
sl@0
   983
sl@0
   984
	test.Next(_L("Create t1"));
sl@0
   985
	RThread t1;
sl@0
   986
	TInt r=t1.Create(_L("Shared1"),aFunction,KDefaultStackSize,aHeap,(TAny*)1);
sl@0
   987
	test(r==KErrNone);
sl@0
   988
	TRequestStatus tStat1;
sl@0
   989
	t1.Logon(tStat1);
sl@0
   990
	test(tStat1==KRequestPending);
sl@0
   991
sl@0
   992
	test.Next(_L("Create t2"));
sl@0
   993
	RThread t2;
sl@0
   994
	r=t2.Create(_L("Shared2"),aFunction,KDefaultStackSize,aHeap,(TAny*)2);
sl@0
   995
	test(r==KErrNone);
sl@0
   996
	TRequestStatus tStat2;
sl@0
   997
	t2.Logon(tStat2);
sl@0
   998
	test(tStat2==KRequestPending);
sl@0
   999
sl@0
  1000
	test.Next(_L("Wait for t1 or t2 - approx 20 seconds"));
sl@0
  1001
	t1.Resume();
sl@0
  1002
	t2.Resume();
sl@0
  1003
	User::WaitForRequest(tStat1,tStat2);
sl@0
  1004
	User::WaitForRequest(tStat1==KRequestPending ? tStat1 : tStat2);
sl@0
  1005
	test(tStat1==1);
sl@0
  1006
	test(tStat2==2);
sl@0
  1007
	CLOSE_AND_WAIT(t1);
sl@0
  1008
	CLOSE_AND_WAIT(t2);
sl@0
  1009
	}
sl@0
  1010
sl@0
  1011
LOCAL_C void SharedHeapTest1()
sl@0
  1012
//
sl@0
  1013
// Shared heap test using normal chunk heap
sl@0
  1014
//
sl@0
  1015
	{
sl@0
  1016
sl@0
  1017
	sem.CreateLocal(0);	// create synchronisation semaphore
sl@0
  1018
	test.Start(_L("Create chunk to share"));
sl@0
  1019
	TPtrC sharedHeap=_L("SharedHeap");
sl@0
  1020
	TInt minsize = ((RHeap&)User::Allocator()).Size();
sl@0
  1021
	gHeapPtr=User::ChunkHeap(&sharedHeap,minsize/*0x20000*/,0x40000);
sl@0
  1022
	test(gHeapPtr!=NULL);
sl@0
  1023
	TInt count=gHeapPtr->Count();
sl@0
  1024
	createTestThreads(sharedHeapTest1,gHeapPtr);
sl@0
  1025
	test(count==gHeapPtr->Count());
sl@0
  1026
	gHeapPtr->Close();
sl@0
  1027
	test.End();
sl@0
  1028
	}
sl@0
  1029
sl@0
  1030
LOCAL_C void SharedHeapTest2()
sl@0
  1031
//
sl@0
  1032
// Shared heap test using the current threads heap. Can test kernel
sl@0
  1033
// cleanup since granularity will have been handled by running
sl@0
  1034
// SharedHeapTest2().
sl@0
  1035
//
sl@0
  1036
	{
sl@0
  1037
sl@0
  1038
	test.Start(_L("Current chunk to share"));
sl@0
  1039
	test.Next(_L("Bump up granularities"));
sl@0
  1040
//
sl@0
  1041
// First create a number of threads to push up the kernels granularities
sl@0
  1042
//
sl@0
  1043
	bumpKernelGranularity();
sl@0
  1044
//
sl@0
  1045
	__KHEAP_MARK;
sl@0
  1046
	gHeapPtr = (RHeap*)&User::Allocator();
sl@0
  1047
	TInt biggest1;
sl@0
  1048
	TInt avail1=gHeapPtr->Available(biggest1);
sl@0
  1049
	TInt size1=gHeapPtr->Size();
sl@0
  1050
sl@0
  1051
	createTestThreads(sharedHeapTest1,NULL);
sl@0
  1052
	
sl@0
  1053
	TInt biggest2;
sl@0
  1054
	TInt avail2=gHeapPtr->Available(biggest2);
sl@0
  1055
	TInt size2=gHeapPtr->Size();
sl@0
  1056
	test.Printf(_L("Before: size %d, %d available (biggest %d)\r\n"),size1,avail1,biggest1);
sl@0
  1057
	test.Printf(_L("After:  size %d, %d available (biggest %d)\r\n"),size2,avail2,biggest2);
sl@0
  1058
	test((size1-avail1)==(size2-avail2));	// no leaks
sl@0
  1059
	if (avail1==biggest1)	// if it was a single block of free space before
sl@0
  1060
		test(avail2==biggest2);	// then it should still be a single block
sl@0
  1061
	__KHEAP_MARKEND;
sl@0
  1062
	test.End();
sl@0
  1063
	}
sl@0
  1064
sl@0
  1065
LOCAL_C void SharedHeapTest3()
sl@0
  1066
//
sl@0
  1067
// Shared heap test borrowing a thread's default heap and
sl@0
  1068
// killing threads in different orders.
sl@0
  1069
//
sl@0
  1070
	{
sl@0
  1071
sl@0
  1072
	test.Start(_L("Create t1 whose heap will be shared"));
sl@0
  1073
	gHeapPtr = NULL;
sl@0
  1074
	RThread t1;
sl@0
  1075
	TInt r=t1.Create(_L("Owner_T1"),sharedHeapTest1,KDefaultStackSize,0x20000,0x40000,(TAny*)1);
sl@0
  1076
	test(r==KErrNone);
sl@0
  1077
	TRequestStatus tStat1;
sl@0
  1078
	t1.Logon(tStat1);
sl@0
  1079
	test(tStat1==KRequestPending);
sl@0
  1080
	t1.SetPriority(EPriorityMore); //t1 gets to wait on semaphore sem, before we start t2
sl@0
  1081
	t1.Resume();
sl@0
  1082
	test.Next(_L("Create t2 sharing t1's heap"));
sl@0
  1083
	RThread t2;
sl@0
  1084
	r=t2.Create(_L("Sharer_T2"),sharedHeapTest1,KDefaultStackSize,gHeapPtr2,(TAny*)2);
sl@0
  1085
	test(r==KErrNone);
sl@0
  1086
	TRequestStatus tStat2;
sl@0
  1087
	t2.Logon(tStat2);
sl@0
  1088
	test(tStat2==KRequestPending);
sl@0
  1089
sl@0
  1090
	test.Next(_L("Get t1 to exit while t2 continues running"));
sl@0
  1091
	test(tStat1==KRequestPending);
sl@0
  1092
	test(tStat2==KRequestPending);
sl@0
  1093
	t1.SetPriority(EPriorityNormal); //back to the same priority as t2
sl@0
  1094
	t2.Resume();
sl@0
  1095
	test(tStat1==KRequestPending);
sl@0
  1096
	test(tStat2==KRequestPending);
sl@0
  1097
	comeInNumber=1;
sl@0
  1098
	test.Next(_L("Wait for t1"));
sl@0
  1099
	User::WaitForRequest(tStat1);
sl@0
  1100
	test(tStat1==1);
sl@0
  1101
	test(t1.ExitType()==EExitKill);
sl@0
  1102
	test(t1.ExitReason()==1);
sl@0
  1103
	test(tStat2==KRequestPending);
sl@0
  1104
	test(t2.ExitType()==EExitPending);
sl@0
  1105
	test.Next(_L("Wait for t2"));
sl@0
  1106
	User::WaitForRequest(tStat2);
sl@0
  1107
	test(tStat2==2);
sl@0
  1108
	test(t2.ExitType()==EExitKill);
sl@0
  1109
	test(t2.ExitReason()==2);
sl@0
  1110
	CLOSE_AND_WAIT(t2);
sl@0
  1111
	CLOSE_AND_WAIT(t1);
sl@0
  1112
	test.End();
sl@0
  1113
	}
sl@0
  1114
sl@0
  1115
LOCAL_C void TestAuto()
sl@0
  1116
//
sl@0
  1117
// Test heap auto expansion and compression
sl@0
  1118
//
sl@0
  1119
	{
sl@0
  1120
sl@0
  1121
	test.Start(_L("Create chunk to"));
sl@0
  1122
	TPtrC autoHeap=_L("AutoHeap");
sl@0
  1123
	gHeapPtr=User::ChunkHeap(&autoHeap,0x1800,0x6000);
sl@0
  1124
	test(gHeapPtr!=NULL);
sl@0
  1125
	TInt biggest;
sl@0
  1126
	TInt avail=gHeapPtr->Available(biggest);
sl@0
  1127
	test(avail==biggest);
sl@0
  1128
	TAny *p1=gHeapPtr->Alloc(biggest);
sl@0
  1129
	test(p1!=NULL);
sl@0
  1130
	TAny *p2=gHeapPtr->Alloc(biggest);
sl@0
  1131
	test(p2!=NULL);
sl@0
  1132
	TAny *p3=gHeapPtr->Alloc(biggest);
sl@0
  1133
	test(p3!=NULL);
sl@0
  1134
	TAny *p4=gHeapPtr->Alloc(biggest);
sl@0
  1135
	test(p4==NULL);
sl@0
  1136
	TInt comp=gHeapPtr->Compress();
sl@0
  1137
	test(comp==0);
sl@0
  1138
	gHeapPtr->Free(p2);
sl@0
  1139
	comp=gHeapPtr->Compress();
sl@0
  1140
	test(comp==0);
sl@0
  1141
	gHeapPtr->Free(p3);
sl@0
  1142
	comp=gHeapPtr->Compress();
sl@0
  1143
// stop wins compiler warning of constant expression as KHeapShrinkHysRatio
sl@0
  1144
// isn't constant for non-emulator builds but ROM 'patchdata'
sl@0
  1145
#pragma warning(disable : 4127)
sl@0
  1146
	// When hysteresis value > 4.0*GrowBy then Free() calls
sl@0
  1147
	// won't shrink heap but normally will shrink heap
sl@0
  1148
	if (KHeapShrinkHysRatio <= 1024)
sl@0
  1149
		test(comp==0);
sl@0
  1150
	else
sl@0
  1151
		test(comp==0x4000);
sl@0
  1152
#pragma warning(default : 4127)
sl@0
  1153
	gHeapPtr->Free(p1);
sl@0
  1154
	comp=gHeapPtr->Compress();
sl@0
  1155
	test(comp==0);
sl@0
  1156
	TInt biggest1;
sl@0
  1157
	TInt avail1=gHeapPtr->Available(biggest1);
sl@0
  1158
	test(avail1==avail1);
sl@0
  1159
	test(biggest==biggest1);
sl@0
  1160
	test(gHeapPtr->Count()==0);
sl@0
  1161
	gHeapPtr->Close();
sl@0
  1162
	test.End();
sl@0
  1163
	}
sl@0
  1164
sl@0
  1165
sl@0
  1166
GLDEF_C TInt E32Main(void)
sl@0
  1167
	{
sl@0
  1168
sl@0
  1169
	test.Title();
sl@0
  1170
sl@0
  1171
	__KHEAP_MARK;
sl@0
  1172
sl@0
  1173
	test.Start(_L("Test 1"));
sl@0
  1174
	UserHal::PageSizeInBytes(PageSize);
sl@0
  1175
        TestRHeap T;
sl@0
  1176
	T.Test1();
sl@0
  1177
	test.Next(_L("Test auto expand and compress"));
sl@0
  1178
	TestAuto();
sl@0
  1179
	test.Next(_L("Test 2"));
sl@0
  1180
	T.Test2();
sl@0
  1181
	test.Next(_L("Test 3"));
sl@0
  1182
	T.Test3();
sl@0
  1183
	test.Next(_L("Test 4"));
sl@0
  1184
	T.Test4();
sl@0
  1185
	test.Next(_L("Test 5"));
sl@0
  1186
	T.Test5();
sl@0
  1187
	test.Next(_L("Test 7"));
sl@0
  1188
	T.Test7();
sl@0
  1189
	test.Next(_L("Test 8"));
sl@0
  1190
	T.Test8();
sl@0
  1191
	test.Next(_L("Test CompressAll()"));
sl@0
  1192
	T.TestCompressAll();
sl@0
  1193
	test.Next(_L("Test offset heap"));
sl@0
  1194
	T.TestOffset();
sl@0
  1195
	test.Next(_L("Shared heap test 1"));
sl@0
  1196
	SharedHeapTest1();
sl@0
  1197
	test.Next(_L("Shared heap test 2"));
sl@0
  1198
	SharedHeapTest2();
sl@0
  1199
	test.Next(_L("Shared heap test 3"));
sl@0
  1200
	SharedHeapTest3();
sl@0
  1201
	sem.Close();
sl@0
  1202
sl@0
  1203
	__KHEAP_CHECK(0);
sl@0
  1204
	__KHEAP_MARKEND;
sl@0
  1205
//
sl@0
  1206
	test.End();
sl@0
  1207
	return(0);
sl@0
  1208
    }
sl@0
  1209