os/kernelhwsrv/kerneltest/e32test/heap/t_heap2.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\heap\t_heap2.cpp
    15 // Overview:
    16 // Tests RHeap class, including a stress test and a "grow in place"
    17 // ReAlloc test.
    18 // API Information:
    19 // RHeap
    20 // Details:
    21 // - Test allocation on fixed length heaps in local, disconnected chunks for
    22 // different heap sizes and alignments.  Assumes knowledge of heap
    23 // implementation.
    24 // - Test allocation, free, reallocation and compression on chunk heaps with
    25 // different maximum and minimum lengths and alignments.  Assumes knowledge
    26 // of heap implementation.      
    27 // - Stress test heap implementation with a single thread that allocates, frees
    28 // and reallocates cells, and checks the heap.
    29 // - Stress test heap implementation with two threads that run concurrently.
    30 // - Create a chunk heap, test growing in place by allocating a cell and 
    31 // then reallocating additional space until failure, verify that the cell 
    32 // did not move and the size was increased.
    33 // - The heap is checked to verify that no cells remain allocated after the 
    34 // tests are complete.
    35 // Platforms/Drives/Compatibility:
    36 // All
    37 // Assumptions/Requirement/Pre-requisites:
    38 // Failures and causes:
    39 // Base Port information:
    40 // 
    41 //
    42 
    43 #include <e32test.h>
    44 #include <e32hal.h>
    45 #include <e32def.h>
    46 #include <e32def_private.h>
    47 
    48 // Needed for KHeapShrinkHysRatio which is now ROM 'patchdata'
    49 #include "TestRHeapShrink.h"
    50 
    51 #define DECL_GET(T,x)		inline T x() const {return i##x;}
    52 #define DECL_GET2(T,x,y)	inline T y() const {return i##x;}
    53 
    54 
    55 #ifdef __EABI__
    56        IMPORT_D extern const TInt KHeapMinCellSize;
    57 #else
    58        const TInt KHeapMinCellSize = 0;
    59 #endif
    60 
    61 RTest test(_L("T_HEAP2"));
    62 
    63 #define	TEST_ALIGN(p,a)		test((TLinAddr(p)&((a)-1))==0)
    64 
    65 struct STestCell
    66 	{
    67 	enum {EMagic = 0xb8aa3b29};
    68 
    69 	TUint32 iLength;
    70 	TUint32 iData[1];
    71 
    72 	void Set(TInt aLength);
    73 	void Verify(TInt aLength);
    74 	void Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength);
    75 	};
    76 
    77 void STestCell::Set(TInt aLength)
    78 	{
    79 	TInt i;
    80 	TUint32 x = (TUint32)this ^ (TUint32)aLength ^ (TUint32)EMagic;
    81 	aLength -= RHeap::EAllocCellSize;
    82 	if (aLength==0)
    83 		return;
    84 	iLength = x;
    85 	aLength /= sizeof(TUint32);
    86 	for (i=0; i<aLength-1; ++i)
    87 		{
    88 		x *= 69069;
    89 		x += 41;
    90 		iData[i] = x;
    91 		}
    92 	}
    93 
    94 void STestCell::Verify(TInt aLength)
    95 	{
    96 	Verify(this, aLength, aLength);
    97 	}
    98 
    99 void STestCell::Verify(const TAny* aInitPtr, TInt aInitLength, TInt aLength)
   100 	{
   101 	TInt i;
   102 	TUint32 x = (TUint32)aInitPtr ^ (TUint32)aInitLength ^ (TUint32)EMagic;
   103 	aLength -= RHeap::EAllocCellSize;
   104 	if (aLength==0)
   105 		return;
   106 	test(iLength == x);
   107 	aLength /= sizeof(TUint32);
   108 	for (i=0; i<aLength-1; ++i)
   109 		{
   110 		x *= 69069;
   111 		x += 41;
   112 		test(iData[i] == x);
   113 		}
   114 	}
   115 
   116 class RTestHeap : public RHeap
   117 	{
   118 public:
   119 	DECL_GET(TInt,AccessCount)
   120 	DECL_GET(TInt,HandleCount)
   121 	DECL_GET(TInt*,Handles)
   122 	DECL_GET(TUint32,Flags)
   123 	DECL_GET(TInt,CellCount)
   124 	DECL_GET(TInt,TotalAllocSize)
   125 	DECL_GET(TInt,MinLength)
   126 	DECL_GET(TInt,Offset)
   127 	DECL_GET(TInt,GrowBy)
   128 	DECL_GET(TInt,ChunkHandle)
   129 	DECL_GET2(const RFastLock&,Lock,LockRef)
   130 	DECL_GET(TUint8*,Top)
   131 	DECL_GET(TInt,Align)
   132 	DECL_GET(TInt,MinCell)
   133 	DECL_GET(TInt,PageSize)
   134 	DECL_GET2(const SCell&,Free,FreeRef)
   135 public:
   136 	TInt CheckAllocatedCell(const TAny* aCell) const;
   137 	void FullCheckAllocatedCell(const TAny* aCell) const;
   138 	TAny* TestAlloc(TInt aSize);
   139 	void TestFree(TAny* aPtr);
   140 	TAny* TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0);
   141 	void FullCheck();
   142 	static void WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen);
   143 	TInt FreeCellLen(const TAny* aPtr) const;
   144 	static RTestHeap* FixedHeap(TInt aMaxLength, TInt aAlign=0, TBool aSingleThread=ETrue);
   145 	void TakeChunkOwnership(RChunk aChunk);
   146 	TInt LastFreeCellLen(void) const;
   147 	TInt CalcComp(TInt aCompSize);
   148 	void ForceCompress(TInt aFreed);
   149 	};
   150 
   151 TInt RTestHeap::CheckAllocatedCell(const TAny* aCell) const
   152 	{
   153 	SCell* pC = GetAddress(aCell);
   154 	TInt len = pC->len;
   155 	TUint8* pEnd = (TUint8*)pC + len;
   156 	TEST_ALIGN(aCell, iAlign);
   157 	TEST_ALIGN(len, iAlign);
   158 	test(len >= iMinCell);
   159 	test((TUint8*)pC>=iBase && pEnd<=iTop);
   160 	return len;
   161 	}
   162 
   163 void RTestHeap::FullCheckAllocatedCell(const TAny* aCell) const
   164 	{
   165 	((STestCell*)aCell)->Verify(CheckAllocatedCell(aCell));
   166 	}
   167 
   168 TAny* RTestHeap::TestAlloc(TInt aSize)
   169 	{
   170 	TAny* p = Alloc(aSize);
   171 	if (p)
   172 		{
   173 		TInt len = CheckAllocatedCell(p);
   174 		test((len-RHeap::EAllocCellSize)>=aSize);
   175 		((STestCell*)p)->Set(len);
   176 		}
   177 	return p;
   178 	}
   179 
   180 void RTestHeap::TestFree(TAny* aPtr)
   181 	{
   182 	if (aPtr)
   183 		FullCheckAllocatedCell(aPtr);
   184 	Free(aPtr);
   185 	}
   186 
   187 TAny* RTestHeap::TestReAlloc(TAny* aPtr, TInt aSize, TInt aMode)
   188 	{
   189 	TInt old_len = aPtr ? CheckAllocatedCell(aPtr) : 0;
   190 	if (aPtr)
   191 		((STestCell*)aPtr)->Verify(old_len);
   192 	TAny* p = ReAlloc(aPtr, aSize, aMode);
   193 	if (!p)
   194 		{
   195 		((STestCell*)aPtr)->Verify(old_len);
   196 		return p;
   197 		}
   198 	TInt new_len = CheckAllocatedCell(p);
   199 	test((new_len-RHeap::EAllocCellSize)>=aSize);
   200 	if (p == aPtr)
   201 		{
   202 		((STestCell*)p)->Verify(p, old_len, Min(old_len, new_len));
   203 		if (new_len != old_len)
   204 			((STestCell*)p)->Set(new_len);
   205 		return p;
   206 		}
   207 	test(!(aMode & ENeverMove));
   208 	test((new_len > old_len) || (aMode & EAllowMoveOnShrink));
   209 	if (old_len)
   210 		((STestCell*)p)->Verify(aPtr, old_len, Min(old_len, new_len));
   211 	if (new_len != old_len)
   212 		((STestCell*)p)->Set(new_len);
   213 	return p;
   214 	}
   215 
   216 struct SHeapCellInfo
   217 	{
   218 	RTestHeap* iHeap;
   219 	TInt iTotalAlloc;
   220 	TInt iTotalAllocSize;
   221 	TInt iTotalFree;
   222 	TUint8* iNextCell;
   223 	};
   224 
   225 void RTestHeap::WalkFullCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen)
   226 	{
   227 	(void)aCell;
   228 	::SHeapCellInfo& info = *(::SHeapCellInfo*)aPtr;
   229 	switch(aType)
   230 		{
   231 		case EGoodAllocatedCell:
   232 			{
   233 			test(aCell == info.iNextCell);
   234 			TInt len = ((SCell*)aCell)->len;
   235 			test(len == aLen);
   236 			info.iNextCell += len;
   237 			++info.iTotalAlloc;
   238 			info.iTotalAllocSize += (aLen-EAllocCellSize);
   239 			STestCell* pT = (STestCell*)((TUint8*)aCell + EAllocCellSize);
   240 			pT->Verify(len);
   241 			break;
   242 			}
   243 		case EGoodFreeCell:
   244 			{
   245 			test(aCell == info.iNextCell);
   246 			TInt len = ((SCell*)aCell)->len;
   247 			test(len == aLen);
   248 			info.iNextCell += len;
   249 			++info.iTotalFree;
   250 			break;
   251 			}
   252 		default:
   253 			test.Printf(_L("TYPE=%d ??\n"),aType);
   254 			test(0);
   255 			break;
   256 		}
   257 	}
   258 
   259 void RTestHeap::FullCheck()
   260 	{
   261 	::SHeapCellInfo info;
   262 	Mem::FillZ(&info, sizeof(info));
   263 	info.iHeap = this;
   264 	info.iNextCell = iBase;
   265 	DebugFunction(EWalk, (TAny*)&WalkFullCheckCell, &info);
   266 	test(info.iNextCell == iTop);
   267 	test(info.iTotalAlloc == iCellCount);
   268 	test(info.iTotalAllocSize == iTotalAllocSize);
   269 	}
   270 
   271 TInt RTestHeap::FreeCellLen(const TAny* aPtr) const
   272 	{
   273 	SCell* p = iFree.next;
   274 	SCell* q = (SCell*)((TUint8*)aPtr - EAllocCellSize);
   275 	for (; p && p!=q; p = p->next) {}
   276 	if (p == q)
   277 		return p->len - EAllocCellSize;
   278 	return -1;
   279 	}
   280 
   281 TInt RTestHeap::LastFreeCellLen(void) const
   282 	{
   283 	SCell* p = iFree.next;
   284 	if (p==NULL)
   285 		return -1;	
   286 	for (; p->next; p=p->next){}
   287 	return p->len;
   288 	}
   289 
   290 
   291 /** Checks whether a call to Compress() will actually perform a reduction 
   292 	of the heap.
   293 	Relies on the free last cell on the heap being cell that has just been freed
   294 	plus any extra.
   295 	Intended for use by t_heap2.cpp - DoTest4().  
   296 	@param aFreedSize The size in bytes of the cell that was freed
   297 */
   298 TInt RTestHeap::CalcComp(TInt aFreedSize)
   299 	{	
   300 	TInt largestCell=0;
   301 	largestCell = LastFreeCellLen();
   302 	// if the largest cell is too small or it would have been compressed by the
   303 	// free operation then return 0.
   304 	if (largestCell < iPageSize || aFreedSize >= KHeapShrinkHysRatio*(iGrowBy>>8))
   305 		{
   306 		return 0;			
   307 		}
   308 		else
   309 		{
   310 		return _ALIGN_DOWN(aFreedSize,iPageSize);
   311 		}	
   312 	}
   313 	
   314 /** compress the heap if the KHeapShrinkRatio is too large for what we are
   315 	expecting in DoTest4().
   316 */
   317 void RTestHeap::ForceCompress(TInt aFreed)
   318 	{	
   319 	if (aFreed < KHeapShrinkHysRatio*(iGrowBy>>8))
   320 		{
   321 		Compress();
   322 		}
   323 	}
   324 RTestHeap* RTestHeap::FixedHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread)
   325 	{
   326 	RChunk c;
   327 	TInt bottom = 0x40000;
   328 	TInt top = bottom + aMaxLength;
   329 	TInt r = c.CreateDisconnectedLocal(bottom, top, top + bottom, EOwnerThread);
   330 	if (r!=KErrNone)
   331 		return NULL;
   332 	TUint8* base = c.Base() + bottom;
   333 	RTestHeap* h = (RTestHeap*)UserHeap::FixedHeap(base, aMaxLength, aAlign, aSingleThread);
   334 	if (!aAlign)
   335 		aAlign = RHeap::ECellAlignment;
   336 	test((TUint8*)h == base);
   337 	test(h->AccessCount() == 1);
   338 	test(h->HandleCount() == (aSingleThread ? 0 : 1));
   339 	test(h->Handles() == (aSingleThread ? NULL : (TInt*)&h->LockRef()));
   340 	test(h->Flags() == TUint32(RAllocator::EFixedSize | (aSingleThread ? RAllocator::ESingleThreaded : 0)));
   341 	test(h->CellCount() == 0);
   342 	test(h->TotalAllocSize() == 0);
   343 	test(h->MaxLength() == aMaxLength);
   344 	test(h->MinLength() == h->Top() - (TUint8*)h);
   345 	test(h->Offset() == 0);
   346 	test(h->GrowBy() == 0);
   347 	test(h->ChunkHandle() == 0);
   348 	test(h->Align() == aAlign);
   349 	TInt min_cell = _ALIGN_UP((KHeapMinCellSize + Max((TInt)RHeap::EAllocCellSize, (TInt)RHeap::EFreeCellSize)), aAlign);
   350 	TInt hdr_len = _ALIGN_UP(sizeof(RHeap) + RHeap::EAllocCellSize, aAlign) - RHeap::EAllocCellSize;
   351 	TInt user_len = _ALIGN_DOWN(aMaxLength - hdr_len, aAlign);
   352 	test(h->Base() == base + hdr_len);
   353 	test(h->MinCell() == min_cell);
   354 	test(h->Top() - h->Base() == user_len);
   355 	test(h->FreeRef().next == (RHeap::SCell*)h->Base());
   356 	h->TakeChunkOwnership(c);
   357 	return h;
   358 	}
   359 
   360 void RTestHeap::TakeChunkOwnership(RChunk aChunk)
   361 	{
   362 	iChunkHandle = aChunk.Handle();
   363 	++iHandleCount;
   364 	iHandles = &iChunkHandle;
   365 	}
   366 
   367 
   368 #define	ACCESS_COUNT(h)		(((RTestHeap*)h)->AccessCount())
   369 #define	HANDLE_COUNT(h)		(((RTestHeap*)h)->HandleCount())
   370 #define	HANDLES(h)			(((RTestHeap*)h)->Handles())
   371 #define	FLAGS(h)			(((RTestHeap*)h)->Flags())
   372 #define	CELL_COUNT(h)		(((RTestHeap*)h)->CellCount())
   373 #define	TOTAL_ALLOC_SIZE(h)	(((RTestHeap*)h)->TotalAllocSize())
   374 #define	MIN_LENGTH(h)		(((RTestHeap*)h)->MinLength())
   375 #define	OFFSET(h)			(((RTestHeap*)h)->Offset())
   376 #define	GROW_BY(h)			(((RTestHeap*)h)->GrowBy())
   377 #define	CHUNK_HANDLE(h)		(((RTestHeap*)h)->ChunkHandle())
   378 #define	LOCK_REF(h)			(((RTestHeap*)h)->LockRef())
   379 #define	TOP(h)				(((RTestHeap*)h)->Top())
   380 #define	ALIGN(h)			(((RTestHeap*)h)->Align())
   381 #define	MIN_CELL(h)			(((RTestHeap*)h)->MinCell())
   382 #define	PAGE_SIZE(h)		(((RTestHeap*)h)->PageSize())
   383 #define	FREE_REF(h)			(((RTestHeap*)h)->FreeRef())
   384 
   385 void DoTest1(RHeap* aH)
   386 	{
   387 	RTestHeap* h = (RTestHeap*)aH;
   388 	test.Printf(_L("Test Alloc: min=%x max=%x align=%d growby=%d\n"),
   389 						h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
   390 	TInt l;
   391 	TAny* p = NULL;
   392 	TUint8* next = h->Base();
   393 	TUint8* top = h->Top();
   394 	TUint8* limit = (TUint8*)h + h->MaxLength();
   395 	TBool fixed = h->Flags() & RAllocator::EFixedSize;
   396 	for (l=1; l<=1024; ++l)
   397 		{
   398 		TInt remain1 = top - next;
   399 		TInt xl1 = _ALIGN_UP(Max((l+RHeap::EAllocCellSize), h->MinCell()), h->Align());
   400 		p = h->TestAlloc(l);
   401 		if ( (fixed && remain1 < xl1) || (next + xl1 > limit) )
   402 			{
   403 			test(p == NULL);
   404 			test(top == h->Top());
   405 			test.Printf(_L("Alloc failed at l=%d next=%08x\n"), l, next);
   406 			break;
   407 			}
   408 		test(p == next + RHeap::EAllocCellSize);
   409 		if (xl1 > remain1)
   410 			{
   411 			// no room for this cell
   412 			TInt g = h->GrowBy();
   413 			while (xl1 > remain1)
   414 				{
   415 				top += g;
   416 				remain1 += g;
   417 				}
   418 			}
   419 		test(top == h->Top());
   420 		if (xl1 + h->MinCell() > remain1)
   421 			{
   422 			// this cell fits but remainder is too small or nonexistent
   423 			xl1 = top - next;
   424 			next = top;
   425 			test(h->FreeRef().next == NULL);
   426 			}
   427 		else
   428 			{
   429 			// this cell fits and remainder can be reused
   430 			next += xl1;
   431 			}
   432 		test(aH->AllocLen(p) == xl1 - RHeap::EAllocCellSize);
   433 		}
   434 	h->FullCheck();
   435 	}
   436 
   437 void DoTest2(RHeap* aH)
   438 	{
   439 	RTestHeap* h = (RTestHeap*)aH;
   440 	test.Printf(_L("Test Free: min=%x max=%x align=%d growby=%d\n"),
   441 						h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
   442 	TInt al;
   443 	TInt min = h->MinCell();
   444 	TBool pad = EFalse;
   445 	for (al=1; al<256; (void)((pad=!pad)!=0 || (al+=al+1)) )
   446 		{
   447 		TAny* p[32];
   448 		TInt last_len = 0;
   449 		TAny* last = NULL;
   450 		TInt i;
   451 		test.Printf(_L("al=%d pad=%d\n"), al, pad);
   452 		TUint8* top=0;
   453 		TAny* spare=0;
   454 		TBool heapReduced = EFalse;
   455 		for (i=0; i<32; ++i)
   456 			{
   457 			// Check whether the cell created for the allocation of al would end up
   458 			// including extra bytes from the last free cell that aren't enough
   459 			// to create a new free cell.
   460 			top = h->Top();
   461 			TInt freeLen=h->LastFreeCellLen();
   462 			TInt actualAllocBytes = Max(_ALIGN_UP(al + RHeap::EAllocCellSize, h->Align()), min);
   463 			TInt remainingBytes = freeLen - actualAllocBytes;
   464 			if (remainingBytes < min)
   465 				{
   466 				// Force the heap to grow so that once this allocation is freed
   467 				// the free cell left will be large enough to include the al allocation
   468 				// and to create a new free cell if necessary.
   469 				actualAllocBytes = _ALIGN_UP(actualAllocBytes + min, h->Align());
   470 				TAny* q = h->TestAlloc(actualAllocBytes);
   471 				// Check heap has grown
   472 				test(top < h->Top());
   473 				top = h->Top();
   474 				test(q!=NULL);
   475 				// Have grown the heap so allocate a cell as a place holder to stop
   476 				// the heap being shrunk and the actual cell we want to allocate from being the
   477 				// wrong size
   478 				spare=h->TestAlloc(8);
   479 				h->TestFree(q);
   480 				// Ensure heap wasn't shrunk after free
   481 				test(top == h->Top());
   482 				}
   483 			top = h->Top();
   484 			// Allocate the new 
   485 			p[i] = h->TestAlloc(al);
   486 			test(p[i]!=NULL);
   487 			if (remainingBytes < min)
   488 				{// now safe to free any padding as p[i] now allocated and its size can't change
   489 				h->TestFree(spare);
   490 				}
   491 			TInt tmp1=h->AllocLen(p[i]);
   492 			TInt tmp2=Max(_ALIGN_UP(al+RHeap::EAllocCellSize,h->Align()), min)-RHeap::EAllocCellSize;
   493 			test(tmp1 == tmp2);
   494 			}
   495 		last = (TUint8*)p[31] + _ALIGN_UP(Max((al + RHeap::EAllocCellSize), min), h->Align());
   496 		last_len = h->FreeCellLen(last);
   497 		test(last_len > 0);
   498 		if (pad)
   499 			{
   500 			test(h->TestAlloc(last_len) == last);
   501 			test(h->FreeRef().next == NULL);
   502 			}
   503 		else
   504 			last = NULL;
   505 		top = h->Top();
   506 		for (i=0,heapReduced=EFalse; i<32; ++i)
   507 			{
   508 			h->TestFree(p[i]);
   509 			TInt fl = h->FreeCellLen(p[i]);
   510 			TInt xfl = _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
   511 			if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
   512 				{
   513 				top = h->Top();
   514 				heapReduced = ETrue;
   515 				}
   516 
   517 			if (i < 31 || pad)
   518 				test(fl == xfl);
   519 			else
   520 				{
   521 				if (!heapReduced)
   522 					test(fl == xfl + RHeap::EAllocCellSize + last_len);
   523 				else
   524 					{
   525 					heapReduced = EFalse;
   526 					}
   527 				}
   528 			test(h->TestAlloc(al)==p[i]);
   529 			}
   530 		for (i=0,heapReduced=EFalse; i<31; ++i)
   531 			{
   532 			TInt j = i+1;
   533 			TUint8* q;
   534 			// Free to adjacent cells and check that the free cell left is the combined
   535 			// size of the 2 adjacent cells just freed
   536 			h->TestFree(p[i]);
   537 			h->TestFree(p[j]);
   538 			TInt fl = h->FreeCellLen(p[i]);
   539 			if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
   540 				{
   541 				top = h->Top();
   542 				heapReduced = ETrue;
   543 				}
   544 			TInt xfl = 2 * _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
   545 			if (j < 31 || pad)
   546 				test(fl == xfl);
   547 			else
   548 				{
   549 				if (!heapReduced)
   550 					test(fl == xfl + RHeap::EAllocCellSize + last_len);
   551 				else
   552 					{
   553 					heapReduced = EFalse;
   554 					}
   555 				}
   556 			test(h->FreeCellLen(p[j]) < 0);
   557 			test(h->TestAlloc(fl)==p[i]);
   558 			test(h->Top() == top);
   559 			h->TestFree(p[i]);
   560 			test(h->FreeCellLen(p[i]) == fl);
   561 			// test when you alloc a cell that is larger than cells just freed
   562 			// that its position is not the same as the freed cells
   563 			// will hold for all cells except top/last one
   564 			if (j < 31 && !pad && fl < last_len)
   565 				{
   566 				q = (TUint8*)h->TestAlloc(fl+1);
   567 				if (h->Top() > top)
   568 					top = h->Top();
   569 				test(h->Top() == top);
   570 				test(q > p[i]);
   571 				h->TestFree(q);
   572 				if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
   573 					{
   574 					top = h->Top();
   575 					heapReduced = ETrue;
   576 					}
   577 				}
   578 			// check cell that is just smaller than space but not small enough 
   579 			// for a new free cell to be created, is the size of whole free cell
   580 			test(h->TestAlloc(fl-min+1)==p[i]);
   581 			test(h->Top() == top);
   582 			test(h->AllocLen(p[i])==fl);
   583 			h->TestFree(p[i]);
   584 			// Check cell that is small enough for new free cell and alloc'd cell to be
   585 			// created at p[i] cell is created at p[i]
   586 			test(h->TestAlloc(fl-min)==p[i]);
   587 			test(h->Top() == top);
   588 			// check free cell is at expected position
   589 			q = (TUint8*)p[i] + fl - min + RHeap::EAllocCellSize;
   590 			test(h->FreeCellLen(q) == min - RHeap::EAllocCellSize);
   591 			// alloc 0 length cell at q, will work as new cell of min length will be created
   592 			test(h->TestAlloc(0) == q);
   593 			test(h->Top() == top);
   594 			h->TestFree(p[i]);
   595 			test(h->FreeCellLen(p[i]) == fl - min);
   596 			h->TestFree(q);
   597 			// again check free cells are combined
   598 			test(h->FreeCellLen(q) < 0);
   599 			test(h->FreeCellLen(p[i]) == fl);
   600 			// check reallocating the cells places them back to same positions
   601 			test(h->TestAlloc(al)==p[i]);
   602 			test(h->Top() == top);
   603 			test(h->TestAlloc(al)==p[j]);
   604 			test(h->Top() == top);
   605 			if (pad)
   606 				test(h->FreeRef().next == NULL);
   607 			}
   608 		for (i=0,heapReduced=EFalse; i<30; ++i)
   609 			{
   610 			TInt j = i+1;
   611 			TInt k = i+2;
   612 			TUint8* q;
   613 			// Free 3 adjacent cells and check free cell created is combined size
   614 			h->TestFree(p[i]);
   615 			h->TestFree(p[k]);
   616 			h->TestFree(p[j]);
   617 			h->FullCheck();
   618 			if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
   619 				{
   620 				top = h->Top();
   621 				heapReduced = ETrue;
   622 				}
   623 			TInt fl = h->FreeCellLen(p[i]);
   624 			TInt xfl = 3 * _ALIGN_UP(Max((al + RHeap::EAllocCellSize), h->MinCell()), h->Align()) - RHeap::EAllocCellSize;
   625 			if (k < 31 || pad)
   626 				test(fl == xfl);
   627 			else
   628 				{
   629 				if (!heapReduced)
   630 					test(fl == xfl + RHeap::EAllocCellSize + last_len);
   631 				else
   632 					{
   633 					heapReduced = EFalse;
   634 					}
   635 				}
   636 			test(h->FreeCellLen(p[j]) < 0);
   637 			test(h->FreeCellLen(p[k]) < 0);
   638 			//ensure created free cell is allocated to new cell of free cell size
   639 			test(h->TestAlloc(fl)==p[i]);
   640 			test(h->Top() == top);
   641 			h->TestFree(p[i]);
   642 			test(h->FreeCellLen(p[i]) == fl);
   643 			if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
   644 				top = h->Top();
   645 			if (k < 31 && !pad && fl < last_len)
   646 				{
   647 				// Test new cell one larger than free cell size is allocated somewhere else
   648 				q = (TUint8*)h->TestAlloc(fl+1);
   649 				if (h->Top() > top)
   650 					top = h->Top();
   651 				test(h->Top() == top); 
   652 				test(q > p[i]);
   653 				h->TestFree(q);
   654 				if (h->Top() < top) // heap was reduced due to small KHeapShrinkHysRatio and big KHeapMinCellSize
   655 					{
   656 					top = h->Top();
   657 					heapReduced = ETrue;
   658 					}
   659 				}
   660 			// check allocating cell just smaller than free cell size but
   661 			// too large for neew free cell to be created, is size of whole free cell
   662 			test(h->TestAlloc(fl-min+1)==p[i]);
   663 			test(h->Top() == top);
   664 			test(h->AllocLen(p[i])==fl);
   665 			h->TestFree(p[i]);
   666 			// ensure free cell is created this time as well as alloc'd cell
   667 			test(h->TestAlloc(fl-min)==p[i]);
   668 			test(h->Top() == top);
   669 			q = (TUint8*)p[i] + fl - min + RHeap::EAllocCellSize;
   670 			test(h->FreeCellLen(q) == min - RHeap::EAllocCellSize);
   671 			test(h->TestAlloc(0) == q);
   672 			test(h->Top() == top);
   673 			h->TestFree(p[i]);
   674 			test(h->FreeCellLen(p[i]) == fl - min);
   675 			h->TestFree(q);
   676 			test(h->FreeCellLen(q) < 0);
   677 			test(h->FreeCellLen(p[i]) == fl);
   678 			// realloc all cells and check heap not expanded
   679 			test(h->TestAlloc(al)==p[i]);
   680 			test(h->Top() == top);
   681 			test(h->TestAlloc(al)==p[j]);
   682 			test(h->Top() == top);
   683 			test(h->TestAlloc(al)==p[k]);
   684 			test(h->Top() == top);
   685 			// If padding than no space should left on heap
   686 			if (pad)
   687 				test(h->FreeRef().next == NULL);
   688 			}
   689 		// when padding this will free padding from top of heap
   690 		h->TestFree(last);
   691 		}
   692 	h->FullCheck();
   693 	}
   694 
   695 void DoTest3(RHeap* aH)
   696 	{
   697 	RTestHeap* h = (RTestHeap*)aH;
   698 	test.Printf(_L("Test ReAlloc: min=%x max=%x align=%d growby=%d\n"),
   699 						h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
   700 	// allocate continuous heap cell, then free them and reallocate again
   701 	TInt al;
   702 	for (al=1; al<256; al+=al+1)
   703 		{
   704 		TAny* p0 = h->TestAlloc(al);
   705 		TInt al0 = h->AllocLen(p0);
   706 		h->TestFree(p0);
   707 		TAny* p1 = h->TestReAlloc(NULL, al, 0);
   708 		TInt al1 = h->AllocLen(p1);
   709 		test(p1 == p0);
   710 		test(al1 == al0);
   711 		h->TestFree(p1);
   712 		TAny* p2 = h->TestAlloc(1);
   713 		TAny* p3 = h->TestReAlloc(p2, al, 0);
   714 		test(p3 == p0);
   715 		TInt al3 = h->AllocLen(p3);
   716 		test(al3 == al0);
   717 		h->TestFree(p3);
   718 		TAny* p4 = h->TestAlloc(1024);
   719 		TAny* p5 = h->TestReAlloc(p4, al, 0);
   720 		test(p5 == p0);
   721 		TInt al5 = h->AllocLen(p5);
   722 		test(al5 == al0);
   723 		h->TestFree(p5);
   724 		}
   725 	TInt i;
   726 	TInt j;
   727 	for (j=0; j<30; j+=3)
   728 		{
   729 		TAny* p[30];
   730 		TInt ala[30];
   731 		TInt fla[30];
   732 		h->Reset();
   733 		for (i=0; i<30; ++i)
   734 			{
   735 			p[i] = h->TestAlloc(8*i*i);
   736 			ala[i] = h->AllocLen(p[i]);
   737 			fla[i] = 0;
   738 			}
   739 		for (i=1; i<30; i+=3)
   740 			{
   741 			h->TestFree(p[i]);
   742 			fla[i] = h->FreeCellLen(p[i]);
   743 			test(fla[i] == ala[i]);
   744 			test(h->FreeCellLen(p[i-1]) < 0);
   745 			test(h->FreeCellLen(p[i+1]) < 0);
   746 			}
   747 		h->FullCheck();
   748 		TInt al1 = _ALIGN_UP(Max((RHeap::EAllocCellSize + 1), h->MinCell()), h->Align());
   749 		// adjust al1 for some case when reallocated heap cell will not be shrinked because remainder will not big enough
   750 		// to form a new free cell due to a big KHeapMinCellSize value
   751 		TInt alaj = ala[j] + RHeap::EAllocCellSize;
   752 		if (al1 < alaj && alaj - al1 < h->MinCell())
   753 			al1 = alaj;
   754 		TAny* p1 = h->TestReAlloc(p[j], 1, RHeap::ENeverMove);
   755 		test(p1 == p[j]);
   756 		test(h->AllocLen(p1) == al1 - RHeap::EAllocCellSize);
   757 		TAny* p1b = (TUint8*)p1 + al1;
   758 		test(h->FreeCellLen(p1b) == fla[j+1] + RHeap::EAllocCellSize + ala[j] - al1);
   759 		TInt l2 = ala[j] + fla[j+1] + RHeap::EAllocCellSize; // max without moving
   760 		TInt l3 = l2 - h->MinCell();
   761 		TAny* p3 = h->TestReAlloc(p[j], l3, RHeap::ENeverMove);
   762 		test(p3 == p[j]);
   763 		TAny* p3b = (TUint8*)p3 + h->AllocLen(p3) + RHeap::EAllocCellSize;
   764 		test(h->FreeCellLen(p3b) == h->MinCell() - RHeap::EAllocCellSize);
   765 		TAny* p2 = h->TestReAlloc(p[j], l2, RHeap::ENeverMove);
   766 		test(p2 == p[j]);
   767 		test(h->AllocLen(p2) == l2);
   768 		TAny* p4 = h->TestReAlloc(p[j], l2+1, RHeap::ENeverMove);
   769 		test(p4 == NULL);
   770 		test(h->AllocLen(p2) == l2);
   771 		TAny* p5 = h->TestReAlloc(p[j], l2+1, 0);
   772 		TInt k = 0;
   773 		for (; k<30 && fla[k] <= l2; ++k) {}
   774 		if (k < 30)
   775 			test(p5 == p[k]);
   776 		else
   777 			test(p5 >= (TUint8*)p[29] + ala[29]);
   778 		test(h->FreeCellLen(p2) == ala[j] + ala[j+1] + RHeap::EAllocCellSize);
   779 		TInt ali = _ALIGN_UP(RHeap::EAllocCellSize,h->Align());
   780 		TAny* p6b = (TUint8*)p[j+2] + ala[j+2] - ali + RHeap::EAllocCellSize;
   781 		test(h->FreeCellLen(p6b) < 0);
   782 		TAny* p6 = h->TestReAlloc(p[j+2], ala[j+2] - ali , 0);
   783 		test(p6 == p[j+2]);
   784 		if (h->AllocLen(p6) != ala[j+2]) // allocated heap cell size changed
   785 			test(h->FreeCellLen(p6b) == h->MinCell() - RHeap::EAllocCellSize);
   786 		TInt g = h->GrowBy();
   787 		TAny* p7 = h->TestReAlloc(p5, 8*g, 0);
   788 		test(p7 >= p5);
   789 		TUint8* p8 = (TUint8*)p7 - RHeap::EAllocCellSize + al1;
   790 		TUint8* p9 = (TUint8*)_ALIGN_UP(TLinAddr(p8), h->PageSize());
   791 		if (p9-p8 < h->MinCell())
   792 			p9 += h->PageSize();
   793 		TAny* p7b = h->TestReAlloc(p7, 1, 0);
   794 		test(p7b == p7);
   795 		test(h->Top() + (RHeap::EAllocCellSize & (h->Align()-1)) == p9);
   796 
   797 		h->FullCheck();
   798 		}
   799 	}
   800 
   801 // Test compression
   802 // {1 free cell, >1 free cell} x {reduce cell, eliminate cell, reduce cell but too small}
   803 //
   804 void DoTest4(RHeap* aH)
   805 	{
   806 	RTestHeap* h = (RTestHeap*)aH;
   807 	test.Printf(_L("Test Compress: min=%x max=%x align=%d growby=%d\n"),
   808 						h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
   809 	TInt page_size;
   810 	UserHal::PageSizeInBytes(page_size);
   811 	test(page_size == h->PageSize());
   812 	TInt g = h->GrowBy();
   813 	TEST_ALIGN(g, page_size);
   814 	test(g >= page_size);
   815 	RChunk c;
   816 	c.SetHandle(h->ChunkHandle());
   817 	TInt align = h->Align();
   818 	TInt minc = h->MinCell();
   819 
   820 	TInt orig_size = c.Size();
   821 	TUint8* orig_top = h->Top();
   822 
   823 	// size in bytes that last free cell on the top of the heap must be 
   824 	// before the heap will be shrunk, size must include the no of bytes to
   825 	// store the cell data/header i.e RHeap::EAllocCellSize
   826 	TInt shrinkThres = KHeapShrinkHysRatio*(g>>8);
   827 
   828 	TInt pass;
   829 	for (pass=0; pass<2; ++pass)
   830 		{
   831 		TUint8* p0 = (TUint8*)h->TestAlloc(4);
   832 		test(p0 == h->Base() + RHeap::EAllocCellSize);
   833 		TInt l1 = h->Top() - (TUint8*)h->FreeRef().next;
   834 		TEST_ALIGN(l1, align);
   835 		l1 -= RHeap::EAllocCellSize;
   836 		TUint8* p1;
   837 		// Grow heap by 2*iGrowBy bytes
   838 		p1 = (TUint8*)h->TestAlloc(l1 + 2*g);
   839 		test(p1 == p0 + h->AllocLen(p0) + RHeap::EAllocCellSize);
   840 		test(h->Top() - orig_top == 2*g);
   841 		test(c.Size() - orig_size == 2*g);
   842 		// May compress heap, may not
   843 		h->TestFree(p1);
   844 		h->ForceCompress(2*g);
   845 		test(h->Top() == orig_top);
   846 		test(c.Size() == orig_size);
   847 		test((TUint8*)h->FreeRef().next == p1 - RHeap::EAllocCellSize);
   848 		h->FullCheck();
   849 		//if KHeapShrinkHysRatio is > 2.0 then heap compression will occur here
   850 		test(h->Compress() == 0);
   851 		test(h->TestAlloc(l1) == p1);
   852 		test(h->FreeRef().next == NULL);
   853 		if (pass)
   854 			h->TestFree(p0);	// leave another free cell on second pass
   855 		TInt l2 = g - RHeap::EAllocCellSize;
   856 		// Will grow heap by iGrowBy bytes
   857 		TUint8* p2 = (TUint8*)h->TestAlloc(l2);
   858 		test(p2 == orig_top + RHeap::EAllocCellSize);
   859 		test(h->Top() - orig_top == g);
   860 		test(c.Size() - orig_size == g);
   861 		// may or may not compress heap
   862 		h->TestFree(p2);
   863 		if (l2+RHeap::EAllocCellSize >= shrinkThres)
   864 			{
   865 			// When KHeapShrinkRatio small enough heap will have been compressed
   866 			test(h->Top() == orig_top);			
   867 			if (pass)
   868 				{
   869 				test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
   870 				test((TUint8*)h->FreeRef().next->next == NULL);
   871 				}
   872 			else
   873 				test((TUint8*)h->FreeRef().next == NULL);
   874 			}
   875 		else
   876 			{			
   877 			test(h->Top() - orig_top == g);
   878 			if (pass)
   879 				{
   880 				test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
   881 				test((TUint8*)h->FreeRef().next->next == orig_top);
   882 				}
   883 			else
   884 				test((TUint8*)h->FreeRef().next == orig_top);
   885 			}
   886 		// this compress will only do anything if the KHeapShrinkRatio is large 
   887 		// enough to introduce hysteresis otherwise the heap would have been compressed 
   888 		// by the free operation itself
   889 		TInt tmp1,tmp2;
   890 		tmp2=h->CalcComp(g);
   891 		tmp1=h->Compress();
   892 		test(tmp1 == tmp2);
   893 		test(h->Top() == orig_top);
   894 		test(c.Size() == orig_size);
   895 		h->FullCheck();
   896 		// shouldn't compress heap as already compressed
   897 		test(h->Compress() == 0);
   898 		//grow heap by iGrowBy bytes
   899 		test(h->TestAlloc(l2) == p2);
   900 		//grow heap by iGrowBy bytes
   901 		TUint8* p3 = (TUint8*)h->TestAlloc(l2);
   902 		test(p3 == p2 + g);
   903 		test(h->Top() - orig_top == 2*g);
   904 		test(c.Size() - orig_size == 2*g);
   905 		// may or may not reduce heap
   906 		h->TestFree(p2);
   907 		// may or may not reduce heap
   908 		h->TestFree(p3);
   909 		h->ForceCompress(2*g);
   910 		test(h->Top() == orig_top);
   911 		test(c.Size() == orig_size);
   912 		h->FullCheck();
   913 		if (pass)
   914 			{
   915 			test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
   916 			test((TUint8*)h->FreeRef().next->next == NULL);
   917 			}
   918 		else
   919 			test((TUint8*)h->FreeRef().next == NULL);
   920 		//grow heap by iGrowBy bytes
   921 		test(h->TestAlloc(l2) == p2);
   922 		//grow heap by iGrowBy*2 + page size bytes
   923 		test(h->TestAlloc(l2 + g + page_size) == p3);
   924 		test(h->Top() - orig_top == 4*g);
   925 		test(c.Size() - orig_size == 4*g);
   926 		// will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatioDflt
   927 		test(h->TestReAlloc(p3, page_size - RHeap::EAllocCellSize, 0) == p3);
   928 		h->ForceCompress(g+page_size);
   929 		test(h->Top() - orig_top == g + page_size);
   930 		test(c.Size() - orig_size == g + page_size);
   931 		h->FullCheck();
   932 		// will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatio1
   933 		h->TestFree(p2);
   934 		// will compress heap if KHeapShrinkHysRatio <= KHeapShrinkRatio1 && g<=page_size
   935 		// or KHeapShrinkHysRatio >= 2.0 and g==page_size
   936 		h->TestFree(p3);
   937 		// may or may not perform further compression
   938 		tmp1=h->CalcComp(g+page_size);
   939 		tmp2=h->Compress();
   940 		test(tmp1 == tmp2);
   941 		test(h->Top() == orig_top);
   942 		test(c.Size() == orig_size);
   943 		h->FullCheck();
   944 		test(h->TestAlloc(l2 - minc) == p2);
   945 		test(h->TestAlloc(l2 + g + page_size + minc) == p3 - minc);
   946 		test(h->Top() - orig_top == 4*g);
   947 		test(c.Size() - orig_size == 4*g);
   948 		h->TestFree(p3 - minc);
   949 		h->ForceCompress(l2 + g + page_size + minc);
   950 		test(h->Top() - orig_top == g);
   951 		test(c.Size() - orig_size == g);
   952 		h->FullCheck();
   953 		if (pass)
   954 			{
   955 			test((TUint8*)h->FreeRef().next == p0 - RHeap::EAllocCellSize);
   956 			test((TUint8*)h->FreeRef().next->next == p3 - minc - RHeap::EAllocCellSize);
   957 			}
   958 		else
   959 			test((TUint8*)h->FreeRef().next == p3 - minc - RHeap::EAllocCellSize);
   960 		h->TestFree(p2);
   961 		if (l2+RHeap::EAllocCellSize >= shrinkThres)
   962 			{
   963 			// When KHeapShrinkRatio small enough heap will have been compressed
   964 			test(h->Top() == orig_top);
   965 			test(c.Size() - orig_size == 0);
   966 			}
   967 		else
   968 			{
   969 			test(h->Top() - orig_top == g);
   970 			test(c.Size() - orig_size == g);
   971 			}
   972 		h->FullCheck();
   973 		if ( ((TLinAddr)orig_top & (align-1)) == 0)
   974 			{
   975 			TAny* free;
   976 			TEST_ALIGN(p2 - RHeap::EAllocCellSize, page_size);
   977 			// will have free space of g-minc
   978 			test(h->TestAlloc(l2 + minc) == p2);
   979 			test(h->Top() - orig_top == 2*g);
   980 			test(c.Size() - orig_size == 2*g);
   981 			free = pass ? h->FreeRef().next->next : h->FreeRef().next;
   982 			test(free != NULL);
   983 			test(h->TestReAlloc(p2, l2 - 4, 0) == p2);
   984 			TInt freeSp = g-minc + (l2+minc - (l2-4));
   985 			TInt adjust = 0;
   986 			if (freeSp >= shrinkThres && freeSp-page_size >= minc)
   987 				{
   988 				// if page_size is less than growBy (g) then heap will be shrunk
   989 				// by less than a whole g.
   990 				adjust = g-((page_size<g)?page_size:0);
   991 				}
   992 			test(h->Top() - orig_top == 2*g - adjust);
   993 			test(c.Size() - orig_size == 2*g - adjust);
   994 			free = pass ? h->FreeRef().next->next : h->FreeRef().next;
   995 			test(free != NULL);
   996 			TEST_ALIGN(TLinAddr(free)+4, page_size);
   997 			test(h->TestAlloc(l2 + g + page_size + 4) == p3 - 4);
   998 			test(h->Top() - orig_top == 4*g - adjust);
   999 			test(c.Size() - orig_size == 4*g - adjust);
  1000 			h->TestFree(p3 - 4);
  1001 			h->ForceCompress(l2 + g + page_size + 4);
  1002 			test(h->Top() - orig_top == g + page_size);
  1003 			test(c.Size() - orig_size == g + page_size);
  1004 			h->FullCheck();
  1005 			h->TestFree(p2);
  1006 			h->ForceCompress(l2-4);
  1007 			test(h->Compress() == 0);
  1008 			// check heap is grown, will have free space of g-minc
  1009 			test(h->TestAlloc(l2 + minc) == p2);
  1010 			test(h->Top() - orig_top == 2*g);
  1011 			test(c.Size() - orig_size == 2*g);
  1012 			free = pass ? h->FreeRef().next->next : h->FreeRef().next;
  1013 			test(free != NULL);
  1014 			// may shrink heap as will now have g+minc free bytes
  1015 			test(h->TestReAlloc(p2, l2 - minc, 0) == p2);
  1016 			if (g+minc >= shrinkThres)
  1017 				{
  1018 				test(h->Top() - orig_top == g);
  1019 				test(c.Size() - orig_size == g);
  1020 				}
  1021 			else
  1022 				{
  1023 				test(h->Top() - orig_top == 2*g);
  1024 				test(c.Size() - orig_size == 2*g);
  1025 				}
  1026 			free = pass ? h->FreeRef().next->next : h->FreeRef().next;
  1027 			test(free != NULL);
  1028 			TEST_ALIGN(TLinAddr(free)+minc, page_size);
  1029 			test(h->TestAlloc(l2 + g + page_size + minc) == p3 - minc);
  1030 			test(h->Top() - orig_top == 4*g);
  1031 			test(c.Size() - orig_size == 4*g);
  1032 			h->TestFree(p3 - minc);
  1033 			h->ForceCompress(l2 + g + page_size + minc);
  1034 			test(h->Top() - orig_top == g);
  1035 			test(c.Size() - orig_size == g);
  1036 			h->FullCheck();
  1037 			h->TestFree(p2);
  1038 			}
  1039 
  1040 		h->TestFree(p1);
  1041 		if (pass == 0)
  1042 			h->TestFree(p0);
  1043 		h->Compress();
  1044 		}
  1045 	h->FullCheck();
  1046 	}
  1047 
  1048 void Test1()
  1049 	{
  1050 	RHeap* h;
  1051 	h = RTestHeap::FixedHeap(0x1000, 0);
  1052 	test(h != NULL);
  1053 	DoTest1(h);
  1054 	h->Close();
  1055 	h = RTestHeap::FixedHeap(0x1000, 0, EFalse);
  1056 	test(h != NULL);
  1057 	DoTest1(h);
  1058 	h->Close();
  1059 	h = RTestHeap::FixedHeap(0x10000, 64);
  1060 	test(h != NULL);
  1061 	DoTest1(h);
  1062 	h->Close();
  1063 	h = RTestHeap::FixedHeap(0x100000, 4096);
  1064 	test(h != NULL);
  1065 	DoTest1(h);
  1066 	h->Close();
  1067 	h = RTestHeap::FixedHeap(0x100000, 8192);
  1068 	test(h != NULL);
  1069 	DoTest1(h);
  1070 	h->Close();
  1071 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x1000, 0x1000, 4);
  1072 	test(h != NULL);
  1073 	DoTest1(h);
  1074 	h->Close();
  1075 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x10000, 0x1000, 4);
  1076 	test(h != NULL);
  1077 	DoTest1(h);
  1078 	h->Close();
  1079 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4096);
  1080 	test(h != NULL);
  1081 	DoTest1(h);
  1082 	h->Close();
  1083 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4);
  1084 	test(h != NULL);
  1085 	DoTest1(h);
  1086 	h->Reset();
  1087 	DoTest2(h);
  1088 	h->Reset();
  1089 	DoTest3(h);
  1090 	h->Reset();
  1091 	DoTest4(h);
  1092 	h->Close();
  1093 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 8);
  1094 	test(h != NULL);
  1095 	DoTest1(h);
  1096 	h->Reset();
  1097 	DoTest2(h);
  1098 	h->Reset();
  1099 	DoTest3(h);
  1100 	h->Reset();
  1101 	DoTest4(h);
  1102 	h->Close();
  1103 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 16);
  1104 	test(h != NULL);
  1105 	DoTest1(h);
  1106 	h->Reset();
  1107 	DoTest2(h);
  1108 	h->Reset();
  1109 	DoTest3(h);
  1110 	h->Reset();
  1111 	DoTest4(h);
  1112 	h->Close();
  1113 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 32);
  1114 	test(h != NULL);
  1115 	DoTest1(h);
  1116 	h->Reset();
  1117 	DoTest2(h);
  1118 	h->Reset();
  1119 	DoTest3(h);
  1120 	h->Reset();
  1121 	DoTest4(h);
  1122 	h->Close();
  1123 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x3000, 0x100000, 0x3000, 4);
  1124 	test(h != NULL);
  1125 	DoTest1(h);
  1126 	h->Reset();
  1127 	DoTest2(h);
  1128 	h->Reset();
  1129 	DoTest3(h);
  1130 	h->Reset();
  1131 	DoTest4(h);
  1132 	h->Close();
  1133 	}
  1134 
  1135 struct SHeapStress
  1136 	{
  1137 	RThread iThread;
  1138 	volatile TBool iStop;
  1139 	TInt iAllocs;
  1140 	TInt iFailedAllocs;
  1141 	TInt iFrees;
  1142 	TInt iReAllocs;
  1143 	TInt iFailedReAllocs;
  1144 	TInt iChecks;
  1145 	TUint32 iSeed;
  1146 	RAllocator* iAllocator;
  1147 
  1148 	TUint32 Random();
  1149 	};
  1150 
  1151 TUint32 SHeapStress::Random()
  1152 	{
  1153 	iSeed *= 69069;
  1154 	iSeed += 41;
  1155 	return iSeed;
  1156 	}
  1157 
  1158 TInt RandomLength(TUint32 aRandom)
  1159 	{
  1160 	TUint8 x = (TUint8)aRandom;
  1161 	if (x & 0x80)
  1162 		return (x & 0x7f) << 7;
  1163 	return x & 0x7f;
  1164 	}
  1165 
  1166 TInt HeapStress(TAny* aPtr)
  1167 	{
  1168 	SHeapStress& hs = *(SHeapStress*)aPtr;
  1169 	RTestHeap* h = (RTestHeap*)&User::Allocator();
  1170 	TUint8* cell[256];
  1171 	TInt len[256];
  1172 
  1173 	Mem::FillZ(cell, sizeof(cell));
  1174 	Mem::FillZ(len, sizeof(len));
  1175 
  1176 	RThread::Rendezvous(KErrNone);
  1177 	while (!hs.iStop)
  1178 		{
  1179 		// allocate all cells
  1180 		TInt i;
  1181 		for (i=0; i<256; ++i)
  1182 			{
  1183 			if (!cell[i])
  1184 				{
  1185 				++hs.iAllocs;
  1186 				cell[i] = (TUint8*)h->TestAlloc(RandomLength(hs.Random()));
  1187 				if (cell[i])
  1188 					len[i] = h->AllocLen(cell[i]);
  1189 				else
  1190 					++hs.iFailedAllocs;
  1191 				}
  1192 			}
  1193 
  1194 		// free some cells
  1195 		TInt n = 64 + (hs.Random() & 127);
  1196 		while (--n)
  1197 			{
  1198 			i = hs.Random() & 0xff;
  1199 			if (cell[i])
  1200 				{
  1201 				test(h->AllocLen(cell[i]) == len[i]);
  1202 				h->TestFree(cell[i]);
  1203 				cell[i] = NULL;
  1204 				len[i] = 0;
  1205 				++hs.iFrees;
  1206 				}
  1207 			}
  1208 
  1209 		// realloc some cells
  1210 		n = 64 + (hs.Random() & 127);
  1211 		while (--n)
  1212 			{
  1213 			TUint32 rn = hs.Random();
  1214 			i = (rn >> 8) & 0xff;
  1215 			TInt new_len = RandomLength(rn);
  1216 			if (cell[i])
  1217 				{
  1218 				test(h->AllocLen(cell[i]) == len[i]);
  1219 				++hs.iReAllocs;
  1220 				TUint8* p = (TUint8*)h->TestReAlloc(cell[i], new_len, rn >> 16);
  1221 				if (p)
  1222 					{
  1223 					cell[i] = p;
  1224 					len[i] = h->AllocLen(p);
  1225 					}
  1226 				else
  1227 					++hs.iFailedReAllocs;
  1228 				}
  1229 			}
  1230 
  1231 		// check the heap
  1232 		h->Check();
  1233 		++hs.iChecks;
  1234 		}
  1235 	return 0;
  1236 	}
  1237 
  1238 void CreateStressThread(SHeapStress& aInfo)
  1239 	{
  1240 	Mem::FillZ(&aInfo, _FOFF(SHeapStress, iSeed));
  1241 	RThread& t = aInfo.iThread;
  1242 	TInt r = t.Create(KNullDesC(), &HeapStress, 0x2000, aInfo.iAllocator, &aInfo);
  1243 	test(r==KErrNone);
  1244 	t.SetPriority(EPriorityLess);
  1245 	TRequestStatus s;
  1246 	t.Rendezvous(s);
  1247 	test(s == KRequestPending);
  1248 	t.Resume();
  1249 	User::WaitForRequest(s);
  1250 	test(s == KErrNone);
  1251 	test(t.ExitType() == EExitPending);
  1252 	t.SetPriority(EPriorityMuchLess);
  1253 	}
  1254 
  1255 void StopStressThread(SHeapStress& aInfo)
  1256 	{
  1257 	RThread& t = aInfo.iThread;
  1258 	TRequestStatus s;
  1259 	t.Logon(s);
  1260 	aInfo.iStop = ETrue;
  1261 	User::WaitForRequest(s);
  1262 	const TDesC& exitCat = t.ExitCategory();
  1263 	TInt exitReason = t.ExitReason();
  1264 	TInt exitType = t.ExitType();
  1265 	test.Printf(_L("Exit type %d,%d,%S\n"), exitType, exitReason, &exitCat);
  1266 	test(exitType == EExitKill);
  1267 	test(exitReason == KErrNone);
  1268 	test(s == KErrNone);
  1269 	test.Printf(_L("Total Allocs    : %d\n"), aInfo.iAllocs);
  1270 	test.Printf(_L("Failed Allocs   : %d\n"), aInfo.iFailedAllocs);
  1271 	test.Printf(_L("Total Frees		: %d\n"), aInfo.iFrees);
  1272 	test.Printf(_L("Total ReAllocs  : %d\n"), aInfo.iReAllocs);
  1273 	test.Printf(_L("Failed ReAllocs : %d\n"), aInfo.iFailedReAllocs);
  1274 	test.Printf(_L("Heap checks     : %d\n"), aInfo.iChecks);
  1275 	}
  1276 
  1277 void DoStressTest1(RAllocator* aAllocator)
  1278 	{
  1279 	RTestHeap* h = (RTestHeap*)aAllocator;
  1280 	test.Printf(_L("Test Stress 1: min=%x max=%x align=%d growby=%d\n"),
  1281 						h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
  1282 	SHeapStress hs;
  1283 	hs.iSeed = 0xb504f334;
  1284 	hs.iAllocator = aAllocator;
  1285 	CreateStressThread(hs);
  1286 	User::After(10*1000000);
  1287 	StopStressThread(hs);
  1288 	CLOSE_AND_WAIT(hs.iThread);
  1289 	h->FullCheck();
  1290 	}
  1291 
  1292 void DoStressTest2(RAllocator* aAllocator)
  1293 	{
  1294 	RTestHeap* h = (RTestHeap*)aAllocator;
  1295 	test.Printf(_L("Test Stress 2: min=%x max=%x align=%d growby=%d\n"),
  1296 						h->MinLength(), h->MaxLength(), h->Align(), h->GrowBy());
  1297 	SHeapStress hs1;
  1298 	SHeapStress hs2;
  1299 	hs1.iSeed = 0xb504f334;
  1300 	hs1.iAllocator = aAllocator;
  1301 	hs2.iSeed = 0xddb3d743;
  1302 	hs2.iAllocator = aAllocator;
  1303 	CreateStressThread(hs1);
  1304 	CreateStressThread(hs2);
  1305 	User::After(20*1000000);
  1306 	StopStressThread(hs1);
  1307 	StopStressThread(hs2);
  1308 	CLOSE_AND_WAIT(hs1.iThread);
  1309 	CLOSE_AND_WAIT(hs2.iThread);
  1310 	h->FullCheck();
  1311 	}
  1312 
  1313 void StressTests()
  1314 	{
  1315 	RHeap* h;
  1316 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 4);
  1317 	test(h != NULL);
  1318 	DoStressTest1(h);
  1319 	h->Reset();
  1320 	DoStressTest2(h);
  1321 	h->Close();
  1322 	h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x100000, 0x1000, 8);
  1323 	test(h != NULL);
  1324 	DoStressTest1(h);
  1325 	h->Reset();
  1326 	DoStressTest2(h);
  1327 	h->Close();
  1328 	}
  1329 		
  1330 TInt TestHeapGrowInPlace(TInt aMode)
  1331     {
  1332     TBool reAllocs=EFalse;
  1333     TBool heapGrew=EFalse;
  1334     
  1335     RHeap* myHeap;
  1336     
  1337     myHeap = UserHeap::ChunkHeap(NULL,0x1000,0x4000,0x1000);
  1338     
  1339     TAny *testBuffer,*testBuffer2;
  1340     // Start size chosen so that 1st realloc will use up exactly all the heap.
  1341     // Later iterations wont, and there will be a free cell at the end of the heap.
  1342     TInt currentSize = ((0x800) - sizeof(RHeap)) - RHeap::EAllocCellSize;
  1343     TInt growBy = 0x800;
  1344     TInt newSpace, space;
  1345     
  1346     testBuffer2 = myHeap->Alloc(currentSize);
  1347 
  1348     newSpace = myHeap->Size();
  1349     do 
  1350     {
  1351     	space = newSpace;
  1352 		testBuffer = testBuffer2;
  1353 	    currentSize+=growBy;
  1354 		testBuffer2 = myHeap->ReAlloc(testBuffer,currentSize,aMode);	
  1355 		
  1356 		newSpace = myHeap->Size();
  1357 		
  1358 		if (testBuffer2) 
  1359 			{
  1360 				
  1361 			if (testBuffer!=testBuffer2)
  1362 					reAllocs = ETrue;
  1363 				
  1364 			if (newSpace>space)
  1365 					heapGrew = ETrue;
  1366 			}
  1367 		growBy-=16;
  1368  	} while (testBuffer2);
  1369     currentSize-=growBy;	
  1370     
  1371     myHeap->Free(testBuffer);
  1372     myHeap->Close();
  1373     
  1374     // How did we do?
  1375     if (reAllocs) 
  1376     	{
  1377     	test.Printf(_L("Failure - Memory was moved!\n"));
  1378     	return -100;
  1379     	}
  1380     if (!heapGrew) 
  1381     	{
  1382     	test.Printf(_L("Failure - Heap Never Grew!\n"));
  1383     	return -200;
  1384     	}
  1385     if (currentSize<= 0x3000) 
  1386     	{
  1387     	test.Printf(_L("Failed to grow by a reasonable amount!\n"));
  1388     	return -300;
  1389     	}
  1390         
  1391     return KErrNone;
  1392     }
  1393     
  1394 void ReAllocTests()
  1395 	{
  1396 	test.Next(_L("Testing Grow In Place"));
  1397 	test(TestHeapGrowInPlace(0)==KErrNone);
  1398     test(TestHeapGrowInPlace(RHeap::ENeverMove)==KErrNone);
  1399 	}
  1400 
  1401 RHeap* TestDEF078391Heap = 0;
  1402 
  1403 TInt TestDEF078391ThreadFunction(TAny*)
  1404 	{
  1405     TestDEF078391Heap = UserHeap::ChunkHeap(NULL,0x1000,0x100000,KMinHeapGrowBy,0,EFalse);
  1406 	return TestDEF078391Heap ? KErrNone : KErrGeneral;
  1407 	}
  1408 
  1409 void TestDEF078391()
  1410 	{
  1411 	// Test that creating a multithreaded heap with UserHeap::ChunkHeap
  1412 	// doesn't create any reference counts on the creating thread.
  1413 	// This is done by creating a heap in a named thread, then exiting
  1414 	// the thread and re-creating it with the same name.
  1415 	// This will fail with KErrAlreadyExists if the orinal thread has
  1416 	// not died because of an unclosed reference count.
  1417 	test.Next(_L("Test that creating a multithreaded heap doesn't open references of creator"));
  1418 	_LIT(KThreadName,"ThreadName");
  1419 	RThread t;
  1420 	TInt r=t.Create(KThreadName,TestDEF078391ThreadFunction,0x1000,0x1000,0x100000,NULL);
  1421 	test(r==KErrNone);
  1422 	TRequestStatus status;
  1423 	t.Logon(status);
  1424 	t.Resume();
  1425 	User::WaitForRequest(status);
  1426 	test(status==KErrNone);
  1427 	test(t.ExitType()==EExitKill);
  1428 	test(t.ExitReason()==KErrNone);
  1429 	CLOSE_AND_WAIT(t);
  1430 	test(TestDEF078391Heap!=0);
  1431 	User::After(1000000); // give more opportunity for thread cleanup to happen
  1432 
  1433 	// create thread a second time
  1434 	r=t.Create(KThreadName,TestDEF078391ThreadFunction,0x1000,0x1000,0x100000,NULL);
  1435 	test(r==KErrNone);
  1436 	t.Kill(0);
  1437 	CLOSE_AND_WAIT(t);
  1438 
  1439 	// close the heap that got created earlier
  1440 	TestDEF078391Heap->Close();
  1441 	}
  1442 
  1443 TInt E32Main()
  1444 	{
  1445 	test.Title();
  1446 	__KHEAP_MARK;
  1447 	test.Start(_L("Testing heaps"));
  1448 	TestDEF078391();
  1449 	Test1();
  1450 	StressTests();
  1451 	ReAllocTests();
  1452 	test.End();
  1453 	__KHEAP_MARKEND;
  1454 	return 0;
  1455 	}