kerneltest/e32test/mmu/t_chunk.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     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 	}