kerneltest/e32test/demandpaging/t_pagetable_limit.cpp
changeset 231 75252ea6123b
parent 33 0173bcd7697c
child 257 3e88ff8f41d5
equal deleted inserted replaced
202:9aca3be14c27 231:75252ea6123b
    31 #include <e32svr.h>
    31 #include <e32svr.h>
    32 #include <u32std.h>
    32 #include <u32std.h>
    33 #include <hal.h>
    33 #include <hal.h>
    34 
    34 
    35 #include "t_dpcmn.h"
    35 #include "t_dpcmn.h"
       
    36 #include "../mmu/freeram.h"
    36 
    37 
    37 RTest test(_L("T_PAGETABLE_LIMIT"));
    38 RTest test(_L("T_PAGETABLE_LIMIT"));
       
    39 
       
    40 // The flexible memory model reserves 0xF800000-0xFFF00000 for page tables, which allows 130,048
       
    41 // pages tables.
       
    42 //
       
    43 // We attempt to map 40 * 40 * 100 == 160,000 page tables.
       
    44 // 
       
    45 // So that the limit is reached in the middle, half the chunks are mapped as paged and half as
       
    46 // unpaged.
       
    47 
       
    48 const TUint KPageTablesPerChunk = 40;
       
    49 const TUint KChunksPerProcess = 40;
       
    50 const TUint KNumProcesses = 100;
       
    51 
       
    52 const TUint KSizeMappedByPageTable = 1024 * 1024;  // the amount of RAM mapped by one page table
    38 
    53 
    39 
    54 
    40 _LIT(KClientPtServerName, "CClientPtServer");
    55 _LIT(KClientPtServerName, "CClientPtServer");
    41 _LIT(KClientProcessName, "T_PAGETABLE_LIMIT");
    56 _LIT(KClientProcessName, "T_PAGETABLE_LIMIT");
    42 
    57 
    44 	{
    59 	{
    45 	EClientConnect = -1,
    60 	EClientConnect = -1,
    46 	EClientDisconnect = -2,
    61 	EClientDisconnect = -2,
    47 	EClientGetChunk = 0,
    62 	EClientGetChunk = 0,
    48 	EClientReadChunks = 1,
    63 	EClientReadChunks = 1,
       
    64 	EClientGetParentProcess = 2,
    49 	};
    65 	};
    50 
    66 
    51 class RDataPagingSession : public RSessionBase
    67 class RDataPagingSession : public RSessionBase
    52 	{
    68 	{
    53 public:
    69 public:
    55 		{ 
    71 		{ 
    56 		return RSessionBase::CreateSession(aServerName,User::Version(),aMsgSlots);
    72 		return RSessionBase::CreateSession(aServerName,User::Version(),aMsgSlots);
    57 		}
    73 		}
    58 	TInt PublicSendReceive(TInt aFunction, const TIpcArgs &aPtr)
    74 	TInt PublicSendReceive(TInt aFunction, const TIpcArgs &aPtr)
    59 		{
    75 		{
    60 		return (SendReceive(aFunction, aPtr));
    76 		return SendReceive(aFunction, aPtr);
    61 		}
       
    62 	TInt PublicSend(TInt aFunction, const TIpcArgs &aPtr)
       
    63 		{
       
    64 		return (Send(aFunction, aPtr));
       
    65 		}
    77 		}
    66 	};
    78 	};
    67 
    79 
       
    80 #define CLIENT_TEST_IMPL(condition, code, line)			\
       
    81 	if (!(condition))									\
       
    82 		{												\
       
    83 		RDebug::Printf("Test %s failed at line %d");	\
       
    84 		r = (code);										\
       
    85 		goto exit;										\
       
    86 		}
       
    87 
       
    88 #define CLIENT_TEST(condition, code) CLIENT_TEST_IMPL(condition, code, __LINE__)
    68 
    89 
    69 TInt ClientProcess(TInt aLen)
    90 TInt ClientProcess(TInt aLen)
    70 	{
    91 	{
    71 	// Read the command line to get the number of chunk to map and whether or 
    92 	// Read the command line to get the number of chunk to map and whether or not to access their
    72 	// not to access their data.
    93 	// data.
    73 	HBufC* buf = HBufC::New(aLen);
    94 	HBufC* buf = HBufC::New(aLen);
    74 	test(buf != NULL);
    95 	test(buf != NULL);
    75 	TPtr ptr = buf->Des();
    96 	TPtr ptr = buf->Des();
    76 	User::CommandLine(ptr);
    97 	User::CommandLine(ptr);
    77 
       
    78 	TLex lex(ptr);
    98 	TLex lex(ptr);
       
    99 
       
   100 	RChunk* chunks = NULL;
       
   101 	RDataPagingSession session;
       
   102 	RProcess parent;
       
   103 	TRequestStatus parentStatus;
       
   104 	TInt offset = 0;
       
   105 	TInt i;
       
   106 	
    79 	TInt chunkCount;
   107 	TInt chunkCount;
    80 	TInt r = lex.Val(chunkCount);
   108 	TInt r = lex.Val(chunkCount);
    81 	test_KErrNone(r);
   109 	CLIENT_TEST(r == KErrNone, r);	
    82 	lex.SkipSpace();
   110 	lex.SkipSpace();
       
   111 	chunks = new RChunk[chunkCount];
       
   112 	CLIENT_TEST(chunks, KErrNoMemory);
    83 
   113 
    84 	TBool accessData;
   114 	TBool accessData;
    85 	r = lex.Val(accessData);
   115 	r = lex.Val(accessData);
    86 	test_KErrNone(r);
   116 	CLIENT_TEST(r == KErrNone, r);
    87 
   117 
    88 
   118 	r = session.CreateSession(KClientPtServerName, 1);
    89 	RDataPagingSession session;
   119 	CLIENT_TEST(r == KErrNone, r);
    90 	test_KErrNone(session.CreateSession(KClientPtServerName, 1));
   120 
    91 
   121 	r = parent.SetReturnedHandle(session.PublicSendReceive(EClientGetParentProcess, TIpcArgs()));
    92 	RChunk* chunks = new RChunk[chunkCount];
   122 	CLIENT_TEST(r == KErrNone, r);
    93 	for (TInt i = 0; i < chunkCount; i++)
   123 	
    94 		{
   124 	for (i = 0; i < chunkCount; i++)
    95 		TInt r = chunks[i].SetReturnedHandle(session.PublicSendReceive(EClientGetChunk, TIpcArgs(i)));
   125 		{
       
   126 		r = chunks[i].SetReturnedHandle(session.PublicSendReceive(EClientGetChunk, TIpcArgs(i)));
    96 		if (r != KErrNone)
   127 		if (r != KErrNone)
    97 			{
   128 			{
    98 			test.Printf(_L("Failed to create a handle to the server's chunk r=%d\n"), r);
   129 			RDebug::Printf("Failed to create a handle to chunk %d r=%d", i, r);
    99 			for (TInt j = 0; j < i; j++)
   130 			goto exit;
   100 				chunks[j].Close();
   131 			}
   101 			session.Close();
   132 		CLIENT_TEST(chunks[i].Size() >= gPageSize, KErrGeneral);
   102 			return r;
   133 		}
   103 			}
   134 
   104 		test_Value(chunks[i].Size(), chunks[i].Size() >= gPageSize);
   135 	// Logon to parent process
   105 		}
   136 	parent.Logon(parentStatus);
   106 	if (!accessData)
   137 
   107 		{
   138 	// Touch each mapped page of all of the chunks.
   108 		// Touch the 1st page of each of the chunks.
   139 	do
       
   140 		{
   109 		for (TInt i = 0; i < chunkCount; i++)
   141 		for (TInt i = 0; i < chunkCount; i++)
   110 			{
   142 			{
   111 			// Write the chunk data from top to bottom of the chunk's first page.
   143 			for (TUint j = 0 ; j < KPageTablesPerChunk ; j++)
   112 			TUint8* base = chunks[i].Base();
       
   113 			TUint8* end = base + gPageSize - 1;
       
   114 			*base = *end;
       
   115 			}
       
   116 		// Tell parent we've touched each chunk.
       
   117 		TInt r =  (TThreadId)session.PublicSendReceive(EClientReadChunks,TIpcArgs());	// Assumes id is only 32-bit.
       
   118 		test_KErrNone(r);
       
   119 		for(;;)
       
   120 			{// Wake up every 100ms to be killed by the main process.
       
   121 			User::After(100000);
       
   122 			}
       
   123 		}
       
   124 	else
       
   125 		{
       
   126 		for (;;)
       
   127 			{
       
   128 			TInt offset = 0;
       
   129 			for (TInt i = 0; i < chunkCount; i++)
       
   130 				{
   144 				{
   131 				// Write the chunk data from top to bottom of the chunk's first page.
   145 				// Write the chunk data from top to bottom of the chunk's first page.
   132 				TUint8* base = chunks[i].Base();
   146 				TUint8* base = chunks[i].Base() + j * KSizeMappedByPageTable;
   133 				TUint8* end = base + gPageSize - 1;
   147 				TUint8* end = base + gPageSize - 1;
   134 				*(base + offset) = *(end - offset);
   148 				*(base + offset) = *(end - offset);
       
   149 
       
   150 				User::After(0);
       
   151 
       
   152 				// Check whether main process is still running
       
   153 				if (parentStatus != KRequestPending)
       
   154 					{
       
   155 					// if we get here the test failed and the main process exited without killing
       
   156 					// us, so just exit quietly
       
   157 					User::WaitForRequest(parentStatus);
       
   158 					r = KErrGeneral;
       
   159 					goto exit;
       
   160 					}
   135 				}
   161 				}
   136 			if (++offset >= (gPageSize >> 1))
   162 			}
   137 				offset = 0;
   163 		offset = (offset + 1) % (gPageSize / 2);
   138 			}
   164 		}
   139 		}
   165 	while (accessData);
   140 	}
   166 
   141 
   167 	// Tell parent we've touched each page.
       
   168 	r = (TThreadId)session.PublicSendReceive(EClientReadChunks,TIpcArgs());	
       
   169 	CLIENT_TEST(r == KErrNone, r);
       
   170 		
       
   171 	// Wait till we get killed by the main process or the main process dies
       
   172 	User::WaitForRequest(parentStatus);
       
   173 	// if we get here the test failed and the main process exited without killing us, so just exit
       
   174 	r = KErrGeneral;
       
   175 
       
   176 exit:
       
   177 	if (chunks)
       
   178 		{
       
   179 		for (TInt i = 0 ; i < chunkCount; ++i)
       
   180 			chunks[i].Close();
       
   181 		}
       
   182 	session.Close();
       
   183 	parent.Close();
       
   184 			
       
   185 	return r;
       
   186 	}
       
   187 
       
   188 TInt FreeSwap()
       
   189 	{
       
   190 	SVMSwapInfo swapInfo;
       
   191 	test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalGetSwapInfo, &swapInfo, 0));
       
   192 	return swapInfo.iSwapFree;
       
   193 	}
       
   194 
       
   195 void PrintFreeRam()
       
   196 	{
       
   197 	test.Printf(_L("%d KB RAM / %d KB swap free\n"), FreeRam() / 1024, FreeSwap() / 1024);
       
   198 	}
       
   199 
       
   200 void CreateChunk(RChunk& aChunk, TInt aChunkIndex, TInt aPageTables, TBool aPaged)
       
   201 	{
       
   202 	// Creates a global chunk.
       
   203 	//
       
   204 	// The chunk uses KPageTablesPerChunk page tables by committing that number of pages at 1MB
       
   205 	// intervals.  Its max size is set so that it is not a multiple of 1MB and hence the FMM will
       
   206 	// use a fine mapping objects whose page tables are not shared between processes.
       
   207 	
       
   208 	test.Printf(_L("  creating chunk %d: "), aChunkIndex);
       
   209 	PrintFreeRam();
       
   210 	
       
   211 	TChunkCreateInfo createInfo;
       
   212 	createInfo.SetDisconnected(0, 0, aPageTables * KSizeMappedByPageTable + gPageSize);
       
   213 	createInfo.SetPaging(aPaged ? TChunkCreateInfo::EPaged : TChunkCreateInfo::EUnpaged);
       
   214 	TBuf<32> name;
       
   215 	name.AppendFormat(_L("t_pagetable_limit chunk %d"), aChunkIndex);
       
   216 	createInfo.SetGlobal(name);
       
   217 	test_KErrNone(aChunk.Create(createInfo));
       
   218 	for (TInt i = 0 ; i < aPageTables ; ++i)
       
   219 		test_KErrNone(aChunk.Commit(i * KSizeMappedByPageTable, gPageSize));
       
   220 	}
       
   221 
       
   222 void CreateProcess(RProcess& aProcess, TInt aProcessIndex, TInt aNumChunks, TBool aAccessData)
       
   223 	{
       
   224 	test.Printf(_L("  creating process %d: "), aProcessIndex);
       
   225 	PrintFreeRam();
       
   226 	
       
   227 	TBuf<80> args;
       
   228 	args.AppendFormat(_L("%d %d"), aNumChunks, aAccessData);
       
   229 	test_KErrNone(aProcess.Create(KClientProcessName, args));
       
   230 	aProcess.SetPriority(EPriorityLow);
       
   231 	}
   142 
   232 
   143 void TestMaxPt()
   233 void TestMaxPt()
   144 	{
   234 	{
   145 	// Flexible memory model reserves 0xF800000-0xFFF00000 for page tables
   235 	test.Printf(_L("Waiting for system idle and kernel cleanup\n"));
   146 	// this allows 130,048 pages tables.  Therefore mapping 1000 one 
   236 	// If this test was run previously, there may be lots of dead processes waiting to be cleaned up
   147 	// page chunks into 256 processes would require 256,000 page tables, i.e.
   237 	TInt r;
   148 	// more than enough to hit the limit.  So that the limit is reached in the middle,
   238 	while((r = FreeRam(10 * 1000)), r == KErrTimedOut)
   149 	// map 500 unpaged and 500 paged chunks in each process.
   239 		{
   150 	const TUint KNumChunks = 1000;
   240 		test.Printf(_L("  waiting: "));
   151 	const TUint KPagedChunksStart = (KNumChunks >> 1);
   241 		PrintFreeRam();
   152 	const TUint KNumProcesses = 256;
       
   153 	const TInt KMinFreeRam = (1000 * gPageSize) + (130048 * (gPageSize>>2));
       
   154 	TInt freeRam;
       
   155 	HAL::Get(HALData::EMemoryRAMFree, freeRam);
       
   156 	if (freeRam < KMinFreeRam)
       
   157 		{
       
   158 		test.Printf(_L("Only 0x%x bytes of free RAM not enough to perform the test.  Skipping test.\n"), freeRam);
       
   159 		return;
       
   160 		}
   242 		}
   161 
   243 
   162 	// Remove the maximum limit on the cache size as the test requires that it can
   244 	// Remove the maximum limit on the cache size as the test requires that it can
   163 	// allocate as many page tables as possible but without stealing any pages as
   245 	// allocate as many page tables as possible but without stealing any pages as
   164 	// stealing pages may indirectly steal paged page table pages.
   246 	// stealing pages may indirectly steal paged page table pages.
       
   247 	test.Printf(_L("Set paging cache max size unlimited\n"));
   165 	TUint minCacheSize, maxCacheSize, currentCacheSize;
   248 	TUint minCacheSize, maxCacheSize, currentCacheSize;
   166 	DPTest::CacheSize(minCacheSize,maxCacheSize,currentCacheSize);
   249 	test_KErrNone(DPTest::CacheSize(minCacheSize,maxCacheSize,currentCacheSize));
   167 	test_KErrNone(DPTest::SetCacheSize(minCacheSize, KMaxTUint));
   250 	test_KErrNone(DPTest::SetCacheSize(minCacheSize, KMaxTUint));
   168 
   251 
       
   252 	const TInt KMinFreeRam = (1000 * gPageSize) + (130048 * (gPageSize>>2));
       
   253 
       
   254 	// Ensure enough RAM available
       
   255 	PrintFreeRam();
       
   256 	TInt freeRam = FreeRam();
       
   257 	if (freeRam < KMinFreeRam)
       
   258 		{
       
   259 		test.Printf(_L("Only 0x%x bytes of free RAM not enough to perform the test.  Skipping test.\n"), freeRam);
       
   260 		return;
       
   261 		}
       
   262 
       
   263 	test.Printf(_L("Start server\n"));
   169 	RServer2 ptServer;
   264 	RServer2 ptServer;
   170 	TInt r = ptServer.CreateGlobal(KClientPtServerName);
   265 	r = ptServer.CreateGlobal(KClientPtServerName);
   171 	test_KErrNone(r);
   266 	test_KErrNone(r);
   172 
   267 
   173 	// Create the global unpaged chunks.  They have one page committed
   268 	test.Printf(_L("Create chunks\n"));
   174 	// but have a maximum size large enough to prevent their page tables being
   269 	const TUint KPagedChunksStart = (KChunksPerProcess >> 1);
   175 	// shared between the chunks.  On arm with 4KB pages each page table maps 1MB
   270 	RChunk* chunks = new RChunk[KChunksPerProcess];
   176 	// so make chunk 1MB+4KB so chunk requires 2 page tables and is not aligned on
   271 	test_NotNull(chunks);
   177 	// a 1MB boundary so it is a fine memory object.
       
   178 	const TUint KChunkSize = (1024 * 1024) + gPageSize;
       
   179 	RChunk* chunks = new RChunk[KNumChunks];
       
   180 	TChunkCreateInfo createInfo;
       
   181 	createInfo.SetNormal(gPageSize, KChunkSize);
       
   182 	createInfo.SetGlobal(KNullDesC);
       
   183 	createInfo.SetPaging(TChunkCreateInfo::EUnpaged);
       
   184 	TUint i = 0;
   272 	TUint i = 0;
   185 	for (; i < KPagedChunksStart; i++)
   273 	for (i = 0 ; i< KChunksPerProcess; i++)
   186 		{
   274 		CreateChunk(chunks[i], i, KPageTablesPerChunk, i >= KPagedChunksStart);
   187 		r = chunks[i].Create(createInfo);
       
   188 		test_KErrNone(r);
       
   189 		}
       
   190 	// Create paged chunks.
       
   191 	createInfo.SetPaging(TChunkCreateInfo::EPaged);
       
   192 	for (; i< KNumChunks; i++)
       
   193 		{
       
   194 		r = chunks[i].Create(createInfo);
       
   195 		test_KErrNone(r);
       
   196 		}
       
   197 
   275 
   198 	// Start remote processes, giving each process handles to each chunk.
   276 	// Start remote processes, giving each process handles to each chunk.
       
   277 	test.Printf(_L("Start remote processes\n"));
   199 	RProcess* processes = new RProcess[KNumProcesses];
   278 	RProcess* processes = new RProcess[KNumProcesses];
   200 	RMessage2 ptMessage;
   279 	test_NotNull(processes);
   201 	TUint processIndex = 0;
   280 	TRequestStatus* statuses = new TRequestStatus[KNumProcesses];
   202 	TUint processLimit = 0;
   281 	test_NotNull(statuses);
       
   282 	TUint processIndex = 0;	
   203 	for (; processIndex < KNumProcesses; processIndex++)
   283 	for (; processIndex < KNumProcesses; processIndex++)
   204 		{
   284 		{
   205 		// Start the process.
   285 		// Start the process.
   206 		test.Printf(_L("Creating process %d\n"), processIndex);
   286 		CreateProcess(processes[processIndex], processIndex, KChunksPerProcess, EFalse);
   207 		TBuf<80> args;
   287 		
   208 		args.AppendFormat(_L("%d %d"), KNumChunks, EFalse);
   288 		// logon to process
   209 		r = processes[processIndex].Create(KClientProcessName, args);
   289 		processes[processIndex].Logon(statuses[processIndex]);
   210 		test_KErrNone(r);
   290 		test_Equal(KRequestPending, statuses[processIndex].Int());
   211 		TRequestStatus s;
       
   212 		processes[processIndex].Logon(s);
       
   213 		test_Equal(KRequestPending, s.Int());
       
   214 		processes[processIndex].Resume();
   291 		processes[processIndex].Resume();
   215 
   292 
       
   293 		// wait for connect message
       
   294 		RMessage2 ptMessage;
   216 		ptServer.Receive(ptMessage);
   295 		ptServer.Receive(ptMessage);
   217 		test_Equal(EClientConnect, ptMessage.Function());
   296 		test_Equal(EClientConnect, ptMessage.Function());
   218 		ptMessage.Complete(KErrNone);
   297 		ptMessage.Complete(KErrNone);
   219 		TInt func = EClientGetChunk;
   298 
       
   299 		// pass client a handle to this process
       
   300 		ptServer.Receive(ptMessage);
       
   301 		test_Equal(EClientGetParentProcess, ptMessage.Function());
       
   302 		ptMessage.Complete(RProcess());
       
   303 
       
   304 		// pass client chunk handles
       
   305 		TInt func;
   220 		TUint chunkIndex = 0;
   306 		TUint chunkIndex = 0;
   221 		for (; chunkIndex < KNumChunks && func == EClientGetChunk; chunkIndex++)
   307 		for (; chunkIndex < KChunksPerProcess ; chunkIndex++)
   222 			{// Pass handles to all the unpaged chunks to the new process.
   308 			{// Pass handles to all the unpaged chunks to the new process.
   223 			ptServer.Receive(ptMessage);
   309 			ptServer.Receive(ptMessage);
   224 			func = ptMessage.Function();
   310 			func = ptMessage.Function();
   225 			if (func == EClientGetChunk)
   311 			if (func != EClientGetChunk)
   226 				{
   312 				break;
   227 				TUint index = ptMessage.Int0();
   313 			ptMessage.Complete(chunks[ptMessage.Int0()]);
   228 				ptMessage.Complete(chunks[index]);
       
   229 				}
       
   230 			}
   314 			}
   231 		if (func != EClientGetChunk)
   315 		if (func != EClientGetChunk)
   232 			{
   316 			{
   233 			// Should hit the limit of page tables and this process instance should exit
   317 			// Should hit the limit of page tables and this process instance should exit
   234 			// sending a disconnect message in the process.
   318 			// sending a disconnect message in the process.
   235 			test_Equal(EClientDisconnect, func);
   319 			test_Equal(EClientDisconnect, func);
   236 			// Should only fail when mapping unpaged chunks.
   320 			// Should only fail when mapping unpaged chunks.
   237 			test_Value(chunkIndex, chunkIndex < (KNumChunks >> 1));
   321 			test_Value(chunkIndex, chunkIndex < (KChunksPerProcess >> 1));
   238 			break;
   322 			break;
   239 			}
   323 			}
       
   324 		
   240 		// Wait for the process to access all the chunks and therefore 
   325 		// Wait for the process to access all the chunks and therefore 
   241 		// allocate the paged page tables before moving onto the next process.
   326 		// allocate the paged page tables before moving onto the next process.
   242 		ptServer.Receive(ptMessage);
   327 		ptServer.Receive(ptMessage);
   243 		func = ptMessage.Function();
   328 		func = ptMessage.Function();
   244 		test_Equal(EClientReadChunks, func);
   329 		test_Equal(EClientReadChunks, func);
   245 		ptMessage.Complete(KErrNone);
   330 		ptMessage.Complete(KErrNone);
   246 
   331 
   247 		// Should have mapped all the required chunks.
   332 		// Should have mapped all the required chunks.
   248 		test_Equal(KNumChunks, chunkIndex);
   333 		test_Equal(KChunksPerProcess, chunkIndex);
   249 		}
   334 		}
       
   335 	
   250 	// Should hit page table limit before KNumProcesses have been created.
   336 	// Should hit page table limit before KNumProcesses have been created.
   251 	test_Value(processIndex, processIndex < KNumProcesses - 1);
   337 	test_Value(processIndex, processIndex < KNumProcesses - 1);
   252 	processLimit = processIndex;
   338 	TUint processLimit = processIndex;
   253 
   339 
   254 	// Now create more processes to access paged data even though the page table 
   340 	// Now create more processes to access paged data even though the page table address space has
   255 	// address space has been exhausted.  Limit to 10 more processes as test takes 
   341 	// been exhausted.  Limit to 10 more processes as test takes long enough already.
   256 	// long enough already.
   342 	test.Printf(_L("Start accessor processes\n"));
   257 	processIndex++;
   343 	processIndex++;
   258 	TUint excessProcesses = KNumProcesses - processIndex;
   344 	TUint excessProcesses = KNumProcesses - processIndex;
   259 	TUint pagedIndexEnd = (excessProcesses > 10)? processIndex + 10 : processIndex + excessProcesses;
   345 	TUint pagedIndexEnd = (excessProcesses > 10)? processIndex + 10 : processIndex + excessProcesses;
   260 	for (; processIndex < pagedIndexEnd; processIndex++)
   346 	for (; processIndex < pagedIndexEnd; processIndex++)
   261 		{
   347 		{
   262 		// Start the process.
   348 		// start the process.
   263 		test.Printf(_L("Creating process %d\n"), processIndex);
   349 		CreateProcess(processes[processIndex], processIndex, KChunksPerProcess-KPagedChunksStart, ETrue);
   264 		TBuf<80> args;
   350 
   265 		args.AppendFormat(_L("%d %d"), KNumChunks-KPagedChunksStart, ETrue);
   351 		// logon to process
   266 		r = processes[processIndex].Create(KClientProcessName, args);
   352 		processes[processIndex].Logon(statuses[processIndex]);
   267 		if (r != KErrNone)
   353 		test_Equal(KRequestPending, statuses[processIndex].Int());
   268 			{// Have hit the limit of processes.
       
   269 			processIndex--;
       
   270 			// Should have created at least one more process.
       
   271 			test_Value(processIndex, processIndex > processLimit);
       
   272 			break;
       
   273 			}
       
   274 		TRequestStatus s;
       
   275 		processes[processIndex].Logon(s);
       
   276 		test_Equal(KRequestPending, s.Int());
       
   277 		processes[processIndex].Resume();
   354 		processes[processIndex].Resume();
   278 
   355 
       
   356 		// wait for connect message
       
   357 		RMessage2 ptMessage;
   279 		ptServer.Receive(ptMessage);
   358 		ptServer.Receive(ptMessage);
   280 		test_Equal(EClientConnect, ptMessage.Function());
   359 		test_Equal(EClientConnect, ptMessage.Function());
   281 		ptMessage.Complete(KErrNone);
   360 		ptMessage.Complete(KErrNone);
   282 
   361 
       
   362 		// pass client a handle to this process
       
   363 		ptServer.Receive(ptMessage);
       
   364 		test_Equal(EClientGetParentProcess, ptMessage.Function());
       
   365 		ptMessage.Complete(RProcess());
       
   366 		
   283 		TInt func = EClientGetChunk;
   367 		TInt func = EClientGetChunk;
   284 		TUint chunkIndex = KPagedChunksStart;
   368 		TUint chunkIndex = KPagedChunksStart;
   285 		for (; chunkIndex < KNumChunks && func == EClientGetChunk; chunkIndex++)
   369 		for (; chunkIndex < KChunksPerProcess && func == EClientGetChunk; chunkIndex++)
   286 			{// Pass handles to all the unpaged chunks to the new process.
   370 			{// Pass handles to all the paged chunks to the new process.
   287 			ptServer.Receive(ptMessage);
   371 			ptServer.Receive(ptMessage);
   288 			func = ptMessage.Function();
   372 			func = ptMessage.Function();
   289 			if (func == EClientGetChunk)
   373 			if (func == EClientGetChunk)
   290 				{
   374 				{
   291 				TUint index = ptMessage.Int0() + KPagedChunksStart;
   375 				TUint index = ptMessage.Int0() + KPagedChunksStart;
   299 			test_Value(processIndex, processIndex > processLimit+1);
   383 			test_Value(processIndex, processIndex > processLimit+1);
   300 			break;
   384 			break;
   301 			}
   385 			}
   302 
   386 
   303 		// Should have mapped all the required chunks.
   387 		// Should have mapped all the required chunks.
   304 		test_Equal(KNumChunks, chunkIndex);
   388 		test_Equal(KChunksPerProcess, chunkIndex);
   305 		}
   389 		}
       
   390 	
   306 	// If we reached the end of then ensure that we kill only the running processes.
   391 	// If we reached the end of then ensure that we kill only the running processes.
   307 	if (processIndex == pagedIndexEnd)
   392 	if (processIndex == pagedIndexEnd)
   308 		processIndex--;
   393 		processIndex--;
       
   394 
       
   395 	// Let the accessor processes run awhile
       
   396 	test.Printf(_L("Waiting...\n"));
       
   397 	User::After(10 * 1000000);
       
   398 	
   309 	// Kill all the remote processes
   399 	// Kill all the remote processes
       
   400 	test.Printf(_L("Killing processes...\n"));
   310 	for(TInt j = processIndex; j >= 0; j--)
   401 	for(TInt j = processIndex; j >= 0; j--)
   311 		{
   402 		{
   312 		test.Printf(_L("killing process %d\n"), j);
   403 		test.Printf(_L("  killing process %d\n"), j);
   313 		TRequestStatus req;
   404 		if (statuses[j] == KRequestPending)
   314 		processes[j].Logon(req);
       
   315 		if (req == KRequestPending)
       
   316 			{
       
   317 			processes[j].Kill(KErrNone);
   405 			processes[j].Kill(KErrNone);
   318 			User::WaitForRequest(req);
       
   319 			}
       
   320 		processes[j].Close();
   406 		processes[j].Close();
   321 		}
   407 		User::WaitForRequest(statuses[j]);
   322 	delete[] processes;
   408 		}
       
   409 	delete [] processes;
       
   410 	delete [] statuses;
       
   411 	
   323 	// Close the chunks.
   412 	// Close the chunks.
   324 	for (TUint k = 0; k < KNumChunks; k++)
   413 	for (TUint k = 0; k < KChunksPerProcess; k++)
   325 		chunks[k].Close();
   414 		chunks[k].Close();
   326 	delete[] chunks;
   415 	delete[] chunks;
   327 	
   416 
       
   417 	// Reset live list size
   328 	test_KErrNone(DPTest::SetCacheSize(minCacheSize, maxCacheSize));
   418 	test_KErrNone(DPTest::SetCacheSize(minCacheSize, maxCacheSize));
   329 	}
   419 	}
   330 
   420 
   331 
   421 
   332 TInt E32Main()
   422 TInt E32Main()