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