os/kernelhwsrv/kerneltest/e32test/mmu/t_chunk.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/mmu/t_chunk.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1434 @@
     1.4 +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// e32test\mmu\t_chunk.cpp
    1.18 +// Overview:
    1.19 +// Test RChunk class
    1.20 +// API Information:
    1.21 +// RChunk, RChangeNotifier, TFindChunk
    1.22 +// Details:
    1.23 +// - Test adjusting chunks: create a global chunk, adjust it, do some size 
    1.24 +// checks, verify Create() rounds up to chunk multiple, verify that adjust
    1.25 +// request for size greater than MaxSize returns an error.
    1.26 +// - Test creating chunks with small sizes (0 and 1), verify results are as expected.
    1.27 +// - Create multiple local and global chunks, verify that Size,MaxSize,Name & FullName methods 
    1.28 +// are as expected. 
    1.29 +// Check Create method of global chunk if the name is already in use. Check the name can be 
    1.30 +// reused after the chunk is closed.
    1.31 +// - Perform adjust tests on a chunk, verify results are as expected.
    1.32 +// - Open and test global chunks with multiple references, verify results are as expected.
    1.33 +// - Open and test local chunks, check TFindChunk::Next method, verify results are as expected.
    1.34 +// - Check user thread is panicked if it creates or adjusts chunk with negative size or of an
    1.35 +// invalid type or with an invalid name.
    1.36 +// - Check the chunk is filled in with the appropriate clear value after creation, verify results
    1.37 +// are as expected.
    1.38 +// - Test sharing a chunk between threads, verify results are as expected.
    1.39 +// - Create a thread to watch for notification of changes in free memory and
    1.40 +// changes in out of memory status. Verify adjusting an RChunk generates
    1.41 +// the expected notifications.
    1.42 +// - Test finding a global chunk by name and verify results are as expected.
    1.43 +// - Check read-only global chunks cannot be written to by other processes.
    1.44 +// Platforms/Drives/Compatibility:
    1.45 +// All.
    1.46 +// Assumptions/Requirement/Pre-requisites:
    1.47 +// Failures and causes:
    1.48 +// Base Port information:
    1.49 +// 
    1.50 +//
    1.51 +
    1.52 +#define __E32TEST_EXTENSION__
    1.53 +
    1.54 +#include <e32test.h>
    1.55 +#include <e32panic.h>
    1.56 +#include <e32svr.h>
    1.57 +#include "mmudetect.h"
    1.58 +#include "d_gobble.h"
    1.59 +#include "freeram.h"
    1.60 +
    1.61 +const TInt KHeapSize=0x200;
    1.62 +
    1.63 +//const TInt KNumberOfChunks=10; can't have that many
    1.64 +const TInt KNumberOfChunks=3;
    1.65 +
    1.66 +const TInt KChunkNum=5;
    1.67 +const TInt KNormalReturn=194;
    1.68 +
    1.69 +#ifdef __WINS__
    1.70 +const TInt KMinChunkSizeInBytesMinus1=0x0000ffff;
    1.71 +const TUint KMinChunkSizeInBytesMask=0xffff0000;
    1.72 +#elif defined (__X86__)
    1.73 +const TInt KMinChunkSizeInBytesMinus1=0x003fffff;
    1.74 +const TUint KMinChunkSizeInBytesMask=0xffc00000;
    1.75 +#else
    1.76 +const TInt KMinChunkSizeInBytesMinus1=0x000fffff;
    1.77 +const TUint KMinChunkSizeInBytesMask=0xfff00000;
    1.78 +#endif
    1.79 +
    1.80 +const TInt KMinPageSizeInBytesMinus1=0x00000fff;
    1.81 +const TUint KMinPageSizeInBytesMask=0xfffff000;
    1.82 +TInt gPageSize;
    1.83 +
    1.84 +LOCAL_D RTest test(_L("T_CHUNK"));
    1.85 +LOCAL_D RTest t(_L("ShareThread"));
    1.86 +LOCAL_D RChunk gChunk;
    1.87 +
    1.88 +LOCAL_D TPtr nullPtr(NULL,0);
    1.89 +
    1.90 +TUint32 MemModel;
    1.91 +
    1.92 +enum TDirective
    1.93 +	{
    1.94 +	ENormal,
    1.95 +	ECreateNegative,
    1.96 +	EAdjustNegative,
    1.97 +	ECreateInvalidType,
    1.98 +	ECreateInvalidName,
    1.99 +	ECreateNoName,
   1.100 +	};
   1.101 +
   1.102 +const TUint8 KDfltClearByte = 0x3;
   1.103 +TBool CheckChunkCleared(RChunk& aRC, TInt aOffset=0, TUint8 aClearByte = KDfltClearByte)
   1.104 +	{
   1.105 +	TUint8* base = aRC.Base()+aOffset;
   1.106 +	TInt size = aRC.Size();
   1.107 +	test.Printf(_L("Testing chunk for 0x%x - size: %d!\n"), aClearByte, size);
   1.108 +	TBool ret=ETrue;
   1.109 +	for(TInt i = 0; i<size; i++)
   1.110 +		if(base[i] != aClearByte)
   1.111 +			ret=EFalse;
   1.112 +	memset((TAny*)base, 0x05, size);
   1.113 +	return ret;
   1.114 +	}
   1.115 +
   1.116 +TInt roundToPageSize(TInt aSize)
   1.117 +	{
   1.118 +
   1.119 +	return(((aSize+KMinPageSizeInBytesMinus1)&KMinPageSizeInBytesMask));
   1.120 +	}
   1.121 +
   1.122 +TInt roundToChunkSize(TInt aSize)
   1.123 +	{
   1.124 +	if(MemModel==EMemModelTypeFlexible)
   1.125 +		return roundToPageSize(aSize);
   1.126 +	return(((aSize+KMinChunkSizeInBytesMinus1)&KMinChunkSizeInBytesMask));
   1.127 +	}
   1.128 +
   1.129 +TInt ThreadEntry2(TAny* /*aParam*/)
   1.130 +//
   1.131 +//	Thread to read from shared chunk
   1.132 +//
   1.133 +	{
   1.134 +	RChunk c;
   1.135 +	TInt r;
   1.136 +	r=c.OpenGlobal(_L("Marmalade"),ETrue);
   1.137 +	t(r==KErrNone);
   1.138 +	TUint8* base=c.Base();
   1.139 +	for (TInt8 i=0;i<10;i++)
   1.140 +		t(*base++==i); // check the chunk has 0-9
   1.141 +	c.Close();
   1.142 +	return(KErrNone);
   1.143 +	}
   1.144 +
   1.145 +TInt ThreadEntry(TAny* aDirective)
   1.146 +//
   1.147 +//	Thread to create a Panic in a variety of ways
   1.148 +//
   1.149 +	{
   1.150 +
   1.151 +	switch((TUint)aDirective)
   1.152 +		{
   1.153 +	case ENormal:
   1.154 +		{
   1.155 +		return KNormalReturn;
   1.156 +		}
   1.157 +	case ECreateNegative:
   1.158 +		{
   1.159 +		gChunk.CreateLocal(0x10,-0x10);
   1.160 +		test(EFalse); 
   1.161 +		}
   1.162 +	case EAdjustNegative:
   1.163 +		{
   1.164 +		gChunk.Adjust(-0x10);
   1.165 +		test(EFalse);
   1.166 +		}
   1.167 +	case ECreateInvalidType :
   1.168 +		{
   1.169 +		TChunkCreateInfo createInfo;
   1.170 +		createInfo.SetCode(gPageSize, gPageSize);
   1.171 +		_LIT(KChunkName, "Chunky");
   1.172 +		createInfo.SetGlobal(KChunkName);
   1.173 +		RChunk chunk;
   1.174 +		chunk.Create(createInfo);
   1.175 +		test(EFalse);
   1.176 +		}
   1.177 +	default:
   1.178 +		test(EFalse);
   1.179 +		}
   1.180 +	return(KErrNone);
   1.181 +	}
   1.182 +
   1.183 +//
   1.184 +//	Test the clear flags for the specified chunk.
   1.185 +//	Assumes chunk has one commited region from base to aBytes.
   1.186 +//
   1.187 +void TestClearChunk(RChunk& aChunk, TUint aBytes, TUint8 aClearByte)
   1.188 +	{
   1.189 +	test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
   1.190 +	test_KErrNone(aChunk.Adjust(0));
   1.191 +	test_KErrNone(aChunk.Adjust(aBytes));
   1.192 +	test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
   1.193 +	aChunk.Close();
   1.194 +	}
   1.195 +
   1.196 +
   1.197 +//
   1.198 +// Create the specified thread and verify the exit reason.
   1.199 +//
   1.200 +void TestThreadExit(TExitType aExitType, TInt aExitReason, TThreadFunction aFunc, TAny* aThreadParam)
   1.201 +	{
   1.202 +	RThread thread;
   1.203 +	test_KErrNone(thread.Create(_L("RChunkPanicThread"), aFunc, KDefaultStackSize, 
   1.204 +								KHeapSize, KHeapSize, aThreadParam));
   1.205 +	// Disable JIT debugging.
   1.206 +	TBool justInTime=User::JustInTime();
   1.207 +	User::SetJustInTime(EFalse);
   1.208 +
   1.209 +	TRequestStatus status;
   1.210 +	thread.Logon(status); 
   1.211 +	thread.Resume();
   1.212 +	User::WaitForRequest(status);
   1.213 +	test_Equal(aExitType, thread.ExitType());
   1.214 +	test_Equal(aExitReason, status.Int());
   1.215 +	test_Equal(aExitReason, thread.ExitReason());
   1.216 +	if (aExitType == EExitPanic)
   1.217 +		test(thread.ExitCategory()==_L("USER"));
   1.218 +	CLOSE_AND_WAIT(thread);
   1.219 +
   1.220 +	// Put JIT debugging back to previous status.
   1.221 +	User::SetJustInTime(justInTime);
   1.222 +	}
   1.223 +
   1.224 +
   1.225 +//
   1.226 +// Thread function to create a chunk with invalid attributes
   1.227 +//
   1.228 +TInt ChunkPanicThread(TAny* aCreateInfo)
   1.229 +	{
   1.230 +	// This should panic.
   1.231 +	RChunk chunk;
   1.232 +	chunk.Create((*(TChunkCreateInfo*) aCreateInfo));
   1.233 +	test(EFalse);
   1.234 +
   1.235 +	return KErrGeneral;	// Shouldn't reach here.
   1.236 +	}
   1.237 +
   1.238 +void testInitialise()
   1.239 +	{
   1.240 +	test.Next(_L("Load gobbler LDD"));
   1.241 +	TInt r = User::LoadLogicalDevice(KGobblerLddFileName);
   1.242 +	test(r==KErrNone || r==KErrAlreadyExists);
   1.243 +
   1.244 +	// get system info...
   1.245 +	MemModel = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL) & EMemModelTypeMask;
   1.246 +
   1.247 +	test_KErrNone(UserHal::PageSizeInBytes(gPageSize));
   1.248 +	}
   1.249 +
   1.250 +
   1.251 +void test1()
   1.252 +//
   1.253 +//	Test creating chunks with silly sizes
   1.254 +//
   1.255 +	{
   1.256 +
   1.257 +	__KHEAP_MARK;
   1.258 +	RChunk chunk;
   1.259 +	TInt r;
   1.260 +	test.Start(_L("Create global chunks"));
   1.261 +	r=chunk.CreateGlobal(_L("Fopp"),1,1);
   1.262 +	test(r==KErrNone);
   1.263 +	chunk.Close();
   1.264 +	r=chunk.CreateGlobal(_L("Fopp"),0,0);
   1.265 +	test(r==KErrArgument);
   1.266 +
   1.267 +	__KHEAP_CHECK(0);
   1.268 +
   1.269 +	test.Next(_L("Create local chunks"));	  
   1.270 +	r=chunk.CreateLocal(1,1);
   1.271 +	test(r==KErrNone);
   1.272 +	chunk.Close();
   1.273 +	r=chunk.CreateLocal(0,0);
   1.274 +	test(r==KErrArgument);
   1.275 +	test.End();
   1.276 +	__KHEAP_MARKEND;
   1.277 +	}
   1.278 +
   1.279 +
   1.280 +void test2(TInt aSize)
   1.281 +//
   1.282 +//	Test local/global chunk creation
   1.283 +//
   1.284 +	{
   1.285 +
   1.286 +	RChunk lchunk[KNumberOfChunks];
   1.287 +	RChunk gchunk[KNumberOfChunks];
   1.288 +	RChunk chunk;
   1.289 +
   1.290 +	__KHEAP_MARK;
   1.291 +	test.Start(_L("Create multiple local and global chunks"));
   1.292 +
   1.293 +	TInt i;
   1.294 +	TBuf<0x40> name;
   1.295 +	TFullName fullname;
   1.296 +	for (i=0; i<KNumberOfChunks; i++)
   1.297 +		{
   1.298 +		TInt r;
   1.299 +		// create a local chunk
   1.300 +		r=lchunk[i].CreateLocal(aSize,aSize);
   1.301 +		test(r==KErrNone);
   1.302 +		r=lchunk[i].MaxSize();
   1.303 +		test(r==roundToChunkSize(aSize));
   1.304 +		test(lchunk[i].Size()==roundToPageSize(aSize)); // was 0
   1.305 +		test(lchunk[i].Name().Left(6)==_L("Local-"));
   1.306 +
   1.307 +		fullname=RProcess().Name();
   1.308 +		fullname+=_L("::");
   1.309 +		fullname+=lchunk[i].Name();
   1.310 +		test(lchunk[i].FullName().CompareF(fullname)==0);
   1.311 +
   1.312 +		// create a global chunk
   1.313 +		name.Format(_L("Chunk%d"),i);
   1.314 +		r=gchunk[i].CreateGlobal(name,aSize,aSize);
   1.315 +		test(r==KErrNone);
   1.316 +  		test(gchunk[i].MaxSize()==roundToChunkSize(aSize));
   1.317 +		test(gchunk[i].Size()==roundToPageSize(aSize)); // was 0
   1.318 +		test(gchunk[i].Name()==name);
   1.319 +		}
   1.320 +
   1.321 +	// make room for another chunk
   1.322 +	lchunk[KNumberOfChunks-1].Close();
   1.323 +	gchunk[KNumberOfChunks-1].Close();
   1.324 +
   1.325 +//	Try to create a global chunk with a duplicate name
   1.326 +	test.Next(_L("Create a chunk with a duplicate name"));
   1.327 +	TInt r=chunk.CreateGlobal(_L("Chunk0"),aSize,aSize);
   1.328 +	test(r==KErrAlreadyExists);
   1.329 +
   1.330 + 	test.Next(_L("Close all chunks"));
   1.331 +	for (i=0; i<KNumberOfChunks-1; i++)
   1.332 +		{
   1.333 +		lchunk[i].Close();
   1.334 +		gchunk[i].Close();
   1.335 +		}
   1.336 +
   1.337 +	test.Next(_L("Reuse a name"));
   1.338 +	r=chunk.CreateGlobal(_L("Chunk1"),aSize,aSize);
   1.339 +	test(r==KErrNone);
   1.340 +	test(chunk.MaxSize()==roundToChunkSize(aSize));
   1.341 +   	test(chunk.Size()==roundToPageSize(aSize));	
   1.342 +	test(chunk.Name()==_L("Chunk1"));
   1.343 +  	chunk.Close();
   1.344 +
   1.345 +	test.End();
   1.346 +	__KHEAP_MARKEND;
   1.347 +	}
   1.348 +
   1.349 +void test3_2(RChunk& aChunk, TInt aSize)
   1.350 +//
   1.351 +//	Perform Adjust tests on aChunk
   1.352 +//
   1.353 +	{
   1.354 +
   1.355 +	TInt r;
   1.356 +	test.Start(_L("Adjust to full size"));
   1.357 +	r=aChunk.Adjust(aSize);
   1.358 + 	test(r==KErrNone);
   1.359 +	test(aChunk.Size()==roundToPageSize(aSize));
   1.360 +	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   1.361 +
   1.362 +	test.Next(_L("Adjust a chunk to half size"));
   1.363 +	r=aChunk.Adjust(aSize/2);
   1.364 +	test(r==KErrNone);
   1.365 +	test(aChunk.Size()==roundToPageSize(aSize/2));
   1.366 +	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   1.367 +
   1.368 +	test.Next(_L("Adjust to same size"));
   1.369 +	r=aChunk.Adjust(aSize/2);
   1.370 +	test(r==KErrNone);
   1.371 +	test(aChunk.Size()==roundToPageSize(aSize/2));
   1.372 +	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   1.373 +
   1.374 +	test.Next(_L("Adjusting to size=0"));
   1.375 + 	r=aChunk.Adjust(0);
   1.376 +	test(r==KErrNone);
   1.377 +	test(aChunk.Size()==0);
   1.378 +	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   1.379 +
   1.380 +	test.Next(_L("Adjust back to half size"));
   1.381 +	r=aChunk.Adjust(aSize/2);
   1.382 +	test(r==KErrNone);
   1.383 +	test(aChunk.Size()==roundToPageSize(aSize/2));
   1.384 +	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   1.385 +
   1.386 +	test.End();
   1.387 +	}
   1.388 +
   1.389 +
   1.390 +void test3(TInt aSize)
   1.391 +//
   1.392 +//	Test Adjust size of chunk	
   1.393 +//
   1.394 +	{
   1.395 +
   1.396 +	RChunk chunk;
   1.397 +	__KHEAP_MARK;	
   1.398 +	TInt r;
   1.399 +//	Run Adjust tests with a local chunk
   1.400 +	test.Start(_L("Local Chunk.Adjust()"));
   1.401 +	r=chunk.CreateLocal(aSize,aSize);
   1.402 +	test3_2(chunk, aSize);
   1.403 +	chunk.Close();
   1.404 +//	Run Adjust tests with a global chunk
   1.405 +	test.Next(_L("Global Chunk.Adjust()"));
   1.406 +	r=chunk.CreateGlobal(_L("Fopp"),aSize,aSize);
   1.407 +	test(KErrNone==r);
   1.408 +	test3_2(chunk,aSize);
   1.409 +	chunk.Close();
   1.410 +	test.End();
   1.411 +	__KHEAP_MARKEND;
   1.412 +	}
   1.413 +
   1.414 +void test4(TInt aSize)
   1.415 +//
   1.416 +//	Test OpenGlobal
   1.417 +//
   1.418 +	{
   1.419 +
   1.420 +	RChunk chunk[KChunkNum];
   1.421 +	RChunk c1, c2, c3;
   1.422 +	TName name;
   1.423 +
   1.424 +	__KHEAP_MARK;
   1.425 +	TInt i,r;
   1.426 +	for (i=0; i<KChunkNum; i++)
   1.427 +		{
   1.428 +		name.Format(_L("Chunk%d"), i);
   1.429 +		r=chunk[i].CreateGlobal(name,aSize,aSize);
   1.430 +		}
   1.431 +
   1.432 +	test.Start(_L("Open Global chunks"));
   1.433 +	r=c1.OpenGlobal(_L("Chunk1"),EFalse); // 2nd ref to this chunk
   1.434 +	test(r==KErrNone);
   1.435 +	r=c2.OpenGlobal(_L("Chunk3"),EFalse); // 2nd ref to this chunk
   1.436 +	test(r==KErrNone);
   1.437 +	r=c3.OpenGlobal(_L("Chunk4"),EFalse); // 2nd ref to this chunk
   1.438 +	test(r==KErrNone);
   1.439 +	c3.Close();
   1.440 +
   1.441 +	test.Next(_L("Attempt Open non-existant chunk"));
   1.442 +	r=c3.OpenGlobal(_L("Non Existant Chunk"),EFalse);
   1.443 +	test(r==KErrNotFound);
   1.444 +
   1.445 +	for (i=0; i<KChunkNum; i++)
   1.446 +		{
   1.447 +		test.Printf(_L("Closing chunk %d\n"),i);
   1.448 +		chunk[i].Close();
   1.449 +		}
   1.450 +
   1.451 +	test.Next(_L("Test chunks with multiple references are still valid"));
   1.452 +	r=c1.Adjust(aSize/2);
   1.453 +	test(r==KErrNone);
   1.454 +	test(c1.MaxSize()==roundToChunkSize(aSize));
   1.455 +	test(c1.Size()==roundToPageSize(aSize/2));
   1.456 +	test(c1.Name()==_L("Chunk1"));
   1.457 +
   1.458 +	r=c2.Adjust(aSize/2);
   1.459 +	test(r==KErrNone);
   1.460 +	test(c2.MaxSize()==roundToChunkSize(aSize));
   1.461 +	test(c2.Size()==roundToPageSize(aSize/2));
   1.462 +	test(c2.Name()==_L("Chunk3"));
   1.463 +
   1.464 +//	Open another reference to a chunk
   1.465 +	r=c3.OpenGlobal(_L("Chunk3"),EFalse);
   1.466 +	test(r==KErrNone);
   1.467 +	test(c3.Base()==c2.Base());
   1.468 +	test(c3.Size()==c2.Size());
   1.469 +	test(c2.Size()!=aSize);
   1.470 +//	Adjust with one reference
   1.471 +	r=c3.Adjust(aSize);
   1.472 +	test(r==KErrNone);
   1.473 +//	Test sizes from the other
   1.474 +	test(c2.Size()==roundToPageSize(aSize));
   1.475 +	test(c2.MaxSize()==roundToChunkSize(aSize));
   1.476 +
   1.477 +	c1.Close();
   1.478 +	c2.Close();
   1.479 +	c3.Close();
   1.480 +
   1.481 +	test.Next(_L("And check the heap..."));
   1.482 +	test.End();
   1.483 +	__KHEAP_MARKEND;
   1.484 +	}
   1.485 +
   1.486 +void test5(TInt aSize)
   1.487 +//
   1.488 +//	Test Open
   1.489 +//
   1.490 +	{
   1.491 +	
   1.492 +	RChunk chunk[2*KNumberOfChunks];
   1.493 +	RChunk c1;
   1.494 +
   1.495 +	test.Start(_L("Creating Local and Global Chunks"));
   1.496 +	__KHEAP_MARK;
   1.497 +	TInt i,r;
   1.498 +	TBuf<0x40> b;
   1.499 +
   1.500 +//	Create KNumberOfChunks Global chunks
   1.501 +	for (i=0; i<KNumberOfChunks; i++)
   1.502 +		{
   1.503 +		b.Format(_L("Chunk%d"), i);
   1.504 +		r=chunk[i].CreateGlobal(b,aSize,aSize);
   1.505 +		test(chunk[i].Name()==b);
   1.506 +		test(r==KErrNone);
   1.507 +		
   1.508 +		b.Format(_L("This is chunk %d"), i);
   1.509 +		b.Append(TChar(0));
   1.510 +		chunk[i].Adjust(aSize);
   1.511 +		Mem::Copy(chunk[i].Base(), b.Ptr(), b.Size());
   1.512 +		test(chunk[i].MaxSize()==roundToChunkSize(aSize));
   1.513 +		test(chunk[i].Size()==roundToPageSize(aSize));
   1.514 +		}
   1.515 +
   1.516 +	test.Next(_L("Find and Open the Chunks"));
   1.517 +	TFindChunk find;
   1.518 +	TFullName name;
   1.519 +	for (i=0; i<KNumberOfChunks; i++)
   1.520 +		{
   1.521 +		test.Printf(_L("Opening chunk %d\n"),i);
   1.522 +		find.Find(chunk[i].FullName());
   1.523 +		r = find.Next(name);
   1.524 +		test(r==KErrNone);
   1.525 +		c1.Open(find);
   1.526 +		b=TPtrC((TText*)c1.Base());
   1.527 +		name.Format(_L("This is chunk %d"), i);
   1.528 +		test(b==name);
   1.529 +		c1.Close();
   1.530 +		}
   1.531 +	
   1.532 +	test.Next(_L("Close chunks"));
   1.533 +	for (i=0; i<KNumberOfChunks; i++)
   1.534 +		chunk[i].Close();
   1.535 +
   1.536 +	test.End();
   1.537 +	__KHEAP_MARKEND;
   1.538 +	}
   1.539 +
   1.540 +
   1.541 +void test7(TInt aSize)
   1.542 +//
   1.543 +//	Deliberately cause RChunk panics
   1.544 +//
   1.545 +	{
   1.546 +	__KHEAP_MARK;
   1.547 +
   1.548 +//	ENormal
   1.549 +	test.Start(_L("Test panic thread"));
   1.550 +	TestThreadExit(EExitKill, KNormalReturn, ThreadEntry, (TAny*)ENormal);
   1.551 +
   1.552 +//	ECreateNegative
   1.553 +	test.Next(_L("Create Chunk with a negative size"));
   1.554 +	TestThreadExit(EExitPanic, EChkCreateMaxSizeNegative, ThreadEntry, (TAny*) ECreateNegative);
   1.555 +
   1.556 +//	EAdjustNegative
   1.557 +	test.Next(_L("Adjust a Chunk to Size = -0x10"));
   1.558 +	gChunk.CreateLocal(aSize,aSize);
   1.559 +	TestThreadExit(EExitPanic, EChkAdjustNewSizeNegative, ThreadEntry, (TAny*) EAdjustNegative);
   1.560 +	gChunk.Close();
   1.561 +
   1.562 +// ECreateInvalidType
   1.563 +	test.Next(_L("Create chunk of invalid type"));
   1.564 +	TestThreadExit(EExitPanic, EChkCreateInvalidType, ThreadEntry, (TAny*) ECreateInvalidType);
   1.565 +
   1.566 +	test.End();
   1.567 +
   1.568 +	__KHEAP_MARKEND;
   1.569 +	}
   1.570 +
   1.571 +
   1.572 +void testClear(TInt aSize)
   1.573 +	{
   1.574 +	__KHEAP_MARK;
   1.575 +	test.Start(_L("Test clearing memory (Platform Security)"));
   1.576 +	
   1.577 +	RChunk c1,c2,c3,c4,c5,c6,c7,c8,c9,c10;
   1.578 +	TInt r;
   1.579 +	
   1.580 +	TBuf<0x40> b;
   1.581 +	
   1.582 +	b.Copy(_L("Chunk"));
   1.583 +	
   1.584 +	r=c1.CreateGlobal(b,aSize,aSize);
   1.585 +	test(r==KErrNone);
   1.586 +	
   1.587 +	test((TBool)ETrue==CheckChunkCleared(c1));
   1.588 +	c1.Close();
   1.589 +	
   1.590 +	r=c2.CreateLocal(aSize,aSize,EOwnerProcess);
   1.591 +	test(r==KErrNone);
   1.592 +	
   1.593 +	test((TBool)ETrue==CheckChunkCleared(c2));
   1.594 +	c2.Close();
   1.595 +
   1.596 +	r=c3.CreateLocalCode(aSize,aSize,EOwnerProcess);
   1.597 +	test(r==KErrNone);
   1.598 +	
   1.599 +	test((TBool)ETrue==CheckChunkCleared(c3));
   1.600 +	c3.Close();
   1.601 +
   1.602 +	r=c4.CreateDoubleEndedLocal(0x1000,0x1000+aSize,0x100000);
   1.603 +	test(r==KErrNone);
   1.604 +	
   1.605 +	test((TBool)ETrue==CheckChunkCleared(c4,c4.Bottom()));
   1.606 +	c4.Close();
   1.607 +
   1.608 +	r=c5.CreateDoubleEndedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
   1.609 +	test(r==KErrNone);
   1.610 +	
   1.611 +	test((TBool)ETrue==CheckChunkCleared(c5,c5.Bottom()));
   1.612 +	c5.Close();
   1.613 +
   1.614 +	r=c6.CreateDisconnectedLocal(0x1000,0x1000+aSize,0x100000);
   1.615 +	test(r==KErrNone);
   1.616 +	
   1.617 +	test((TBool)ETrue==CheckChunkCleared(c6,0x1000));
   1.618 +	c6.Close();
   1.619 +
   1.620 +	r=c7.CreateDisconnectedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
   1.621 +	test(r==KErrNone);
   1.622 +	
   1.623 +	test((TBool)ETrue==CheckChunkCleared(c7,0x1000));
   1.624 +	c7.Close();
   1.625 +
   1.626 +	test.Next(_L("Test setting the clear byte of RChunk::Create()"));
   1.627 +
   1.628 +	TChunkCreateInfo createInfo;
   1.629 +	createInfo.SetNormal(aSize, aSize);
   1.630 +	test_KErrNone(c10.Create(createInfo));
   1.631 +	TestClearChunk(c10, aSize, KDfltClearByte);
   1.632 +
   1.633 +	createInfo.SetClearByte(0x0);
   1.634 +	test_KErrNone(c8.Create(createInfo));
   1.635 +	TestClearChunk(c8, aSize, 0x0);
   1.636 +
   1.637 +	createInfo.SetClearByte(0xff);
   1.638 +	test_KErrNone(c9.Create(createInfo));
   1.639 +	TestClearChunk(c9, aSize, 0xff);
   1.640 +
   1.641 +	test.End();
   1.642 +	__KHEAP_MARKEND;
   1.643 +	}
   1.644 +
   1.645 +void testShare()
   1.646 +//
   1.647 +// Test sharing a chunk between threads
   1.648 +//
   1.649 +	{
   1.650 +	test.Start(_L("Test chunk sharing between threads"));
   1.651 +
   1.652 +	test.Next(_L("Create chunk Marmalade"));
   1.653 +	TInt r=0;
   1.654 +	RChunk chunk;
   1.655 +	TInt size=0x1000;
   1.656 +	TInt maxSize=0x5000;
   1.657 +	r=0;
   1.658 +	r=chunk.CreateGlobal(_L("Marmalade"),size,maxSize);
   1.659 +	test(r==KErrNone);
   1.660 +	test.Next(_L("Write 0-9 to it"));
   1.661 +	TUint8* base=chunk.Base();
   1.662 +	for (TInt8 j=0;j<10;j++)
   1.663 +		*base++=j; // write 0 - 9 to the chunk
   1.664 +
   1.665 +	RThread t;
   1.666 +	TRequestStatus stat;
   1.667 +	test.Next(_L("Create reader thread"));
   1.668 +	r=t.Create(_L("RChunkShareThread"), ThreadEntry2, KDefaultStackSize,KHeapSize,KHeapSize,NULL);
   1.669 +	test(r==KErrNone);
   1.670 +	t.Logon(stat);
   1.671 +	test.Next(_L("Resume reader thread"));
   1.672 +	t.Resume();
   1.673 +	User::WaitForRequest(stat);	
   1.674 +	CLOSE_AND_WAIT(t);
   1.675 +	chunk.Close();
   1.676 +
   1.677 +	test.End();
   1.678 +	}
   1.679 +
   1.680 +void FindChunks()
   1.681 +    { // taken from some code written by SteveG
   1.682 +    test.Start(_L("Finding chunks...\n"));
   1.683 +
   1.684 +    TFullName name=_L("*");
   1.685 +    TFindChunk find(name);
   1.686 +	TInt i=0;
   1.687 +
   1.688 +
   1.689 +    while (find.Next(name)==KErrNone)
   1.690 +        {
   1.691 +        RChunk chunk;
   1.692 +        test.Printf(_L("Chunk name %S\n"),&name);
   1.693 +		TInt err=chunk.Open(find);
   1.694 +        if (err)
   1.695 +            test.Printf(_L("Error %d opening chunk"),err);
   1.696 +        else
   1.697 +        	{
   1.698 +			TBuf<16> access;
   1.699 +			if (chunk.IsWritable())
   1.700 +				access=_L("ReadWrite");
   1.701 +			else if (chunk.IsReadable())
   1.702 +				access=_L("ReadOnly");
   1.703 +			else
   1.704 +				access=_L("No Access");
   1.705 +            test.Printf(_L("Chunk size %08x bytes, %S\n"),chunk.Size(),&access);
   1.706 +			chunk.Close();
   1.707 +			i++;
   1.708 +			}
   1.709 +        User::After(1000000);
   1.710 +  	    }
   1.711 +    test.End();
   1.712 +    }
   1.713 +
   1.714 +void testAdjustChunk()
   1.715 +	{
   1.716 +	test.Start(_L("Test adjusting chunks"));
   1.717 +
   1.718 +	RChunk hermione;
   1.719 +	
   1.720 +	test.Next(_L("Create global chunk"));
   1.721 +	TInt r=hermione.CreateGlobal(_L("Hermione"),0x1000,0x100000);
   1.722 +	test(r==KErrNone);
   1.723 +	TUint32* base=(TUint32*)hermione.Base();
   1.724 +	TUint32* top=(TUint32*)(hermione.Base()+hermione.Size());
   1.725 +	TUint32* i;
   1.726 +
   1.727 +	test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
   1.728 +	test.Next(_L("Check I can write to all of it"));
   1.729 +	for (i=base;i<top;i++)
   1.730 +		*i=0xdeaddead;
   1.731 +
   1.732 +	test.Next(_L("Adjust the chunk"));
   1.733 +	r=hermione.Adjust(0x1400);
   1.734 +	test(r==KErrNone);
   1.735 +
   1.736 +	base=(TUint32*)hermione.Base();
   1.737 +	top=(TUint32*)(hermione.Base()+hermione.Size());
   1.738 +	test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
   1.739 +	test.Next(_L("Check I can write to all of the bigger chunk"));
   1.740 +	for (i=base;i<top;i++)
   1.741 +		*i=0xdeaddead;
   1.742 +
   1.743 +	hermione.Close();
   1.744 +
   1.745 +	test.Next(_L("Do some size checks"));
   1.746 +	RChunk wibble;
   1.747 +	r=wibble.CreateGlobal(_L("Wibble"),0x1,gPageSize*8);
   1.748 +	test(r==KErrNone);
   1.749 +	test.Next(_L("Check create rounds up to page multiple"));
   1.750 +	test(wibble.Size()==(TInt)gPageSize);
   1.751 +	test.Next(_L("Check create rounds up to chunk multiple"));
   1.752 +	test(wibble.MaxSize()==roundToChunkSize(gPageSize*8));
   1.753 +
   1.754 +	test.Next(_L("Check adjust rounds up to page multiple"));
   1.755 +	r=wibble.Adjust((gPageSize*6)-12);
   1.756 +	test(r==KErrNone);
   1.757 +	test(wibble.Size()==gPageSize*6);
   1.758 +
   1.759 +	test.Next(_L("Different number, same size"));
   1.760 +	r=wibble.Adjust((gPageSize*6)-18);
   1.761 +	test(r==KErrNone);
   1.762 +	test(wibble.Size()==gPageSize*6);
   1.763 +
   1.764 +	test.Next(_L("Check adjust > MaxSize returns error"));
   1.765 +	r=wibble.Adjust(wibble.MaxSize()+gPageSize);
   1.766 +	test(r==KErrArgument);
   1.767 +
   1.768 +	wibble.Close();
   1.769 +	test.End();
   1.770 +	}
   1.771 +
   1.772 +TInt NotifierCount=0;
   1.773 +TInt OOMCount=0;
   1.774 +RChangeNotifier Notifier;
   1.775 +RThread NtfThrd;
   1.776 +_LIT(KNotifierThreadName,"NotifierThread");
   1.777 +
   1.778 +TInt NotifierThread(TAny*)
   1.779 +	{
   1.780 +	TInt r=Notifier.Create();
   1.781 +	while (r==KErrNone)
   1.782 +		{
   1.783 +		TRequestStatus s;
   1.784 +		r=Notifier.Logon(s);
   1.785 +		if (r!=KErrNone)
   1.786 +			break;
   1.787 +		User::WaitForRequest(s);
   1.788 +		if (s.Int()&EChangesFreeMemory)
   1.789 +			++NotifierCount;
   1.790 +		if (s.Int()&EChangesOutOfMemory)
   1.791 +			++OOMCount;
   1.792 +		}
   1.793 +	Notifier.Close();
   1.794 +	return r;
   1.795 +	}
   1.796 +
   1.797 +
   1.798 +void WaitForNotifier()
   1.799 +	{
   1.800 +	User::After(500000);		// wait for notifier
   1.801 +	}
   1.802 +
   1.803 +
   1.804 +void CheckNotifierCount(TInt aLevel, TInt aOom)
   1.805 +	{
   1.806 +	WaitForNotifier();
   1.807 +	if (NtfThrd.ExitType()!=EExitPending)
   1.808 +		{
   1.809 +		TExitCategoryName exitCat=NtfThrd.ExitCategory();
   1.810 +		test.Printf(_L("Thread exited: %d,%d,%S"),NtfThrd.ExitType(),NtfThrd.ExitReason(),&exitCat);
   1.811 +		test(0);
   1.812 +		}
   1.813 +	TInt c1=NotifierCount;
   1.814 +	TInt c2=OOMCount;
   1.815 +	if (c1!=aLevel || c2!=aOom)
   1.816 +		{
   1.817 +		test.Printf(_L("Count %d,%d Expected %d,%d"),c1,c2,aLevel,aOom);
   1.818 +		test(0);
   1.819 +		}
   1.820 +	}
   1.821 +
   1.822 +void testNotifiers()
   1.823 +	{
   1.824 +	RGobbler gobbler;
   1.825 +	TInt r = gobbler.Open();
   1.826 +	test(r==KErrNone);
   1.827 +	TUint32 taken = gobbler.GobbleRAM(128*1024*1024);
   1.828 +	test.Printf(_L("Gobbled: %dK\n"), taken/1024);
   1.829 +	test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam());
   1.830 +
   1.831 +	test.Next(_L("Create thread"));
   1.832 +	r=NtfThrd.Create(KNotifierThreadName,NotifierThread,KDefaultStackSize,NULL,NULL);
   1.833 +	test(r==KErrNone);
   1.834 +	NtfThrd.SetPriority(EPriorityMore);
   1.835 +	NtfThrd.Resume();
   1.836 +	test.Next(_L("Check for initial notifier"));
   1.837 +	CheckNotifierCount(1,1);
   1.838 +	TInt free=FreeRam();
   1.839 +	test.Printf(_L("Free RAM: %dK\n"),free/1024);
   1.840 +	test(free>=1048576);
   1.841 +	test.Next(_L("Set thresholds"));
   1.842 +	r=UserSvr::SetMemoryThresholds(65536,524288);	// low=64K good=512K
   1.843 +	test(r==KErrNone);
   1.844 +	test.Next(_L("Create chunk"));
   1.845 +	// Chunk must not be paged otherwise it will not effect the amount 
   1.846 +	// of free ram reported plus on h4 swap size is less than the total ram.
   1.847 +	TChunkCreateInfo createInfo;
   1.848 +	createInfo.SetNormal(0, free+2097152);
   1.849 +	createInfo.SetPaging(TChunkCreateInfo::EUnpaged);
   1.850 +	RChunk c;
   1.851 +	test_KErrNone(c.Create(createInfo));
   1.852 +	const TInt KBufferSpace = 768*1024;	// 768K buffer
   1.853 +	CheckNotifierCount(1,1);
   1.854 +	test.Next(_L("Leave 768K"));
   1.855 +	r=c.Adjust(free-KBufferSpace);	// leave 768K
   1.856 +	test(r==KErrNone);
   1.857 +	CheckNotifierCount(1,1);		// shouldn't get notifier
   1.858 +	TInt free2=FreeRam();
   1.859 +	test.Printf(_L("Free RAM: %dK\n"),free2/1024);
   1.860 +	test(free2<=KBufferSpace);
   1.861 +	TInt free3=free-(KBufferSpace-free2);	// this accounts for space used by page tables
   1.862 +	test.Next(_L("Leave 32K"));
   1.863 +	r=c.Adjust(free3-32768);		// leave 32K
   1.864 +	test(r==KErrNone);
   1.865 +	CheckNotifierCount(2,1);		// should get notifier
   1.866 +	test.Next(_L("Leave 28K"));
   1.867 +	r=c.Adjust(free3-28672);		// leave 28K
   1.868 +	test(r==KErrNone);
   1.869 +	CheckNotifierCount(2,1);		// shouldn't get another notifier
   1.870 +	test.Next(_L("Ask for too much"));
   1.871 +	r=c.Adjust(free3+4096);			// try to get more than available
   1.872 +	test(r==KErrNoMemory);
   1.873 +	CheckNotifierCount(2,2);		// should get another notifier
   1.874 +	test.Next(_L("Leave 128K"));
   1.875 +	r=c.Adjust(free3-131072);		// leave 128K
   1.876 +	test(r==KErrNone);
   1.877 +	CheckNotifierCount(2,2);		// shouldn't get another notifier
   1.878 +	test.Next(_L("Leave 640K"));
   1.879 +	r=c.Adjust(free3-655360);		// leave 640K
   1.880 +	test(r==KErrNone);
   1.881 +	CheckNotifierCount(3,2);		// should get another notifier
   1.882 +	test.Next(_L("Leave 1M"));
   1.883 +	r=c.Adjust(free3-1048576);		// leave 1M
   1.884 +	test(r==KErrNone);
   1.885 +	CheckNotifierCount(3,2);		// shouldn't get another notifier
   1.886 +	test.Next(_L("Ask for too much"));
   1.887 +	r=c.Adjust(free3+4096);			// try to get more than available
   1.888 +	test(r==KErrNoMemory);
   1.889 +
   1.890 +	TInt notifierCount = 3;
   1.891 +	if(MemModel==EMemModelTypeFlexible)
   1.892 +		{
   1.893 +		// on flexible memory model, we get memory changed notifiers
   1.894 +		// on failed memory allocation; this hack lets the test code
   1.895 +		// pass this as acceptable behaviour...
   1.896 +		WaitForNotifier();
   1.897 +		notifierCount = NotifierCount; // expect whatever we actually got
   1.898 +		}
   1.899 +
   1.900 +	CheckNotifierCount(notifierCount,3);		// should get another notifier
   1.901 +	test.Next(_L("Leave 1M"));
   1.902 +	r=c.Adjust(free3-1048576);					// leave 1M
   1.903 +	test(r==KErrNone);
   1.904 +	CheckNotifierCount(notifierCount,3);		// shouldn't get another notifier
   1.905 +
   1.906 +	c.Close();
   1.907 +	TRequestStatus s;
   1.908 +	NtfThrd.Logon(s);
   1.909 +	NtfThrd.Kill(0);
   1.910 +	User::WaitForRequest(s);
   1.911 +	CLOSE_AND_WAIT(NtfThrd);
   1.912 +	Notifier.Close();
   1.913 +	gobbler.Close();
   1.914 +	}
   1.915 +
   1.916 +
   1.917 +// TestFullAddressSpace is used to stress the memory allocation mechanism(beyond the 1GB limit).
   1.918 +// However, the memory model can introduce limitations in the total amount of memory a single 
   1.919 +// process is allowed to allocate. To make the test more generic before closing the reserved 
   1.920 +// chunks for this test we trigger the creation of a new process. This process executes 
   1.921 +// t_chunk again, passing argument "extended". The result is that more chunks will be created
   1.922 +// through another call to TestFullAddressSpace, with the parameter extendedFlag set to true. 
   1.923 +// Eventually the total amount of allocated space will overcome the 1Gb limit in any case.
   1.924 +
   1.925 +void TestFullAddressSpace(TBool extendedFlag )
   1.926 +	{
   1.927 +	test.Start(_L("Fill process address space with chunks\n"));
   1.928 +	RChunk chunk[2][11];
   1.929 +	TInt total = 0;
   1.930 +	TInt i;
   1.931 +	TInt j;
   1.932 +	TInt r;
   1.933 +		
   1.934 +	for(j=0; j<=1; j++)
   1.935 +		{
   1.936 +		if(!j)
   1.937 +			test.Next(_L("Creating local chunks"));
   1.938 +		else
   1.939 +			test.Next(_L("Creating global chunks"));
   1.940 +		for(i=10; i>=0; --i)
   1.941 +			{
   1.942 +			TInt size = 1<<(20+i);
   1.943 +			
   1.944 +			if(!j)
   1.945 +				r = chunk[j][i].CreateDisconnectedLocal(0,0,size);
   1.946 +			else
   1.947 +				r = chunk[j][i].CreateDisconnectedGlobal(KNullDesC,0,0,size);
   1.948 +			TBuf<128> text;
   1.949 +			text.AppendFormat(_L("Create %dMB chunk returns %d"),1<<i,r);
   1.950 +			test.Next(text);
   1.951 +			if(r!=KErrNoMemory)
   1.952 +				{
   1.953 +				test(r==KErrNone);
   1.954 +				// commit memory to each 1MB region,
   1.955 +				// this excercises page table allocation
   1.956 +				volatile TUint8* base = (TUint8*)chunk[j][i].Base();
   1.957 +				for(TInt o=0; o<size; o+=1<<20)
   1.958 +					{
   1.959 +					r = chunk[j][i].Commit(o,1);
   1.960 +					test(r==KErrNone);
   1.961 +					// access the commited memory...
   1.962 +					base[o] = (TUint8)(o&0xff);
   1.963 +					test(base[o]==(TUint8)(o&0xff));
   1.964 +					base[o] = (TUint8)~(o&0xff);
   1.965 +					test(base[o]==(TUint8)~(o&0xff));
   1.966 +					}
   1.967 +				total += 1<<i;
   1.968 +				}
   1.969 +			}
   1.970 +		}
   1.971 +		
   1.972 +	if (extendedFlag == EFalse)
   1.973 +		{
   1.974 +		
   1.975 +		test.Printf(_L("Total chunk size created was %d MB\n\n"),total);	  
   1.976 +
   1.977 +		if(total<1024)
   1.978 +			{
   1.979 +			_LIT(KOtherProcessName,"t_chunk");
   1.980 +			_LIT(KProcessArgs,"extended");
   1.981 +			
   1.982 +			RProcess process;      
   1.983 +			r=process.Create(KOtherProcessName,KProcessArgs );
   1.984 +			test.Printf(_L("Creating new process( t_chunk extended) returns %d\n"),r );
   1.985 +			test( r == KErrNone);
   1.986 +		   
   1.987 +			TRequestStatus status;
   1.988 +			process.Logon(status);
   1.989 +			process.Resume(); 
   1.990 +			
   1.991 +			User::WaitForRequest(status);
   1.992 +			  
   1.993 +			test(process.ExitType() == EExitKill);
   1.994 +			test(process.ExitReason() == 0);
   1.995 +			process.Close();
   1.996 +			}
   1.997 +	
   1.998 +		}           
   1.999 +  	else
  1.1000 +  		test.Printf(_L("Total chunk size created by the new process was %d MB\n"),total); 
  1.1001 + 
  1.1002 +	for(j=0; j<=1; j++)
  1.1003 +		for(i=10; i>=0; --i)
  1.1004 +			chunk[j][i].Close();
  1.1005 +	test.End();
  1.1006 +	}	
  1.1007 +
  1.1008 +
  1.1009 +#ifdef __WINS__
  1.1010 +void TestExecLocalCode()
  1.1011 +	{
  1.1012 +	RChunk c;
  1.1013 +	TInt size = 10 * 1024;
  1.1014 +	TInt rc = c.CreateLocalCode(size, size, EOwnerProcess);
  1.1015 +	test_KErrNone(rc);
  1.1016 +	TUint8 *p = c.Base();
  1.1017 +	TUint32 (*func)() = (TUint32 (*)())p;
  1.1018 +	test.Printf(_L("Create small function in the new code chunk\n"));
  1.1019 +	*p++ = 0xB8;		// mov eax, 0x12345678
  1.1020 +	*p++ = 0x78;
  1.1021 +	*p++ = 0x56;
  1.1022 +	*p++ = 0x34;
  1.1023 +	*p++ = 0x12;
  1.1024 +	*p   = 0xC3;		// ret
  1.1025 +	test.Printf(_L("Going to call the new function\n"));
  1.1026 +	TUint32 res = (*func)();
  1.1027 +	test_Equal(0x12345678, res);
  1.1028 +	c.Close();
  1.1029 +	}
  1.1030 +#endif	//  __WINS__
  1.1031 +
  1.1032 +
  1.1033 +_LIT(KChunkName, "CloseChunk");
  1.1034 +
  1.1035 +struct TRequestData
  1.1036 +	{
  1.1037 +	RSemaphore requestSem;
  1.1038 +	RSemaphore completionSem;
  1.1039 +	RSemaphore nextItSem;
  1.1040 +	};
  1.1041 +
  1.1042 +TInt CloseThread(TAny* data)
  1.1043 +	{
  1.1044 +	TRequestData* reqData = (TRequestData*)data;
  1.1045 +	ASSERT(reqData);
  1.1046 +	
  1.1047 +	for(;;)
  1.1048 +		{
  1.1049 +		// Wait for a request to open and close the chunk.
  1.1050 +		reqData->requestSem.Wait();
  1.1051 +		
  1.1052 +		// Try to open the chunk (may have already been closed by another thread).
  1.1053 +		RChunk chunk;
  1.1054 +		TInt r = chunk.OpenGlobal(KChunkName, EFalse, EOwnerThread);
  1.1055 +		if (r != KErrNone)
  1.1056 +			{
  1.1057 +			// The chunk was already closed...
  1.1058 +			r = (r == KErrNotFound) ? KErrNone : r;	// Ensure no debug output for expected failures.
  1.1059 +			
  1.1060 +			if(r != KErrNone)
  1.1061 +				{
  1.1062 +				test.Printf(_L("CloseThread RChunk::OpenGlobal Err: %d\n"), r);
  1.1063 +				test_KErrNone(r);
  1.1064 +				}
  1.1065 +			}
  1.1066 +		else
  1.1067 +			{ 
  1.1068 +			// Close the chunk.
  1.1069 +			chunk.Close();
  1.1070 +			}
  1.1071 +		
  1.1072 +		// Tell our parent we have completed this iteration and wait for the next.
  1.1073 +		reqData->completionSem.Signal();
  1.1074 +		reqData->nextItSem.Wait();
  1.1075 +		}
  1.1076 +	}
  1.1077 +
  1.1078 +void TestClosure()
  1.1079 +	{
  1.1080 +	const TUint KCloseThreads = 50;
  1.1081 +	RThread thread[KCloseThreads];
  1.1082 +	TRequestStatus dead[KCloseThreads];
  1.1083 +
  1.1084 +	// We need three semaphores or we risk signal stealing if one thread gets ahead of the
  1.1085 +	// others and starts a second iteration before the other threads have been signalled
  1.1086 +	// and have begun their first iteration.  Such a situation results in deadlock so we
  1.1087 +	// force all threads to finish the iteration first using the nextItSem semaphore to
  1.1088 +	// ensure we can only move to the next iteration once every thread has completed the
  1.1089 +	// current iteration.
  1.1090 +	TRequestData reqData;
  1.1091 +	test_KErrNone(reqData.requestSem.CreateLocal(0));
  1.1092 +	test_KErrNone(reqData.completionSem.CreateLocal(0));
  1.1093 +	test_KErrNone(reqData.nextItSem.CreateLocal(0));
  1.1094 +	
  1.1095 +	TUint i = 0;
  1.1096 +
  1.1097 +	// Create thread pool.  We do this rather than create 50 threads
  1.1098 +	// over and over again for 800 times - the kernel's garbage collection
  1.1099 +	// does not keep up and we run out of backing store.
  1.1100 +	for (; i < KCloseThreads; i++)
  1.1101 +		{
  1.1102 +		test_KErrNone(thread[i].Create(KNullDesC, CloseThread, KDefaultStackSize, NULL, (TAny*)&reqData));
  1.1103 +		thread[i].Logon(dead[i]);
  1.1104 +		thread[i].SetPriority(EPriorityMuchLess);
  1.1105 +		thread[i].Resume();
  1.1106 +		}
  1.1107 +
  1.1108 +	for (TUint delay = 200; delay < 1000; delay++)
  1.1109 +		{
  1.1110 +		test.Printf(_L("Closure delay %dus\r"), delay);
  1.1111 +
  1.1112 +		// Create a global chunk.
  1.1113 +		RChunk chunk;
  1.1114 +		test_KErrNone(chunk.CreateGlobal(KChunkName, gPageSize, gPageSize));
  1.1115 +
  1.1116 +		// Release the threads so they can try to close the handle.
  1.1117 +		reqData.requestSem.Signal(KCloseThreads);
  1.1118 +
  1.1119 +		// Wait for the delay then close the handle ourselves.
  1.1120 +		User::AfterHighRes(delay);
  1.1121 +		chunk.Close();
  1.1122 +
  1.1123 +		// Wait for the threads to complete then release them for the next iteration.
  1.1124 +		for (i = 0; i < KCloseThreads; i++)
  1.1125 +			{
  1.1126 +			reqData.completionSem.Wait();
  1.1127 +			}
  1.1128 +		reqData.nextItSem.Signal(KCloseThreads);
  1.1129 +
  1.1130 +		// Ensure garbage collection is complete to prevent the kernel's
  1.1131 +		// garbage collection from being overwhelmed and causing the
  1.1132 +		// backing store to be exhausted.
  1.1133 +		UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
  1.1134 +		}
  1.1135 +
  1.1136 +	// Kill thread pool.
  1.1137 +	for (i = 0; i < KCloseThreads; i++)
  1.1138 +		{
  1.1139 +		thread[i].Kill(KErrNone);
  1.1140 +		User::WaitForRequest(dead[i]);
  1.1141 +		test(KErrNone == thread[i].ExitReason());
  1.1142 +		test_Equal(EExitKill, thread[i].ExitType());
  1.1143 +		thread[i].Close();
  1.1144 +		}
  1.1145 +		
  1.1146 +	reqData.requestSem.Close();
  1.1147 +	reqData.completionSem.Close();
  1.1148 +	reqData.nextItSem.Close();
  1.1149 +
  1.1150 +	// Ensure garbage collection is complete to prevent false positive
  1.1151 +	// kernel memory leaks.
  1.1152 +	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
  1.1153 +	}
  1.1154 +	
  1.1155 +
  1.1156 +/**Returns true if argument is found in the command line*/
  1.1157 +TBool IsInCommandLine(const TDesC& aArg)
  1.1158 +	{
  1.1159 +	TBuf<64> c;
  1.1160 +	User::CommandLine(c);
  1.1161 +	if (c.FindF(aArg) >= 0)
  1.1162 +		return ETrue;
  1.1163 +	return EFalse;
  1.1164 +	}
  1.1165 +
  1.1166 +_LIT(KTestChunkReadOnly, "TestReadOnlyChunk");
  1.1167 +_LIT(KTestSemaphoreReadOnly, "TestReadOnlySemaphore");
  1.1168 +_LIT(KTestParamRo, "restro");
  1.1169 +_LIT(KTestParamRw, "restrw");
  1.1170 +_LIT(KTestParamWait, "restwait");
  1.1171 +_LIT(KTestParamWritableChunk, "restwritable");
  1.1172 +
  1.1173 +enum TTestProcessParameters
  1.1174 +	{
  1.1175 +	ETestRw = 0x1,
  1.1176 +	ETestWait = 0x2,
  1.1177 +	ETestWritableChunk = 0x4,
  1.1178 +	};
  1.1179 +
  1.1180 +void TestReadOnlyProcess(TUint aParams)
  1.1181 +	{
  1.1182 +	TInt r;
  1.1183 +	RChunk chunk;
  1.1184 +	RSemaphore sem;
  1.1185 +
  1.1186 +	test.Start(_L("Open global chunk"));
  1.1187 +	r = chunk.OpenGlobal(KTestChunkReadOnly, EFalse);
  1.1188 +	test_KErrNone(r);
  1.1189 +
  1.1190 +	test(chunk.IsReadable());
  1.1191 +	r = chunk.Adjust(1);
  1.1192 +	if (aParams & ETestWritableChunk)
  1.1193 +		{
  1.1194 +		test(chunk.IsWritable());
  1.1195 +		test_KErrNone(r);
  1.1196 +		}
  1.1197 +	else
  1.1198 +		{
  1.1199 +		test(!chunk.IsWritable());
  1.1200 +		test_Equal(KErrAccessDenied, r);
  1.1201 +		}
  1.1202 +
  1.1203 +	if (aParams & ETestWait)
  1.1204 +		{
  1.1205 +		RProcess::Rendezvous(KErrNone);
  1.1206 +		test.Next(_L("Wait on semaphore"));
  1.1207 +		r = sem.OpenGlobal(KTestSemaphoreReadOnly);
  1.1208 +		test_KErrNone(r);
  1.1209 +		sem.Wait();
  1.1210 +		}
  1.1211 +
  1.1212 +	test.Next(_L("Read"));
  1.1213 +	TUint8 read = *(volatile TUint8*) chunk.Base();
  1.1214 +	(void) read;
  1.1215 +
  1.1216 +	if (aParams & ETestRw)
  1.1217 +		{
  1.1218 +		test.Next(_L("Write"));
  1.1219 +		TUint8* write = chunk.Base();
  1.1220 +		*write = 0x3d;
  1.1221 +		}
  1.1222 +
  1.1223 +	chunk.Close();
  1.1224 +	if (aParams & ETestWait)
  1.1225 +		{
  1.1226 +		sem.Close();
  1.1227 +		}
  1.1228 +	test.End();
  1.1229 +	}
  1.1230 +
  1.1231 +void TestReadOnly()
  1.1232 +	{
  1.1233 +	TInt r;
  1.1234 +	RChunk chunk;
  1.1235 +	RProcess process1;
  1.1236 +	RProcess process2;
  1.1237 +	RSemaphore sem;
  1.1238 +	TRequestStatus rs;
  1.1239 +	TRequestStatus rv;
  1.1240 +
  1.1241 +	// Assumption is made that any memory model from Flexible onwards that supports
  1.1242 +	// read-only memory also supports read-only chunks
  1.1243 +	if (MemModelType() < EMemModelTypeFlexible || !HaveWriteProt())
  1.1244 +		{
  1.1245 +		test.Printf(_L("Memory model is not expected to support Read-Only Chunks\n"));
  1.1246 +		return;
  1.1247 +		}
  1.1248 +
  1.1249 +	TBool jit = User::JustInTime();
  1.1250 +	User::SetJustInTime(EFalse);
  1.1251 +
  1.1252 +	test.Start(_L("Create writable global chunk"));
  1.1253 +	TChunkCreateInfo info;
  1.1254 +	info.SetNormal(0, 1234567);
  1.1255 +	info.SetGlobal(KTestChunkReadOnly);
  1.1256 +	r = chunk.Create(info);
  1.1257 +	test_KErrNone(r);
  1.1258 +	test(chunk.IsReadable());
  1.1259 +	test(chunk.IsWritable());
  1.1260 +
  1.1261 +	test.Next(_L("Adjust size"));
  1.1262 +	r = chunk.Adjust(1); // add one page
  1.1263 +	test_KErrNone(r);
  1.1264 +
  1.1265 +	test.Next(_L("Attempt read/write 1"));
  1.1266 +	r = process1.Create(RProcess().FileName(), KTestParamWritableChunk);
  1.1267 +	test_KErrNone(r);
  1.1268 +	process1.Logon(rs);
  1.1269 +	process1.Resume();
  1.1270 +	User::WaitForRequest(rs);
  1.1271 +	test_Equal(EExitKill, process1.ExitType());
  1.1272 +	test_KErrNone(process1.ExitReason());
  1.1273 +	CLOSE_AND_WAIT(process1);
  1.1274 +	CLOSE_AND_WAIT(chunk);
  1.1275 +
  1.1276 +	test.Next(_L("Create read-only global chunk"));
  1.1277 +	info.SetReadOnly();
  1.1278 +	r = chunk.Create(info);
  1.1279 +	test_KErrNone(r);
  1.1280 +	test(chunk.IsReadable());
  1.1281 +	test(chunk.IsWritable());
  1.1282 +	// To keep in sync with the 'process2' process
  1.1283 +	r = sem.CreateGlobal(KTestSemaphoreReadOnly, 0);
  1.1284 +	test_KErrNone(r);
  1.1285 +
  1.1286 +	test.Next(_L("Attempt read 1"));
  1.1287 +	r = process1.Create(RProcess().FileName(), KTestParamRo);
  1.1288 +	test_KErrNone(r);
  1.1289 +	process1.Logon(rs);
  1.1290 +	process1.Resume();
  1.1291 +	User::WaitForRequest(rs);
  1.1292 +	test_Equal(EExitPanic, process1.ExitType());
  1.1293 +	test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
  1.1294 +	CLOSE_AND_WAIT(process1);
  1.1295 +	// Create second process before commiting memory and make it wait
  1.1296 +	r = process2.Create(RProcess().FileName(), KTestParamWait);
  1.1297 +	test_KErrNone(r)
  1.1298 +	process2.Rendezvous(rv);
  1.1299 +	process2.Resume();
  1.1300 +	User::WaitForRequest(rv);
  1.1301 +
  1.1302 +	test.Next(_L("Adjust size"));
  1.1303 +	r = chunk.Adjust(1); // add one page
  1.1304 +	test_KErrNone(r);
  1.1305 +
  1.1306 +	test.Next(_L("Attempt read 2"));
  1.1307 +	r = process1.Create(RProcess().FileName(), KTestParamRo);
  1.1308 +	test_KErrNone(r);
  1.1309 +	process1.Logon(rs);
  1.1310 +	process1.Resume();
  1.1311 +	User::WaitForRequest(rs);
  1.1312 +	test_Equal(EExitKill, process1.ExitType());
  1.1313 +	test_KErrNone(process1.ExitReason());
  1.1314 +	CLOSE_AND_WAIT(process1);
  1.1315 +
  1.1316 +	test.Next(_L("Attempt read/write 1"));
  1.1317 +	r = process1.Create(RProcess().FileName(), KTestParamRw);
  1.1318 +	test_KErrNone(r);
  1.1319 +	process1.Logon(rs);
  1.1320 +	process1.Resume();
  1.1321 +	User::WaitForRequest(rs);
  1.1322 +	test_Equal(EExitPanic, process1.ExitType());
  1.1323 +	test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
  1.1324 +	CLOSE_AND_WAIT(process1);
  1.1325 +	// Controlling process is not affected
  1.1326 +	TUint8* write = chunk.Base();
  1.1327 +	*write = 0x77;
  1.1328 +
  1.1329 +	test.Next(_L("Attempt read/write 2"));
  1.1330 +	test_Equal(EExitPending, process2.ExitType());
  1.1331 +	process2.Logon(rs);
  1.1332 +	sem.Signal();
  1.1333 +	User::WaitForRequest(rs);
  1.1334 +	test_Equal(EExitPanic, process2.ExitType());
  1.1335 +	test_Equal(3, process2.ExitReason()); // KERN-EXEC 3 assumed
  1.1336 +	CLOSE_AND_WAIT(process2);
  1.1337 +
  1.1338 +	chunk.Close();
  1.1339 +	sem.Close();
  1.1340 +	test.End();
  1.1341 +	User::SetJustInTime(jit);
  1.1342 +	}
  1.1343 +
  1.1344 +TInt E32Main()
  1.1345 +//
  1.1346 +//	Test RChunk class
  1.1347 +//
  1.1348 +	{
  1.1349 +	test.Title();
  1.1350 +	if (!HaveVirtMem())
  1.1351 +		{
  1.1352 +		test.Printf(_L("This test requires an MMU\n"));
  1.1353 +		return KErrNone;
  1.1354 +		}
  1.1355 +	testInitialise();
  1.1356 +
  1.1357 +	// Turn off lazy dll unloading so the kernel heap checking isn't affected.
  1.1358 +	RLoader l;
  1.1359 +	test(l.Connect()==KErrNone);
  1.1360 +	test(l.CancelLazyDllUnload()==KErrNone);
  1.1361 +	l.Close();
  1.1362 +
  1.1363 +	_LIT(KExtended,"extended");
  1.1364 +
  1.1365 +	if (IsInCommandLine(KExtended))
  1.1366 +		{
  1.1367 +		__KHEAP_MARK;
  1.1368 +		test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
  1.1369 +		TestFullAddressSpace(ETrue);
  1.1370 +		__KHEAP_MARKEND;
  1.1371 +		}
  1.1372 +	else if (IsInCommandLine(KTestParamRo))
  1.1373 +		{
  1.1374 +		test_KErrNone(User::RenameProcess(KTestParamRo));
  1.1375 +		TestReadOnlyProcess(0);
  1.1376 +		}
  1.1377 +	else if (IsInCommandLine(KTestParamRw))
  1.1378 +		{
  1.1379 +		test_KErrNone(User::RenameProcess(KTestParamRw));
  1.1380 +		TestReadOnlyProcess(ETestRw);
  1.1381 +		}
  1.1382 +	else if (IsInCommandLine(KTestParamWait))
  1.1383 +		{
  1.1384 +		test_KErrNone(User::RenameProcess(KTestParamWait));
  1.1385 +		TestReadOnlyProcess(ETestRw | ETestWait);
  1.1386 +		}
  1.1387 +	else if (IsInCommandLine(KTestParamWritableChunk))
  1.1388 +		{
  1.1389 +		test_KErrNone(User::RenameProcess(KTestParamWritableChunk));
  1.1390 +		TestReadOnlyProcess(ETestWritableChunk | ETestRw);
  1.1391 +		}
  1.1392 +	else 
  1.1393 +		{
  1.1394 +		__KHEAP_MARK;
  1.1395 +		test.Start(_L("Testing.."));
  1.1396 +		testAdjustChunk();
  1.1397 +		test.Next(_L("Test1"));
  1.1398 +		test1();
  1.1399 +		test.Next(_L("Test2"));
  1.1400 +		test2(0x80);
  1.1401 +		test.Next(_L("Test3"));
  1.1402 +		test3(0x7000);
  1.1403 +		test.Next(_L("Test4"));
  1.1404 +		test4(0x7000);
  1.1405 +		test.Next(_L("Test5"));
  1.1406 +		test5(0x80);
  1.1407 +		test.Next(_L("Test7"));
  1.1408 +		test7(0x80);
  1.1409 +		test.Next(_L("Test chunk data clearing attributes"));
  1.1410 +		testClear(0x500);
  1.1411 +		testClear(07000);
  1.1412 +		test.Next(_L("Test9"));
  1.1413 +		testShare();
  1.1414 +		test.Next(_L("Test memory notifiers"));
  1.1415 +		testNotifiers();
  1.1416 +		test.Next(_L("FindChunks"));
  1.1417 +		FindChunks();
  1.1418 +		
  1.1419 +		test.Next(_L("Test full address space"));
  1.1420 +		TestFullAddressSpace(EFalse);
  1.1421 +
  1.1422 +#ifdef __WINS__
  1.1423 +		test.Next(_L("Test execution of code in a local code chunk on emulator"));
  1.1424 +		TestExecLocalCode();
  1.1425 +#endif	//  __WINS__
  1.1426 +
  1.1427 +		test.Next(_L("Test for race conditions in chunk closure"));
  1.1428 +		TestClosure();
  1.1429 +		test.Next(_L("Read-only chunks"));
  1.1430 +		TestReadOnly();
  1.1431 +		test.End();
  1.1432 +		__KHEAP_MARKEND;
  1.1433 +		}
  1.1434 +
  1.1435 +	test.Close();
  1.1436 +	return(KErrNone);
  1.1437 +	}