os/kernelhwsrv/kerneltest/e32test/mmu/t_chunk.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1995-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\mmu\t_chunk.cpp
    15 // Overview:
    16 // Test RChunk class
    17 // API Information:
    18 // RChunk, RChangeNotifier, TFindChunk
    19 // Details:
    20 // - Test adjusting chunks: create a global chunk, adjust it, do some size 
    21 // checks, verify Create() rounds up to chunk multiple, verify that adjust
    22 // request for size greater than MaxSize returns an error.
    23 // - Test creating chunks with small sizes (0 and 1), verify results are as expected.
    24 // - Create multiple local and global chunks, verify that Size,MaxSize,Name & FullName methods 
    25 // are as expected. 
    26 // Check Create method of global chunk if the name is already in use. Check the name can be 
    27 // reused after the chunk is closed.
    28 // - Perform adjust tests on a chunk, verify results are as expected.
    29 // - Open and test global chunks with multiple references, verify results are as expected.
    30 // - Open and test local chunks, check TFindChunk::Next method, verify results are as expected.
    31 // - Check user thread is panicked if it creates or adjusts chunk with negative size or of an
    32 // invalid type or with an invalid name.
    33 // - Check the chunk is filled in with the appropriate clear value after creation, verify results
    34 // are as expected.
    35 // - Test sharing a chunk between threads, verify results are as expected.
    36 // - Create a thread to watch for notification of changes in free memory and
    37 // changes in out of memory status. Verify adjusting an RChunk generates
    38 // the expected notifications.
    39 // - Test finding a global chunk by name and verify results are as expected.
    40 // - Check read-only global chunks cannot be written to by other processes.
    41 // Platforms/Drives/Compatibility:
    42 // All.
    43 // Assumptions/Requirement/Pre-requisites:
    44 // Failures and causes:
    45 // Base Port information:
    46 // 
    47 //
    48 
    49 #define __E32TEST_EXTENSION__
    50 
    51 #include <e32test.h>
    52 #include <e32panic.h>
    53 #include <e32svr.h>
    54 #include "mmudetect.h"
    55 #include "d_gobble.h"
    56 #include "freeram.h"
    57 
    58 const TInt KHeapSize=0x200;
    59 
    60 //const TInt KNumberOfChunks=10; can't have that many
    61 const TInt KNumberOfChunks=3;
    62 
    63 const TInt KChunkNum=5;
    64 const TInt KNormalReturn=194;
    65 
    66 #ifdef __WINS__
    67 const TInt KMinChunkSizeInBytesMinus1=0x0000ffff;
    68 const TUint KMinChunkSizeInBytesMask=0xffff0000;
    69 #elif defined (__X86__)
    70 const TInt KMinChunkSizeInBytesMinus1=0x003fffff;
    71 const TUint KMinChunkSizeInBytesMask=0xffc00000;
    72 #else
    73 const TInt KMinChunkSizeInBytesMinus1=0x000fffff;
    74 const TUint KMinChunkSizeInBytesMask=0xfff00000;
    75 #endif
    76 
    77 const TInt KMinPageSizeInBytesMinus1=0x00000fff;
    78 const TUint KMinPageSizeInBytesMask=0xfffff000;
    79 TInt gPageSize;
    80 
    81 LOCAL_D RTest test(_L("T_CHUNK"));
    82 LOCAL_D RTest t(_L("ShareThread"));
    83 LOCAL_D RChunk gChunk;
    84 
    85 LOCAL_D TPtr nullPtr(NULL,0);
    86 
    87 TUint32 MemModel;
    88 
    89 enum TDirective
    90 	{
    91 	ENormal,
    92 	ECreateNegative,
    93 	EAdjustNegative,
    94 	ECreateInvalidType,
    95 	ECreateInvalidName,
    96 	ECreateNoName,
    97 	};
    98 
    99 const TUint8 KDfltClearByte = 0x3;
   100 TBool CheckChunkCleared(RChunk& aRC, TInt aOffset=0, TUint8 aClearByte = KDfltClearByte)
   101 	{
   102 	TUint8* base = aRC.Base()+aOffset;
   103 	TInt size = aRC.Size();
   104 	test.Printf(_L("Testing chunk for 0x%x - size: %d!\n"), aClearByte, size);
   105 	TBool ret=ETrue;
   106 	for(TInt i = 0; i<size; i++)
   107 		if(base[i] != aClearByte)
   108 			ret=EFalse;
   109 	memset((TAny*)base, 0x05, size);
   110 	return ret;
   111 	}
   112 
   113 TInt roundToPageSize(TInt aSize)
   114 	{
   115 
   116 	return(((aSize+KMinPageSizeInBytesMinus1)&KMinPageSizeInBytesMask));
   117 	}
   118 
   119 TInt roundToChunkSize(TInt aSize)
   120 	{
   121 	if(MemModel==EMemModelTypeFlexible)
   122 		return roundToPageSize(aSize);
   123 	return(((aSize+KMinChunkSizeInBytesMinus1)&KMinChunkSizeInBytesMask));
   124 	}
   125 
   126 TInt ThreadEntry2(TAny* /*aParam*/)
   127 //
   128 //	Thread to read from shared chunk
   129 //
   130 	{
   131 	RChunk c;
   132 	TInt r;
   133 	r=c.OpenGlobal(_L("Marmalade"),ETrue);
   134 	t(r==KErrNone);
   135 	TUint8* base=c.Base();
   136 	for (TInt8 i=0;i<10;i++)
   137 		t(*base++==i); // check the chunk has 0-9
   138 	c.Close();
   139 	return(KErrNone);
   140 	}
   141 
   142 TInt ThreadEntry(TAny* aDirective)
   143 //
   144 //	Thread to create a Panic in a variety of ways
   145 //
   146 	{
   147 
   148 	switch((TUint)aDirective)
   149 		{
   150 	case ENormal:
   151 		{
   152 		return KNormalReturn;
   153 		}
   154 	case ECreateNegative:
   155 		{
   156 		gChunk.CreateLocal(0x10,-0x10);
   157 		test(EFalse); 
   158 		}
   159 	case EAdjustNegative:
   160 		{
   161 		gChunk.Adjust(-0x10);
   162 		test(EFalse);
   163 		}
   164 	case ECreateInvalidType :
   165 		{
   166 		TChunkCreateInfo createInfo;
   167 		createInfo.SetCode(gPageSize, gPageSize);
   168 		_LIT(KChunkName, "Chunky");
   169 		createInfo.SetGlobal(KChunkName);
   170 		RChunk chunk;
   171 		chunk.Create(createInfo);
   172 		test(EFalse);
   173 		}
   174 	default:
   175 		test(EFalse);
   176 		}
   177 	return(KErrNone);
   178 	}
   179 
   180 //
   181 //	Test the clear flags for the specified chunk.
   182 //	Assumes chunk has one commited region from base to aBytes.
   183 //
   184 void TestClearChunk(RChunk& aChunk, TUint aBytes, TUint8 aClearByte)
   185 	{
   186 	test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
   187 	test_KErrNone(aChunk.Adjust(0));
   188 	test_KErrNone(aChunk.Adjust(aBytes));
   189 	test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
   190 	aChunk.Close();
   191 	}
   192 
   193 
   194 //
   195 // Create the specified thread and verify the exit reason.
   196 //
   197 void TestThreadExit(TExitType aExitType, TInt aExitReason, TThreadFunction aFunc, TAny* aThreadParam)
   198 	{
   199 	RThread thread;
   200 	test_KErrNone(thread.Create(_L("RChunkPanicThread"), aFunc, KDefaultStackSize, 
   201 								KHeapSize, KHeapSize, aThreadParam));
   202 	// Disable JIT debugging.
   203 	TBool justInTime=User::JustInTime();
   204 	User::SetJustInTime(EFalse);
   205 
   206 	TRequestStatus status;
   207 	thread.Logon(status); 
   208 	thread.Resume();
   209 	User::WaitForRequest(status);
   210 	test_Equal(aExitType, thread.ExitType());
   211 	test_Equal(aExitReason, status.Int());
   212 	test_Equal(aExitReason, thread.ExitReason());
   213 	if (aExitType == EExitPanic)
   214 		test(thread.ExitCategory()==_L("USER"));
   215 	CLOSE_AND_WAIT(thread);
   216 
   217 	// Put JIT debugging back to previous status.
   218 	User::SetJustInTime(justInTime);
   219 	}
   220 
   221 
   222 //
   223 // Thread function to create a chunk with invalid attributes
   224 //
   225 TInt ChunkPanicThread(TAny* aCreateInfo)
   226 	{
   227 	// This should panic.
   228 	RChunk chunk;
   229 	chunk.Create((*(TChunkCreateInfo*) aCreateInfo));
   230 	test(EFalse);
   231 
   232 	return KErrGeneral;	// Shouldn't reach here.
   233 	}
   234 
   235 void testInitialise()
   236 	{
   237 	test.Next(_L("Load gobbler LDD"));
   238 	TInt r = User::LoadLogicalDevice(KGobblerLddFileName);
   239 	test(r==KErrNone || r==KErrAlreadyExists);
   240 
   241 	// get system info...
   242 	MemModel = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL) & EMemModelTypeMask;
   243 
   244 	test_KErrNone(UserHal::PageSizeInBytes(gPageSize));
   245 	}
   246 
   247 
   248 void test1()
   249 //
   250 //	Test creating chunks with silly sizes
   251 //
   252 	{
   253 
   254 	__KHEAP_MARK;
   255 	RChunk chunk;
   256 	TInt r;
   257 	test.Start(_L("Create global chunks"));
   258 	r=chunk.CreateGlobal(_L("Fopp"),1,1);
   259 	test(r==KErrNone);
   260 	chunk.Close();
   261 	r=chunk.CreateGlobal(_L("Fopp"),0,0);
   262 	test(r==KErrArgument);
   263 
   264 	__KHEAP_CHECK(0);
   265 
   266 	test.Next(_L("Create local chunks"));	  
   267 	r=chunk.CreateLocal(1,1);
   268 	test(r==KErrNone);
   269 	chunk.Close();
   270 	r=chunk.CreateLocal(0,0);
   271 	test(r==KErrArgument);
   272 	test.End();
   273 	__KHEAP_MARKEND;
   274 	}
   275 
   276 
   277 void test2(TInt aSize)
   278 //
   279 //	Test local/global chunk creation
   280 //
   281 	{
   282 
   283 	RChunk lchunk[KNumberOfChunks];
   284 	RChunk gchunk[KNumberOfChunks];
   285 	RChunk chunk;
   286 
   287 	__KHEAP_MARK;
   288 	test.Start(_L("Create multiple local and global chunks"));
   289 
   290 	TInt i;
   291 	TBuf<0x40> name;
   292 	TFullName fullname;
   293 	for (i=0; i<KNumberOfChunks; i++)
   294 		{
   295 		TInt r;
   296 		// create a local chunk
   297 		r=lchunk[i].CreateLocal(aSize,aSize);
   298 		test(r==KErrNone);
   299 		r=lchunk[i].MaxSize();
   300 		test(r==roundToChunkSize(aSize));
   301 		test(lchunk[i].Size()==roundToPageSize(aSize)); // was 0
   302 		test(lchunk[i].Name().Left(6)==_L("Local-"));
   303 
   304 		fullname=RProcess().Name();
   305 		fullname+=_L("::");
   306 		fullname+=lchunk[i].Name();
   307 		test(lchunk[i].FullName().CompareF(fullname)==0);
   308 
   309 		// create a global chunk
   310 		name.Format(_L("Chunk%d"),i);
   311 		r=gchunk[i].CreateGlobal(name,aSize,aSize);
   312 		test(r==KErrNone);
   313   		test(gchunk[i].MaxSize()==roundToChunkSize(aSize));
   314 		test(gchunk[i].Size()==roundToPageSize(aSize)); // was 0
   315 		test(gchunk[i].Name()==name);
   316 		}
   317 
   318 	// make room for another chunk
   319 	lchunk[KNumberOfChunks-1].Close();
   320 	gchunk[KNumberOfChunks-1].Close();
   321 
   322 //	Try to create a global chunk with a duplicate name
   323 	test.Next(_L("Create a chunk with a duplicate name"));
   324 	TInt r=chunk.CreateGlobal(_L("Chunk0"),aSize,aSize);
   325 	test(r==KErrAlreadyExists);
   326 
   327  	test.Next(_L("Close all chunks"));
   328 	for (i=0; i<KNumberOfChunks-1; i++)
   329 		{
   330 		lchunk[i].Close();
   331 		gchunk[i].Close();
   332 		}
   333 
   334 	test.Next(_L("Reuse a name"));
   335 	r=chunk.CreateGlobal(_L("Chunk1"),aSize,aSize);
   336 	test(r==KErrNone);
   337 	test(chunk.MaxSize()==roundToChunkSize(aSize));
   338    	test(chunk.Size()==roundToPageSize(aSize));	
   339 	test(chunk.Name()==_L("Chunk1"));
   340   	chunk.Close();
   341 
   342 	test.End();
   343 	__KHEAP_MARKEND;
   344 	}
   345 
   346 void test3_2(RChunk& aChunk, TInt aSize)
   347 //
   348 //	Perform Adjust tests on aChunk
   349 //
   350 	{
   351 
   352 	TInt r;
   353 	test.Start(_L("Adjust to full size"));
   354 	r=aChunk.Adjust(aSize);
   355  	test(r==KErrNone);
   356 	test(aChunk.Size()==roundToPageSize(aSize));
   357 	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   358 
   359 	test.Next(_L("Adjust a chunk to half size"));
   360 	r=aChunk.Adjust(aSize/2);
   361 	test(r==KErrNone);
   362 	test(aChunk.Size()==roundToPageSize(aSize/2));
   363 	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   364 
   365 	test.Next(_L("Adjust to same size"));
   366 	r=aChunk.Adjust(aSize/2);
   367 	test(r==KErrNone);
   368 	test(aChunk.Size()==roundToPageSize(aSize/2));
   369 	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   370 
   371 	test.Next(_L("Adjusting to size=0"));
   372  	r=aChunk.Adjust(0);
   373 	test(r==KErrNone);
   374 	test(aChunk.Size()==0);
   375 	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   376 
   377 	test.Next(_L("Adjust back to half size"));
   378 	r=aChunk.Adjust(aSize/2);
   379 	test(r==KErrNone);
   380 	test(aChunk.Size()==roundToPageSize(aSize/2));
   381 	test(aChunk.MaxSize()==roundToChunkSize(aSize));
   382 
   383 	test.End();
   384 	}
   385 
   386 
   387 void test3(TInt aSize)
   388 //
   389 //	Test Adjust size of chunk	
   390 //
   391 	{
   392 
   393 	RChunk chunk;
   394 	__KHEAP_MARK;	
   395 	TInt r;
   396 //	Run Adjust tests with a local chunk
   397 	test.Start(_L("Local Chunk.Adjust()"));
   398 	r=chunk.CreateLocal(aSize,aSize);
   399 	test3_2(chunk, aSize);
   400 	chunk.Close();
   401 //	Run Adjust tests with a global chunk
   402 	test.Next(_L("Global Chunk.Adjust()"));
   403 	r=chunk.CreateGlobal(_L("Fopp"),aSize,aSize);
   404 	test(KErrNone==r);
   405 	test3_2(chunk,aSize);
   406 	chunk.Close();
   407 	test.End();
   408 	__KHEAP_MARKEND;
   409 	}
   410 
   411 void test4(TInt aSize)
   412 //
   413 //	Test OpenGlobal
   414 //
   415 	{
   416 
   417 	RChunk chunk[KChunkNum];
   418 	RChunk c1, c2, c3;
   419 	TName name;
   420 
   421 	__KHEAP_MARK;
   422 	TInt i,r;
   423 	for (i=0; i<KChunkNum; i++)
   424 		{
   425 		name.Format(_L("Chunk%d"), i);
   426 		r=chunk[i].CreateGlobal(name,aSize,aSize);
   427 		}
   428 
   429 	test.Start(_L("Open Global chunks"));
   430 	r=c1.OpenGlobal(_L("Chunk1"),EFalse); // 2nd ref to this chunk
   431 	test(r==KErrNone);
   432 	r=c2.OpenGlobal(_L("Chunk3"),EFalse); // 2nd ref to this chunk
   433 	test(r==KErrNone);
   434 	r=c3.OpenGlobal(_L("Chunk4"),EFalse); // 2nd ref to this chunk
   435 	test(r==KErrNone);
   436 	c3.Close();
   437 
   438 	test.Next(_L("Attempt Open non-existant chunk"));
   439 	r=c3.OpenGlobal(_L("Non Existant Chunk"),EFalse);
   440 	test(r==KErrNotFound);
   441 
   442 	for (i=0; i<KChunkNum; i++)
   443 		{
   444 		test.Printf(_L("Closing chunk %d\n"),i);
   445 		chunk[i].Close();
   446 		}
   447 
   448 	test.Next(_L("Test chunks with multiple references are still valid"));
   449 	r=c1.Adjust(aSize/2);
   450 	test(r==KErrNone);
   451 	test(c1.MaxSize()==roundToChunkSize(aSize));
   452 	test(c1.Size()==roundToPageSize(aSize/2));
   453 	test(c1.Name()==_L("Chunk1"));
   454 
   455 	r=c2.Adjust(aSize/2);
   456 	test(r==KErrNone);
   457 	test(c2.MaxSize()==roundToChunkSize(aSize));
   458 	test(c2.Size()==roundToPageSize(aSize/2));
   459 	test(c2.Name()==_L("Chunk3"));
   460 
   461 //	Open another reference to a chunk
   462 	r=c3.OpenGlobal(_L("Chunk3"),EFalse);
   463 	test(r==KErrNone);
   464 	test(c3.Base()==c2.Base());
   465 	test(c3.Size()==c2.Size());
   466 	test(c2.Size()!=aSize);
   467 //	Adjust with one reference
   468 	r=c3.Adjust(aSize);
   469 	test(r==KErrNone);
   470 //	Test sizes from the other
   471 	test(c2.Size()==roundToPageSize(aSize));
   472 	test(c2.MaxSize()==roundToChunkSize(aSize));
   473 
   474 	c1.Close();
   475 	c2.Close();
   476 	c3.Close();
   477 
   478 	test.Next(_L("And check the heap..."));
   479 	test.End();
   480 	__KHEAP_MARKEND;
   481 	}
   482 
   483 void test5(TInt aSize)
   484 //
   485 //	Test Open
   486 //
   487 	{
   488 	
   489 	RChunk chunk[2*KNumberOfChunks];
   490 	RChunk c1;
   491 
   492 	test.Start(_L("Creating Local and Global Chunks"));
   493 	__KHEAP_MARK;
   494 	TInt i,r;
   495 	TBuf<0x40> b;
   496 
   497 //	Create KNumberOfChunks Global chunks
   498 	for (i=0; i<KNumberOfChunks; i++)
   499 		{
   500 		b.Format(_L("Chunk%d"), i);
   501 		r=chunk[i].CreateGlobal(b,aSize,aSize);
   502 		test(chunk[i].Name()==b);
   503 		test(r==KErrNone);
   504 		
   505 		b.Format(_L("This is chunk %d"), i);
   506 		b.Append(TChar(0));
   507 		chunk[i].Adjust(aSize);
   508 		Mem::Copy(chunk[i].Base(), b.Ptr(), b.Size());
   509 		test(chunk[i].MaxSize()==roundToChunkSize(aSize));
   510 		test(chunk[i].Size()==roundToPageSize(aSize));
   511 		}
   512 
   513 	test.Next(_L("Find and Open the Chunks"));
   514 	TFindChunk find;
   515 	TFullName name;
   516 	for (i=0; i<KNumberOfChunks; i++)
   517 		{
   518 		test.Printf(_L("Opening chunk %d\n"),i);
   519 		find.Find(chunk[i].FullName());
   520 		r = find.Next(name);
   521 		test(r==KErrNone);
   522 		c1.Open(find);
   523 		b=TPtrC((TText*)c1.Base());
   524 		name.Format(_L("This is chunk %d"), i);
   525 		test(b==name);
   526 		c1.Close();
   527 		}
   528 	
   529 	test.Next(_L("Close chunks"));
   530 	for (i=0; i<KNumberOfChunks; i++)
   531 		chunk[i].Close();
   532 
   533 	test.End();
   534 	__KHEAP_MARKEND;
   535 	}
   536 
   537 
   538 void test7(TInt aSize)
   539 //
   540 //	Deliberately cause RChunk panics
   541 //
   542 	{
   543 	__KHEAP_MARK;
   544 
   545 //	ENormal
   546 	test.Start(_L("Test panic thread"));
   547 	TestThreadExit(EExitKill, KNormalReturn, ThreadEntry, (TAny*)ENormal);
   548 
   549 //	ECreateNegative
   550 	test.Next(_L("Create Chunk with a negative size"));
   551 	TestThreadExit(EExitPanic, EChkCreateMaxSizeNegative, ThreadEntry, (TAny*) ECreateNegative);
   552 
   553 //	EAdjustNegative
   554 	test.Next(_L("Adjust a Chunk to Size = -0x10"));
   555 	gChunk.CreateLocal(aSize,aSize);
   556 	TestThreadExit(EExitPanic, EChkAdjustNewSizeNegative, ThreadEntry, (TAny*) EAdjustNegative);
   557 	gChunk.Close();
   558 
   559 // ECreateInvalidType
   560 	test.Next(_L("Create chunk of invalid type"));
   561 	TestThreadExit(EExitPanic, EChkCreateInvalidType, ThreadEntry, (TAny*) ECreateInvalidType);
   562 
   563 	test.End();
   564 
   565 	__KHEAP_MARKEND;
   566 	}
   567 
   568 
   569 void testClear(TInt aSize)
   570 	{
   571 	__KHEAP_MARK;
   572 	test.Start(_L("Test clearing memory (Platform Security)"));
   573 	
   574 	RChunk c1,c2,c3,c4,c5,c6,c7,c8,c9,c10;
   575 	TInt r;
   576 	
   577 	TBuf<0x40> b;
   578 	
   579 	b.Copy(_L("Chunk"));
   580 	
   581 	r=c1.CreateGlobal(b,aSize,aSize);
   582 	test(r==KErrNone);
   583 	
   584 	test((TBool)ETrue==CheckChunkCleared(c1));
   585 	c1.Close();
   586 	
   587 	r=c2.CreateLocal(aSize,aSize,EOwnerProcess);
   588 	test(r==KErrNone);
   589 	
   590 	test((TBool)ETrue==CheckChunkCleared(c2));
   591 	c2.Close();
   592 
   593 	r=c3.CreateLocalCode(aSize,aSize,EOwnerProcess);
   594 	test(r==KErrNone);
   595 	
   596 	test((TBool)ETrue==CheckChunkCleared(c3));
   597 	c3.Close();
   598 
   599 	r=c4.CreateDoubleEndedLocal(0x1000,0x1000+aSize,0x100000);
   600 	test(r==KErrNone);
   601 	
   602 	test((TBool)ETrue==CheckChunkCleared(c4,c4.Bottom()));
   603 	c4.Close();
   604 
   605 	r=c5.CreateDoubleEndedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
   606 	test(r==KErrNone);
   607 	
   608 	test((TBool)ETrue==CheckChunkCleared(c5,c5.Bottom()));
   609 	c5.Close();
   610 
   611 	r=c6.CreateDisconnectedLocal(0x1000,0x1000+aSize,0x100000);
   612 	test(r==KErrNone);
   613 	
   614 	test((TBool)ETrue==CheckChunkCleared(c6,0x1000));
   615 	c6.Close();
   616 
   617 	r=c7.CreateDisconnectedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
   618 	test(r==KErrNone);
   619 	
   620 	test((TBool)ETrue==CheckChunkCleared(c7,0x1000));
   621 	c7.Close();
   622 
   623 	test.Next(_L("Test setting the clear byte of RChunk::Create()"));
   624 
   625 	TChunkCreateInfo createInfo;
   626 	createInfo.SetNormal(aSize, aSize);
   627 	test_KErrNone(c10.Create(createInfo));
   628 	TestClearChunk(c10, aSize, KDfltClearByte);
   629 
   630 	createInfo.SetClearByte(0x0);
   631 	test_KErrNone(c8.Create(createInfo));
   632 	TestClearChunk(c8, aSize, 0x0);
   633 
   634 	createInfo.SetClearByte(0xff);
   635 	test_KErrNone(c9.Create(createInfo));
   636 	TestClearChunk(c9, aSize, 0xff);
   637 
   638 	test.End();
   639 	__KHEAP_MARKEND;
   640 	}
   641 
   642 void testShare()
   643 //
   644 // Test sharing a chunk between threads
   645 //
   646 	{
   647 	test.Start(_L("Test chunk sharing between threads"));
   648 
   649 	test.Next(_L("Create chunk Marmalade"));
   650 	TInt r=0;
   651 	RChunk chunk;
   652 	TInt size=0x1000;
   653 	TInt maxSize=0x5000;
   654 	r=0;
   655 	r=chunk.CreateGlobal(_L("Marmalade"),size,maxSize);
   656 	test(r==KErrNone);
   657 	test.Next(_L("Write 0-9 to it"));
   658 	TUint8* base=chunk.Base();
   659 	for (TInt8 j=0;j<10;j++)
   660 		*base++=j; // write 0 - 9 to the chunk
   661 
   662 	RThread t;
   663 	TRequestStatus stat;
   664 	test.Next(_L("Create reader thread"));
   665 	r=t.Create(_L("RChunkShareThread"), ThreadEntry2, KDefaultStackSize,KHeapSize,KHeapSize,NULL);
   666 	test(r==KErrNone);
   667 	t.Logon(stat);
   668 	test.Next(_L("Resume reader thread"));
   669 	t.Resume();
   670 	User::WaitForRequest(stat);	
   671 	CLOSE_AND_WAIT(t);
   672 	chunk.Close();
   673 
   674 	test.End();
   675 	}
   676 
   677 void FindChunks()
   678     { // taken from some code written by SteveG
   679     test.Start(_L("Finding chunks...\n"));
   680 
   681     TFullName name=_L("*");
   682     TFindChunk find(name);
   683 	TInt i=0;
   684 
   685 
   686     while (find.Next(name)==KErrNone)
   687         {
   688         RChunk chunk;
   689         test.Printf(_L("Chunk name %S\n"),&name);
   690 		TInt err=chunk.Open(find);
   691         if (err)
   692             test.Printf(_L("Error %d opening chunk"),err);
   693         else
   694         	{
   695 			TBuf<16> access;
   696 			if (chunk.IsWritable())
   697 				access=_L("ReadWrite");
   698 			else if (chunk.IsReadable())
   699 				access=_L("ReadOnly");
   700 			else
   701 				access=_L("No Access");
   702             test.Printf(_L("Chunk size %08x bytes, %S\n"),chunk.Size(),&access);
   703 			chunk.Close();
   704 			i++;
   705 			}
   706         User::After(1000000);
   707   	    }
   708     test.End();
   709     }
   710 
   711 void testAdjustChunk()
   712 	{
   713 	test.Start(_L("Test adjusting chunks"));
   714 
   715 	RChunk hermione;
   716 	
   717 	test.Next(_L("Create global chunk"));
   718 	TInt r=hermione.CreateGlobal(_L("Hermione"),0x1000,0x100000);
   719 	test(r==KErrNone);
   720 	TUint32* base=(TUint32*)hermione.Base();
   721 	TUint32* top=(TUint32*)(hermione.Base()+hermione.Size());
   722 	TUint32* i;
   723 
   724 	test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
   725 	test.Next(_L("Check I can write to all of it"));
   726 	for (i=base;i<top;i++)
   727 		*i=0xdeaddead;
   728 
   729 	test.Next(_L("Adjust the chunk"));
   730 	r=hermione.Adjust(0x1400);
   731 	test(r==KErrNone);
   732 
   733 	base=(TUint32*)hermione.Base();
   734 	top=(TUint32*)(hermione.Base()+hermione.Size());
   735 	test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
   736 	test.Next(_L("Check I can write to all of the bigger chunk"));
   737 	for (i=base;i<top;i++)
   738 		*i=0xdeaddead;
   739 
   740 	hermione.Close();
   741 
   742 	test.Next(_L("Do some size checks"));
   743 	RChunk wibble;
   744 	r=wibble.CreateGlobal(_L("Wibble"),0x1,gPageSize*8);
   745 	test(r==KErrNone);
   746 	test.Next(_L("Check create rounds up to page multiple"));
   747 	test(wibble.Size()==(TInt)gPageSize);
   748 	test.Next(_L("Check create rounds up to chunk multiple"));
   749 	test(wibble.MaxSize()==roundToChunkSize(gPageSize*8));
   750 
   751 	test.Next(_L("Check adjust rounds up to page multiple"));
   752 	r=wibble.Adjust((gPageSize*6)-12);
   753 	test(r==KErrNone);
   754 	test(wibble.Size()==gPageSize*6);
   755 
   756 	test.Next(_L("Different number, same size"));
   757 	r=wibble.Adjust((gPageSize*6)-18);
   758 	test(r==KErrNone);
   759 	test(wibble.Size()==gPageSize*6);
   760 
   761 	test.Next(_L("Check adjust > MaxSize returns error"));
   762 	r=wibble.Adjust(wibble.MaxSize()+gPageSize);
   763 	test(r==KErrArgument);
   764 
   765 	wibble.Close();
   766 	test.End();
   767 	}
   768 
   769 TInt NotifierCount=0;
   770 TInt OOMCount=0;
   771 RChangeNotifier Notifier;
   772 RThread NtfThrd;
   773 _LIT(KNotifierThreadName,"NotifierThread");
   774 
   775 TInt NotifierThread(TAny*)
   776 	{
   777 	TInt r=Notifier.Create();
   778 	while (r==KErrNone)
   779 		{
   780 		TRequestStatus s;
   781 		r=Notifier.Logon(s);
   782 		if (r!=KErrNone)
   783 			break;
   784 		User::WaitForRequest(s);
   785 		if (s.Int()&EChangesFreeMemory)
   786 			++NotifierCount;
   787 		if (s.Int()&EChangesOutOfMemory)
   788 			++OOMCount;
   789 		}
   790 	Notifier.Close();
   791 	return r;
   792 	}
   793 
   794 
   795 void WaitForNotifier()
   796 	{
   797 	User::After(500000);		// wait for notifier
   798 	}
   799 
   800 
   801 void CheckNotifierCount(TInt aLevel, TInt aOom)
   802 	{
   803 	WaitForNotifier();
   804 	if (NtfThrd.ExitType()!=EExitPending)
   805 		{
   806 		TExitCategoryName exitCat=NtfThrd.ExitCategory();
   807 		test.Printf(_L("Thread exited: %d,%d,%S"),NtfThrd.ExitType(),NtfThrd.ExitReason(),&exitCat);
   808 		test(0);
   809 		}
   810 	TInt c1=NotifierCount;
   811 	TInt c2=OOMCount;
   812 	if (c1!=aLevel || c2!=aOom)
   813 		{
   814 		test.Printf(_L("Count %d,%d Expected %d,%d"),c1,c2,aLevel,aOom);
   815 		test(0);
   816 		}
   817 	}
   818 
   819 void testNotifiers()
   820 	{
   821 	RGobbler gobbler;
   822 	TInt r = gobbler.Open();
   823 	test(r==KErrNone);
   824 	TUint32 taken = gobbler.GobbleRAM(128*1024*1024);
   825 	test.Printf(_L("Gobbled: %dK\n"), taken/1024);
   826 	test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam());
   827 
   828 	test.Next(_L("Create thread"));
   829 	r=NtfThrd.Create(KNotifierThreadName,NotifierThread,KDefaultStackSize,NULL,NULL);
   830 	test(r==KErrNone);
   831 	NtfThrd.SetPriority(EPriorityMore);
   832 	NtfThrd.Resume();
   833 	test.Next(_L("Check for initial notifier"));
   834 	CheckNotifierCount(1,1);
   835 	TInt free=FreeRam();
   836 	test.Printf(_L("Free RAM: %dK\n"),free/1024);
   837 	test(free>=1048576);
   838 	test.Next(_L("Set thresholds"));
   839 	r=UserSvr::SetMemoryThresholds(65536,524288);	// low=64K good=512K
   840 	test(r==KErrNone);
   841 	test.Next(_L("Create chunk"));
   842 	// Chunk must not be paged otherwise it will not effect the amount 
   843 	// of free ram reported plus on h4 swap size is less than the total ram.
   844 	TChunkCreateInfo createInfo;
   845 	createInfo.SetNormal(0, free+2097152);
   846 	createInfo.SetPaging(TChunkCreateInfo::EUnpaged);
   847 	RChunk c;
   848 	test_KErrNone(c.Create(createInfo));
   849 	const TInt KBufferSpace = 768*1024;	// 768K buffer
   850 	CheckNotifierCount(1,1);
   851 	test.Next(_L("Leave 768K"));
   852 	r=c.Adjust(free-KBufferSpace);	// leave 768K
   853 	test(r==KErrNone);
   854 	CheckNotifierCount(1,1);		// shouldn't get notifier
   855 	TInt free2=FreeRam();
   856 	test.Printf(_L("Free RAM: %dK\n"),free2/1024);
   857 	test(free2<=KBufferSpace);
   858 	TInt free3=free-(KBufferSpace-free2);	// this accounts for space used by page tables
   859 	test.Next(_L("Leave 32K"));
   860 	r=c.Adjust(free3-32768);		// leave 32K
   861 	test(r==KErrNone);
   862 	CheckNotifierCount(2,1);		// should get notifier
   863 	test.Next(_L("Leave 28K"));
   864 	r=c.Adjust(free3-28672);		// leave 28K
   865 	test(r==KErrNone);
   866 	CheckNotifierCount(2,1);		// shouldn't get another notifier
   867 	test.Next(_L("Ask for too much"));
   868 	r=c.Adjust(free3+4096);			// try to get more than available
   869 	test(r==KErrNoMemory);
   870 	CheckNotifierCount(2,2);		// should get another notifier
   871 	test.Next(_L("Leave 128K"));
   872 	r=c.Adjust(free3-131072);		// leave 128K
   873 	test(r==KErrNone);
   874 	CheckNotifierCount(2,2);		// shouldn't get another notifier
   875 	test.Next(_L("Leave 640K"));
   876 	r=c.Adjust(free3-655360);		// leave 640K
   877 	test(r==KErrNone);
   878 	CheckNotifierCount(3,2);		// should get another notifier
   879 	test.Next(_L("Leave 1M"));
   880 	r=c.Adjust(free3-1048576);		// leave 1M
   881 	test(r==KErrNone);
   882 	CheckNotifierCount(3,2);		// shouldn't get another notifier
   883 	test.Next(_L("Ask for too much"));
   884 	r=c.Adjust(free3+4096);			// try to get more than available
   885 	test(r==KErrNoMemory);
   886 
   887 	TInt notifierCount = 3;
   888 	if(MemModel==EMemModelTypeFlexible)
   889 		{
   890 		// on flexible memory model, we get memory changed notifiers
   891 		// on failed memory allocation; this hack lets the test code
   892 		// pass this as acceptable behaviour...
   893 		WaitForNotifier();
   894 		notifierCount = NotifierCount; // expect whatever we actually got
   895 		}
   896 
   897 	CheckNotifierCount(notifierCount,3);		// should get another notifier
   898 	test.Next(_L("Leave 1M"));
   899 	r=c.Adjust(free3-1048576);					// leave 1M
   900 	test(r==KErrNone);
   901 	CheckNotifierCount(notifierCount,3);		// shouldn't get another notifier
   902 
   903 	c.Close();
   904 	TRequestStatus s;
   905 	NtfThrd.Logon(s);
   906 	NtfThrd.Kill(0);
   907 	User::WaitForRequest(s);
   908 	CLOSE_AND_WAIT(NtfThrd);
   909 	Notifier.Close();
   910 	gobbler.Close();
   911 	}
   912 
   913 
   914 // TestFullAddressSpace is used to stress the memory allocation mechanism(beyond the 1GB limit).
   915 // However, the memory model can introduce limitations in the total amount of memory a single 
   916 // process is allowed to allocate. To make the test more generic before closing the reserved 
   917 // chunks for this test we trigger the creation of a new process. This process executes 
   918 // t_chunk again, passing argument "extended". The result is that more chunks will be created
   919 // through another call to TestFullAddressSpace, with the parameter extendedFlag set to true. 
   920 // Eventually the total amount of allocated space will overcome the 1Gb limit in any case.
   921 
   922 void TestFullAddressSpace(TBool extendedFlag )
   923 	{
   924 	test.Start(_L("Fill process address space with chunks\n"));
   925 	RChunk chunk[2][11];
   926 	TInt total = 0;
   927 	TInt i;
   928 	TInt j;
   929 	TInt r;
   930 		
   931 	for(j=0; j<=1; j++)
   932 		{
   933 		if(!j)
   934 			test.Next(_L("Creating local chunks"));
   935 		else
   936 			test.Next(_L("Creating global chunks"));
   937 		for(i=10; i>=0; --i)
   938 			{
   939 			TInt size = 1<<(20+i);
   940 			
   941 			if(!j)
   942 				r = chunk[j][i].CreateDisconnectedLocal(0,0,size);
   943 			else
   944 				r = chunk[j][i].CreateDisconnectedGlobal(KNullDesC,0,0,size);
   945 			TBuf<128> text;
   946 			text.AppendFormat(_L("Create %dMB chunk returns %d"),1<<i,r);
   947 			test.Next(text);
   948 			if(r!=KErrNoMemory)
   949 				{
   950 				test(r==KErrNone);
   951 				// commit memory to each 1MB region,
   952 				// this excercises page table allocation
   953 				volatile TUint8* base = (TUint8*)chunk[j][i].Base();
   954 				for(TInt o=0; o<size; o+=1<<20)
   955 					{
   956 					r = chunk[j][i].Commit(o,1);
   957 					test(r==KErrNone);
   958 					// access the commited memory...
   959 					base[o] = (TUint8)(o&0xff);
   960 					test(base[o]==(TUint8)(o&0xff));
   961 					base[o] = (TUint8)~(o&0xff);
   962 					test(base[o]==(TUint8)~(o&0xff));
   963 					}
   964 				total += 1<<i;
   965 				}
   966 			}
   967 		}
   968 		
   969 	if (extendedFlag == EFalse)
   970 		{
   971 		
   972 		test.Printf(_L("Total chunk size created was %d MB\n\n"),total);	  
   973 
   974 		if(total<1024)
   975 			{
   976 			_LIT(KOtherProcessName,"t_chunk");
   977 			_LIT(KProcessArgs,"extended");
   978 			
   979 			RProcess process;      
   980 			r=process.Create(KOtherProcessName,KProcessArgs );
   981 			test.Printf(_L("Creating new process( t_chunk extended) returns %d\n"),r );
   982 			test( r == KErrNone);
   983 		   
   984 			TRequestStatus status;
   985 			process.Logon(status);
   986 			process.Resume(); 
   987 			
   988 			User::WaitForRequest(status);
   989 			  
   990 			test(process.ExitType() == EExitKill);
   991 			test(process.ExitReason() == 0);
   992 			process.Close();
   993 			}
   994 	
   995 		}           
   996   	else
   997   		test.Printf(_L("Total chunk size created by the new process was %d MB\n"),total); 
   998  
   999 	for(j=0; j<=1; j++)
  1000 		for(i=10; i>=0; --i)
  1001 			chunk[j][i].Close();
  1002 	test.End();
  1003 	}	
  1004 
  1005 
  1006 #ifdef __WINS__
  1007 void TestExecLocalCode()
  1008 	{
  1009 	RChunk c;
  1010 	TInt size = 10 * 1024;
  1011 	TInt rc = c.CreateLocalCode(size, size, EOwnerProcess);
  1012 	test_KErrNone(rc);
  1013 	TUint8 *p = c.Base();
  1014 	TUint32 (*func)() = (TUint32 (*)())p;
  1015 	test.Printf(_L("Create small function in the new code chunk\n"));
  1016 	*p++ = 0xB8;		// mov eax, 0x12345678
  1017 	*p++ = 0x78;
  1018 	*p++ = 0x56;
  1019 	*p++ = 0x34;
  1020 	*p++ = 0x12;
  1021 	*p   = 0xC3;		// ret
  1022 	test.Printf(_L("Going to call the new function\n"));
  1023 	TUint32 res = (*func)();
  1024 	test_Equal(0x12345678, res);
  1025 	c.Close();
  1026 	}
  1027 #endif	//  __WINS__
  1028 
  1029 
  1030 _LIT(KChunkName, "CloseChunk");
  1031 
  1032 struct TRequestData
  1033 	{
  1034 	RSemaphore requestSem;
  1035 	RSemaphore completionSem;
  1036 	RSemaphore nextItSem;
  1037 	};
  1038 
  1039 TInt CloseThread(TAny* data)
  1040 	{
  1041 	TRequestData* reqData = (TRequestData*)data;
  1042 	ASSERT(reqData);
  1043 	
  1044 	for(;;)
  1045 		{
  1046 		// Wait for a request to open and close the chunk.
  1047 		reqData->requestSem.Wait();
  1048 		
  1049 		// Try to open the chunk (may have already been closed by another thread).
  1050 		RChunk chunk;
  1051 		TInt r = chunk.OpenGlobal(KChunkName, EFalse, EOwnerThread);
  1052 		if (r != KErrNone)
  1053 			{
  1054 			// The chunk was already closed...
  1055 			r = (r == KErrNotFound) ? KErrNone : r;	// Ensure no debug output for expected failures.
  1056 			
  1057 			if(r != KErrNone)
  1058 				{
  1059 				test.Printf(_L("CloseThread RChunk::OpenGlobal Err: %d\n"), r);
  1060 				test_KErrNone(r);
  1061 				}
  1062 			}
  1063 		else
  1064 			{ 
  1065 			// Close the chunk.
  1066 			chunk.Close();
  1067 			}
  1068 		
  1069 		// Tell our parent we have completed this iteration and wait for the next.
  1070 		reqData->completionSem.Signal();
  1071 		reqData->nextItSem.Wait();
  1072 		}
  1073 	}
  1074 
  1075 void TestClosure()
  1076 	{
  1077 	const TUint KCloseThreads = 50;
  1078 	RThread thread[KCloseThreads];
  1079 	TRequestStatus dead[KCloseThreads];
  1080 
  1081 	// We need three semaphores or we risk signal stealing if one thread gets ahead of the
  1082 	// others and starts a second iteration before the other threads have been signalled
  1083 	// and have begun their first iteration.  Such a situation results in deadlock so we
  1084 	// force all threads to finish the iteration first using the nextItSem semaphore to
  1085 	// ensure we can only move to the next iteration once every thread has completed the
  1086 	// current iteration.
  1087 	TRequestData reqData;
  1088 	test_KErrNone(reqData.requestSem.CreateLocal(0));
  1089 	test_KErrNone(reqData.completionSem.CreateLocal(0));
  1090 	test_KErrNone(reqData.nextItSem.CreateLocal(0));
  1091 	
  1092 	TUint i = 0;
  1093 
  1094 	// Create thread pool.  We do this rather than create 50 threads
  1095 	// over and over again for 800 times - the kernel's garbage collection
  1096 	// does not keep up and we run out of backing store.
  1097 	for (; i < KCloseThreads; i++)
  1098 		{
  1099 		test_KErrNone(thread[i].Create(KNullDesC, CloseThread, KDefaultStackSize, NULL, (TAny*)&reqData));
  1100 		thread[i].Logon(dead[i]);
  1101 		thread[i].SetPriority(EPriorityMuchLess);
  1102 		thread[i].Resume();
  1103 		}
  1104 
  1105 	for (TUint delay = 200; delay < 1000; delay++)
  1106 		{
  1107 		test.Printf(_L("Closure delay %dus\r"), delay);
  1108 
  1109 		// Create a global chunk.
  1110 		RChunk chunk;
  1111 		test_KErrNone(chunk.CreateGlobal(KChunkName, gPageSize, gPageSize));
  1112 
  1113 		// Release the threads so they can try to close the handle.
  1114 		reqData.requestSem.Signal(KCloseThreads);
  1115 
  1116 		// Wait for the delay then close the handle ourselves.
  1117 		User::AfterHighRes(delay);
  1118 		chunk.Close();
  1119 
  1120 		// Wait for the threads to complete then release them for the next iteration.
  1121 		for (i = 0; i < KCloseThreads; i++)
  1122 			{
  1123 			reqData.completionSem.Wait();
  1124 			}
  1125 		reqData.nextItSem.Signal(KCloseThreads);
  1126 
  1127 		// Ensure garbage collection is complete to prevent the kernel's
  1128 		// garbage collection from being overwhelmed and causing the
  1129 		// backing store to be exhausted.
  1130 		UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
  1131 		}
  1132 
  1133 	// Kill thread pool.
  1134 	for (i = 0; i < KCloseThreads; i++)
  1135 		{
  1136 		thread[i].Kill(KErrNone);
  1137 		User::WaitForRequest(dead[i]);
  1138 		test(KErrNone == thread[i].ExitReason());
  1139 		test_Equal(EExitKill, thread[i].ExitType());
  1140 		thread[i].Close();
  1141 		}
  1142 		
  1143 	reqData.requestSem.Close();
  1144 	reqData.completionSem.Close();
  1145 	reqData.nextItSem.Close();
  1146 
  1147 	// Ensure garbage collection is complete to prevent false positive
  1148 	// kernel memory leaks.
  1149 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
  1150 	}
  1151 	
  1152 
  1153 /**Returns true if argument is found in the command line*/
  1154 TBool IsInCommandLine(const TDesC& aArg)
  1155 	{
  1156 	TBuf<64> c;
  1157 	User::CommandLine(c);
  1158 	if (c.FindF(aArg) >= 0)
  1159 		return ETrue;
  1160 	return EFalse;
  1161 	}
  1162 
  1163 _LIT(KTestChunkReadOnly, "TestReadOnlyChunk");
  1164 _LIT(KTestSemaphoreReadOnly, "TestReadOnlySemaphore");
  1165 _LIT(KTestParamRo, "restro");
  1166 _LIT(KTestParamRw, "restrw");
  1167 _LIT(KTestParamWait, "restwait");
  1168 _LIT(KTestParamWritableChunk, "restwritable");
  1169 
  1170 enum TTestProcessParameters
  1171 	{
  1172 	ETestRw = 0x1,
  1173 	ETestWait = 0x2,
  1174 	ETestWritableChunk = 0x4,
  1175 	};
  1176 
  1177 void TestReadOnlyProcess(TUint aParams)
  1178 	{
  1179 	TInt r;
  1180 	RChunk chunk;
  1181 	RSemaphore sem;
  1182 
  1183 	test.Start(_L("Open global chunk"));
  1184 	r = chunk.OpenGlobal(KTestChunkReadOnly, EFalse);
  1185 	test_KErrNone(r);
  1186 
  1187 	test(chunk.IsReadable());
  1188 	r = chunk.Adjust(1);
  1189 	if (aParams & ETestWritableChunk)
  1190 		{
  1191 		test(chunk.IsWritable());
  1192 		test_KErrNone(r);
  1193 		}
  1194 	else
  1195 		{
  1196 		test(!chunk.IsWritable());
  1197 		test_Equal(KErrAccessDenied, r);
  1198 		}
  1199 
  1200 	if (aParams & ETestWait)
  1201 		{
  1202 		RProcess::Rendezvous(KErrNone);
  1203 		test.Next(_L("Wait on semaphore"));
  1204 		r = sem.OpenGlobal(KTestSemaphoreReadOnly);
  1205 		test_KErrNone(r);
  1206 		sem.Wait();
  1207 		}
  1208 
  1209 	test.Next(_L("Read"));
  1210 	TUint8 read = *(volatile TUint8*) chunk.Base();
  1211 	(void) read;
  1212 
  1213 	if (aParams & ETestRw)
  1214 		{
  1215 		test.Next(_L("Write"));
  1216 		TUint8* write = chunk.Base();
  1217 		*write = 0x3d;
  1218 		}
  1219 
  1220 	chunk.Close();
  1221 	if (aParams & ETestWait)
  1222 		{
  1223 		sem.Close();
  1224 		}
  1225 	test.End();
  1226 	}
  1227 
  1228 void TestReadOnly()
  1229 	{
  1230 	TInt r;
  1231 	RChunk chunk;
  1232 	RProcess process1;
  1233 	RProcess process2;
  1234 	RSemaphore sem;
  1235 	TRequestStatus rs;
  1236 	TRequestStatus rv;
  1237 
  1238 	// Assumption is made that any memory model from Flexible onwards that supports
  1239 	// read-only memory also supports read-only chunks
  1240 	if (MemModelType() < EMemModelTypeFlexible || !HaveWriteProt())
  1241 		{
  1242 		test.Printf(_L("Memory model is not expected to support Read-Only Chunks\n"));
  1243 		return;
  1244 		}
  1245 
  1246 	TBool jit = User::JustInTime();
  1247 	User::SetJustInTime(EFalse);
  1248 
  1249 	test.Start(_L("Create writable global chunk"));
  1250 	TChunkCreateInfo info;
  1251 	info.SetNormal(0, 1234567);
  1252 	info.SetGlobal(KTestChunkReadOnly);
  1253 	r = chunk.Create(info);
  1254 	test_KErrNone(r);
  1255 	test(chunk.IsReadable());
  1256 	test(chunk.IsWritable());
  1257 
  1258 	test.Next(_L("Adjust size"));
  1259 	r = chunk.Adjust(1); // add one page
  1260 	test_KErrNone(r);
  1261 
  1262 	test.Next(_L("Attempt read/write 1"));
  1263 	r = process1.Create(RProcess().FileName(), KTestParamWritableChunk);
  1264 	test_KErrNone(r);
  1265 	process1.Logon(rs);
  1266 	process1.Resume();
  1267 	User::WaitForRequest(rs);
  1268 	test_Equal(EExitKill, process1.ExitType());
  1269 	test_KErrNone(process1.ExitReason());
  1270 	CLOSE_AND_WAIT(process1);
  1271 	CLOSE_AND_WAIT(chunk);
  1272 
  1273 	test.Next(_L("Create read-only global chunk"));
  1274 	info.SetReadOnly();
  1275 	r = chunk.Create(info);
  1276 	test_KErrNone(r);
  1277 	test(chunk.IsReadable());
  1278 	test(chunk.IsWritable());
  1279 	// To keep in sync with the 'process2' process
  1280 	r = sem.CreateGlobal(KTestSemaphoreReadOnly, 0);
  1281 	test_KErrNone(r);
  1282 
  1283 	test.Next(_L("Attempt read 1"));
  1284 	r = process1.Create(RProcess().FileName(), KTestParamRo);
  1285 	test_KErrNone(r);
  1286 	process1.Logon(rs);
  1287 	process1.Resume();
  1288 	User::WaitForRequest(rs);
  1289 	test_Equal(EExitPanic, process1.ExitType());
  1290 	test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
  1291 	CLOSE_AND_WAIT(process1);
  1292 	// Create second process before commiting memory and make it wait
  1293 	r = process2.Create(RProcess().FileName(), KTestParamWait);
  1294 	test_KErrNone(r)
  1295 	process2.Rendezvous(rv);
  1296 	process2.Resume();
  1297 	User::WaitForRequest(rv);
  1298 
  1299 	test.Next(_L("Adjust size"));
  1300 	r = chunk.Adjust(1); // add one page
  1301 	test_KErrNone(r);
  1302 
  1303 	test.Next(_L("Attempt read 2"));
  1304 	r = process1.Create(RProcess().FileName(), KTestParamRo);
  1305 	test_KErrNone(r);
  1306 	process1.Logon(rs);
  1307 	process1.Resume();
  1308 	User::WaitForRequest(rs);
  1309 	test_Equal(EExitKill, process1.ExitType());
  1310 	test_KErrNone(process1.ExitReason());
  1311 	CLOSE_AND_WAIT(process1);
  1312 
  1313 	test.Next(_L("Attempt read/write 1"));
  1314 	r = process1.Create(RProcess().FileName(), KTestParamRw);
  1315 	test_KErrNone(r);
  1316 	process1.Logon(rs);
  1317 	process1.Resume();
  1318 	User::WaitForRequest(rs);
  1319 	test_Equal(EExitPanic, process1.ExitType());
  1320 	test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
  1321 	CLOSE_AND_WAIT(process1);
  1322 	// Controlling process is not affected
  1323 	TUint8* write = chunk.Base();
  1324 	*write = 0x77;
  1325 
  1326 	test.Next(_L("Attempt read/write 2"));
  1327 	test_Equal(EExitPending, process2.ExitType());
  1328 	process2.Logon(rs);
  1329 	sem.Signal();
  1330 	User::WaitForRequest(rs);
  1331 	test_Equal(EExitPanic, process2.ExitType());
  1332 	test_Equal(3, process2.ExitReason()); // KERN-EXEC 3 assumed
  1333 	CLOSE_AND_WAIT(process2);
  1334 
  1335 	chunk.Close();
  1336 	sem.Close();
  1337 	test.End();
  1338 	User::SetJustInTime(jit);
  1339 	}
  1340 
  1341 TInt E32Main()
  1342 //
  1343 //	Test RChunk class
  1344 //
  1345 	{
  1346 	test.Title();
  1347 	if (!HaveVirtMem())
  1348 		{
  1349 		test.Printf(_L("This test requires an MMU\n"));
  1350 		return KErrNone;
  1351 		}
  1352 	testInitialise();
  1353 
  1354 	// Turn off lazy dll unloading so the kernel heap checking isn't affected.
  1355 	RLoader l;
  1356 	test(l.Connect()==KErrNone);
  1357 	test(l.CancelLazyDllUnload()==KErrNone);
  1358 	l.Close();
  1359 
  1360 	_LIT(KExtended,"extended");
  1361 
  1362 	if (IsInCommandLine(KExtended))
  1363 		{
  1364 		__KHEAP_MARK;
  1365 		test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
  1366 		TestFullAddressSpace(ETrue);
  1367 		__KHEAP_MARKEND;
  1368 		}
  1369 	else if (IsInCommandLine(KTestParamRo))
  1370 		{
  1371 		test_KErrNone(User::RenameProcess(KTestParamRo));
  1372 		TestReadOnlyProcess(0);
  1373 		}
  1374 	else if (IsInCommandLine(KTestParamRw))
  1375 		{
  1376 		test_KErrNone(User::RenameProcess(KTestParamRw));
  1377 		TestReadOnlyProcess(ETestRw);
  1378 		}
  1379 	else if (IsInCommandLine(KTestParamWait))
  1380 		{
  1381 		test_KErrNone(User::RenameProcess(KTestParamWait));
  1382 		TestReadOnlyProcess(ETestRw | ETestWait);
  1383 		}
  1384 	else if (IsInCommandLine(KTestParamWritableChunk))
  1385 		{
  1386 		test_KErrNone(User::RenameProcess(KTestParamWritableChunk));
  1387 		TestReadOnlyProcess(ETestWritableChunk | ETestRw);
  1388 		}
  1389 	else 
  1390 		{
  1391 		__KHEAP_MARK;
  1392 		test.Start(_L("Testing.."));
  1393 		testAdjustChunk();
  1394 		test.Next(_L("Test1"));
  1395 		test1();
  1396 		test.Next(_L("Test2"));
  1397 		test2(0x80);
  1398 		test.Next(_L("Test3"));
  1399 		test3(0x7000);
  1400 		test.Next(_L("Test4"));
  1401 		test4(0x7000);
  1402 		test.Next(_L("Test5"));
  1403 		test5(0x80);
  1404 		test.Next(_L("Test7"));
  1405 		test7(0x80);
  1406 		test.Next(_L("Test chunk data clearing attributes"));
  1407 		testClear(0x500);
  1408 		testClear(07000);
  1409 		test.Next(_L("Test9"));
  1410 		testShare();
  1411 		test.Next(_L("Test memory notifiers"));
  1412 		testNotifiers();
  1413 		test.Next(_L("FindChunks"));
  1414 		FindChunks();
  1415 		
  1416 		test.Next(_L("Test full address space"));
  1417 		TestFullAddressSpace(EFalse);
  1418 
  1419 #ifdef __WINS__
  1420 		test.Next(_L("Test execution of code in a local code chunk on emulator"));
  1421 		TestExecLocalCode();
  1422 #endif	//  __WINS__
  1423 
  1424 		test.Next(_L("Test for race conditions in chunk closure"));
  1425 		TestClosure();
  1426 		test.Next(_L("Read-only chunks"));
  1427 		TestReadOnly();
  1428 		test.End();
  1429 		__KHEAP_MARKEND;
  1430 		}
  1431 
  1432 	test.Close();
  1433 	return(KErrNone);
  1434 	}