os/kernelhwsrv/kerneltest/e32test/mmu/t_mmustress.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/mmu/t_mmustress.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,669 @@
     1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// e32test\mmu\t_mmustress.cpp
    1.18 +// Stress test for memory management services performed by the kernel's memory model.
    1.19 +// 
    1.20 +//
    1.21 +
    1.22 +/**
    1.23 + @file
    1.24 +*/
    1.25 +
    1.26 +#define __E32TEST_EXTENSION__
    1.27 +#include <e32test.h>
    1.28 +#include "u32std.h"
    1.29 +#include <u32hal.h>
    1.30 +#include <e32svr.h>
    1.31 +#include <dptest.h>
    1.32 +#include <e32def.h>
    1.33 +#include <e32def_private.h>
    1.34 +#include "d_memorytest.h"
    1.35 +#include "..\defrag\d_pagemove.h"
    1.36 +
    1.37 +TBool TRACE = 0;
    1.38 +
    1.39 +LOCAL_D RTest test(_L("T_MMUSTRESS"));
    1.40 +
    1.41 +TUint32 MemModelAttributes;
    1.42 +TUint32 MemModel;
    1.43 +TInt PageSize;
    1.44 +TInt PageMask;
    1.45 +
    1.46 +#if !defined(__WINS__) && !defined(__X86__)
    1.47 +const TPtrC KMoveLddFileName=_L("D_PAGEMOVE.LDD");
    1.48 +RPageMove MoveLdd;
    1.49 +#endif
    1.50 +
    1.51 +RMemoryTestLdd Ldd;
    1.52 +
    1.53 +const TUint KNumTestChunks = 6;
    1.54 +RChunk Chunks[KNumTestChunks];
    1.55 +TInt Committed[KNumTestChunks] = {0}; // for each chunk, is the 'owned' region uncommited(0), commited(1) or mixed(-1)
    1.56 +class TNicePtr8 : public TPtr8 { public: TNicePtr8() : TPtr8(0,0) {} } ChunkPtr[KNumTestChunks];
    1.57 +
    1.58 +const TUint KNumSlaveProcesses = 4;
    1.59 +RProcess Slaves[KNumSlaveProcesses];
    1.60 +TRequestStatus SlaveLogons[KNumSlaveProcesses];
    1.61 +TRequestStatus SlaveRendezvous[KNumSlaveProcesses];
    1.62 +
    1.63 +TInt SlaveNumber = -1; // master process is slave -1
    1.64 +
    1.65 +const TInt KLocalIpcBufferSize = 0x10000;
    1.66 +TUint8* LocalIpcBuffer = 0;
    1.67 +
    1.68 +RSemaphore StartSemaphore;
    1.69 +
    1.70 +//
    1.71 +// Random number generation
    1.72 +//
    1.73 +
    1.74 +TUint32 RandomSeed;
    1.75 +
    1.76 +TUint32 Random()
    1.77 +	{
    1.78 +	RandomSeed = RandomSeed*69069+1;
    1.79 +	return RandomSeed;
    1.80 +	}
    1.81 +
    1.82 +TUint32 Random(TUint32 aRange)
    1.83 +	{
    1.84 +	return (TUint32)((TUint64(Random())*TUint64(aRange))>>32);
    1.85 +	}
    1.86 +
    1.87 +void RandomInit(TUint32 aSeed)
    1.88 +	{
    1.89 +	RandomSeed = aSeed+(aSeed<<8)+(aSeed<<16)+(aSeed<<24);
    1.90 +	Random();
    1.91 +	Random();
    1.92 +	}
    1.93 +
    1.94 +
    1.95 +
    1.96 +//
    1.97 +// Chunk utils
    1.98 +//
    1.99 +
   1.100 +TBuf<KMaxKernelName> ChunkName(TInt aChunkNumber)
   1.101 +	{
   1.102 +	TBuf<KMaxKernelName> name;
   1.103 +	name.Format(_L("T_MMUSTRESS-Chunk%d"),aChunkNumber);
   1.104 +	return name;
   1.105 +	}
   1.106 +
   1.107 +#ifdef __WINS__
   1.108 +TInt KChunkShift = 16;
   1.109 +#elif defined(__X86__)
   1.110 +TInt KChunkShift = 22;
   1.111 +#else
   1.112 +TInt KChunkShift = 20;
   1.113 +#endif
   1.114 +
   1.115 +TInt ChunkSize(TInt aChunkNumber)
   1.116 +	{
   1.117 +	// biggest chunk (number 0) is big enough for each slave to own a region which is
   1.118 +	// 2 page tables ('chunks') in size...
   1.119 +	return (2*KNumSlaveProcesses)<<(KChunkShift-aChunkNumber);
   1.120 +	}
   1.121 +
   1.122 +// check smallest chunk is less than 'chunk' size...
   1.123 +__ASSERT_COMPILE((2*KNumSlaveProcesses>>(KNumTestChunks-1))==0);
   1.124 +
   1.125 +
   1.126 +/* Memory region 'owned' by this slave process */
   1.127 +void ChunkOwnedRegion(TInt aChunkNumber,TInt& aOffset,TInt& aSize)
   1.128 +	{
   1.129 +	TInt size = ChunkSize(aChunkNumber)/KNumSlaveProcesses;
   1.130 +	aSize = size;
   1.131 +	aOffset = SlaveNumber*size;
   1.132 +	test_Equal(0,size&PageMask);
   1.133 +	}
   1.134 +
   1.135 +void ChunkMarkRegion(TInt aChunkNumber,TInt aOffset,TInt aSize)
   1.136 +	{
   1.137 +	TInt pageSize = PageSize;
   1.138 +	TUint32 mark = aOffset|aChunkNumber|(SlaveNumber<<4);
   1.139 +	TUint8* ptr = Chunks[aChunkNumber].Base()+aOffset;
   1.140 +	TUint8* ptrEnd = ptr+aSize;
   1.141 +	while(ptr<ptrEnd)
   1.142 +		{
   1.143 +		((TUint32*)ptr)[0] = mark;
   1.144 +		((TUint32*)ptr)[1] = ~mark;
   1.145 +		mark += pageSize;
   1.146 +		ptr += pageSize;
   1.147 +		}
   1.148 +	}
   1.149 +
   1.150 +void ChunkCheckRegion(TInt aChunkNumber,TInt aOffset,TInt aSize)
   1.151 +	{
   1.152 +	TInt pageSize = PageSize;
   1.153 +	TUint32 mark = aOffset|aChunkNumber|(SlaveNumber<<4);
   1.154 +	TUint8* ptr = Chunks[aChunkNumber].Base()+aOffset;
   1.155 +	TUint8* ptrEnd = ptr+aSize;
   1.156 +	while(ptr<ptrEnd)
   1.157 +		{
   1.158 +		test_Equal(mark,((TUint32*)ptr)[0]);
   1.159 +		test_Equal(~mark,((TUint32*)ptr)[1]);
   1.160 +		mark += pageSize;
   1.161 +		ptr += pageSize;
   1.162 +		}
   1.163 +	}
   1.164 +
   1.165 +TInt ChunkOpen(TInt aChunkNumber)
   1.166 +	{
   1.167 +	RChunk& chunk = Chunks[aChunkNumber];
   1.168 +	if(chunk.Handle()!=0)
   1.169 +		return KErrNone;
   1.170 +
   1.171 +	if(TRACE) RDebug::Printf("%d %d Open",SlaveNumber,aChunkNumber);
   1.172 +	TInt r = chunk.OpenGlobal(ChunkName(aChunkNumber),false);
   1.173 +	if(r!=KErrNoMemory)
   1.174 +		test_KErrNone(r);
   1.175 +	return r;
   1.176 +	}
   1.177 +
   1.178 +//
   1.179 +// Server utils
   1.180 +//
   1.181 +
   1.182 +TBuf<KMaxKernelName> ServerName(TInt aSlaveNumber)
   1.183 +	{
   1.184 +	TBuf<KMaxKernelName> name;
   1.185 +	name.Format(_L("T_MMUSTRESS-Server%d"),aSlaveNumber);
   1.186 +	return name;
   1.187 +	}
   1.188 +
   1.189 +RServer2 Server;
   1.190 +RMessage2 ServerMessage;
   1.191 +TRequestStatus ServerStatus;
   1.192 +
   1.193 +class RTestSession : public RSessionBase
   1.194 +	{
   1.195 +public:
   1.196 +	TInt Connect(TInt aServerNumber)
   1.197 +		{
   1.198 +		return CreateSession(ServerName(aServerNumber),TVersion(),1,EIpcSession_Unsharable,0,&iStatus);
   1.199 +		}
   1.200 +	TInt Send(TInt aChunkNumber)
   1.201 +		{
   1.202 +		return RSessionBase::Send(0,TIpcArgs(SlaveNumber,aChunkNumber,&ChunkPtr[aChunkNumber]));
   1.203 +		}
   1.204 +	TRequestStatus iStatus;
   1.205 +	};
   1.206 +RTestSession Sessions[KNumSlaveProcesses];
   1.207 +
   1.208 +
   1.209 +//
   1.210 +//
   1.211 +//
   1.212 +
   1.213 +void SlaveInit()
   1.214 +	{
   1.215 +	RDebug::Printf("Slave %d initialising",SlaveNumber);
   1.216 +
   1.217 +	TBuf<KMaxKernelName> name;
   1.218 +	name.Format(_L("T_MMUSTRESS-Slave%d"),SlaveNumber);
   1.219 +	User::RenameThread(name);
   1.220 +
   1.221 +	test_KErrNone(StartSemaphore.Open(2));
   1.222 +	TInt r;
   1.223 +#if !defined(__WINS__) && !defined(__X86__)
   1.224 +	// Move ldd may not be in the ROM so needs to be loaded.
   1.225 +	r=User::LoadLogicalDevice(KMoveLddFileName);
   1.226 +	test_Value(r, r==KErrNone || r==KErrAlreadyExists);
   1.227 +	test_KErrNone(MoveLdd.Open());
   1.228 +#endif
   1.229 +
   1.230 +	test_KErrNone(Ldd.Open());
   1.231 +	test_KErrNone(Ldd.CreateVirtualPinObject());
   1.232 +
   1.233 +	LocalIpcBuffer = (TUint8*)User::Alloc(KLocalIpcBufferSize);
   1.234 +	test(LocalIpcBuffer!=0);
   1.235 +
   1.236 +	test_KErrNone(Server.CreateGlobal(ServerName(SlaveNumber)));
   1.237 +
   1.238 +	TUint i;
   1.239 +
   1.240 +	// create sessions with other slaves...
   1.241 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.242 +		{
   1.243 +		for(;;)
   1.244 +			{
   1.245 +			r = Sessions[i].Connect(i);
   1.246 +//			RDebug::Printf("%d Session %d = %d,%d",SlaveNumber,i,r,Sessions[i].iStatus.Int());
   1.247 +			if(r==KErrNotFound)
   1.248 +				{
   1.249 +				// give other slaves time to create their servers...
   1.250 +				User::After(10000);
   1.251 +				continue;
   1.252 +				}
   1.253 +			test_KErrNone(r);
   1.254 +			break;
   1.255 +			}
   1.256 +		}
   1.257 +
   1.258 +	// process session connect messages...
   1.259 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.260 +		{
   1.261 +		RMessage2 m;
   1.262 +//		RDebug::Printf("%d Server waiting for connect message",SlaveNumber);
   1.263 +		Server.Receive(m);
   1.264 +		test_Equal(RMessage2::EConnect,m.Function())
   1.265 +		m.Complete(KErrNone);
   1.266 +		}
   1.267 +
   1.268 +	// wait for our session connections...
   1.269 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.270 +		{
   1.271 +//		RDebug::Printf("%d Session wait %d",SlaveNumber,i);
   1.272 +		User::WaitForRequest(Sessions[i].iStatus);
   1.273 +		}
   1.274 +
   1.275 +	// prime server for receiving mesages...
   1.276 +	Server.Receive(ServerMessage,ServerStatus);
   1.277 +
   1.278 +	// synchronise with other processes...
   1.279 +	RDebug::Printf("Slave %d waiting for trigger",SlaveNumber);
   1.280 +	RProcess::Rendezvous(KErrNone);
   1.281 +	StartSemaphore.Wait();
   1.282 +	RDebug::Printf("Slave %d started",SlaveNumber);
   1.283 +	}
   1.284 +
   1.285 +
   1.286 +
   1.287 +//
   1.288 +// Test by random operations...
   1.289 +//
   1.290 +
   1.291 +void DoTest()
   1.292 +	{
   1.293 +	RandomInit(SlaveNumber);
   1.294 +	TInt r;
   1.295 +	for(;;)
   1.296 +		{
   1.297 +		// select random chunk...
   1.298 +		TInt chunkNumber = Random(KNumTestChunks);
   1.299 +		RChunk& chunk = Chunks[chunkNumber];
   1.300 +
   1.301 +		// get the region of this chunk which this process 'owns'...
   1.302 +		TInt offset;
   1.303 +		TInt size;
   1.304 +		ChunkOwnedRegion(chunkNumber,offset,size);
   1.305 +
   1.306 +		// calculate a random region in the owned part...
   1.307 +		TInt randomOffset = offset+(Random(size)&~PageMask);
   1.308 +		TInt randomSize = (Random(size-(randomOffset-offset))+PageMask)&~PageMask;
   1.309 +		if(!randomSize)
   1.310 +			continue; // try again
   1.311 +
   1.312 +		// pick a random slave...
   1.313 +		TInt randomSlave = Random(KNumSlaveProcesses);
   1.314 +
   1.315 +		// open chunk if it isn't already...
   1.316 +		r = ChunkOpen(chunkNumber);
   1.317 +		if(r==KErrNoMemory)
   1.318 +			continue; // can't do anything with chunk if we can't open it
   1.319 +
   1.320 +		// check our contents of chunk...
   1.321 +		if(Committed[chunkNumber]==1)
   1.322 +			{
   1.323 +			if(TRACE) RDebug::Printf("%d %d Check %08x+%08x",SlaveNumber,chunkNumber,offset,size);
   1.324 +			ChunkCheckRegion(chunkNumber,offset,size);
   1.325 +			}
   1.326 +
   1.327 +		// perform random operation...
   1.328 +		switch(Random(12))
   1.329 +			{
   1.330 +		case 0:
   1.331 +		case 1:
   1.332 +			// close chunk...
   1.333 +			if(TRACE) RDebug::Printf("%d %d Close",SlaveNumber,chunkNumber);
   1.334 +			chunk.Close();
   1.335 +			break;
   1.336 +
   1.337 +		case 2:
   1.338 +			// commit all...
   1.339 +			if(TRACE) RDebug::Printf("%d %d Commit all %08x+%08x",SlaveNumber,chunkNumber,offset,size);
   1.340 +			if(Committed[chunkNumber]!=0)
   1.341 +				{
   1.342 +				r = chunk.Decommit(offset,size);
   1.343 +				test_KErrNone(r);
   1.344 +				Committed[chunkNumber] = 0;
   1.345 +				}
   1.346 +			r = chunk.Commit(offset,size);
   1.347 +			if(r!=KErrNoMemory)
   1.348 +				{
   1.349 +				test_KErrNone(r);
   1.350 +				Committed[chunkNumber] = 1;
   1.351 +				ChunkMarkRegion(chunkNumber,offset,size);
   1.352 +				}
   1.353 +			break;
   1.354 +
   1.355 +		case 3:
   1.356 +			// decommit all...
   1.357 +			if(TRACE) RDebug::Printf("%d %d Decommit all %08x+%08x",SlaveNumber,chunkNumber,offset,size);
   1.358 +			r = chunk.Decommit(offset,size);
   1.359 +			test_KErrNone(r);
   1.360 +			Committed[chunkNumber] = 0;
   1.361 +			break;
   1.362 +
   1.363 +		case 4:
   1.364 +		case 5:
   1.365 +			// commit random...
   1.366 +			if(TRACE) RDebug::Printf("%d %d Commit %08x+%08x",SlaveNumber,chunkNumber,randomOffset,randomSize);
   1.367 +			r = chunk.Commit(randomOffset,randomSize);
   1.368 +			if(r!=KErrNoMemory)
   1.369 +				{
   1.370 +				if(Committed[chunkNumber]==0)
   1.371 +					{
   1.372 +					test_KErrNone(r);
   1.373 +					Committed[chunkNumber] = -1;
   1.374 +					}
   1.375 +				else if(Committed[chunkNumber]==1)
   1.376 +					{
   1.377 +					test_Equal(KErrAlreadyExists,r);
   1.378 +					}
   1.379 +				else
   1.380 +					{
   1.381 +					if(r!=KErrAlreadyExists)
   1.382 +						test_KErrNone(r);
   1.383 +					}
   1.384 +				}
   1.385 +			break;
   1.386 +
   1.387 +		case 6:
   1.388 +		case 7:
   1.389 +			// decommit random...
   1.390 +			if(TRACE) RDebug::Printf("%d %d Decommit %08x+%08x",SlaveNumber,chunkNumber,randomOffset,randomSize);
   1.391 +			r = chunk.Decommit(randomOffset,randomSize);
   1.392 +			test_KErrNone(r);
   1.393 +			if(Committed[chunkNumber]==1)
   1.394 +				Committed[chunkNumber] = -1;
   1.395 +			break;
   1.396 +
   1.397 +		case 8:
   1.398 +			if(TRACE) RDebug::Printf("%d %d IPC Send->%d",SlaveNumber,chunkNumber,randomSlave);
   1.399 +//			ChunkPtr[chunkNumber].Set(chunk.Base(),ChunkSize(chunkNumber),ChunkSize(chunkNumber));
   1.400 +			ChunkPtr[chunkNumber].Set(chunk.Base()+offset,size,size);
   1.401 +			Sessions[randomSlave].Send(chunkNumber);
   1.402 +			break;
   1.403 +
   1.404 +		case 9:
   1.405 +			// process IPC messages...
   1.406 +			if(ServerStatus.Int()==KRequestPending)
   1.407 +				continue;
   1.408 +			User::WaitForRequest(ServerStatus);
   1.409 +
   1.410 +			{
   1.411 +			TInt sourceSlave = ServerMessage.Int0();
   1.412 +			chunkNumber = ServerMessage.Int1();
   1.413 +			if(TRACE) RDebug::Printf("%d %d IPC Receive<-%d",SlaveNumber,chunkNumber,sourceSlave);
   1.414 +			test_Equal(0,ServerMessage.Function());
   1.415 +
   1.416 +			// get local descriptor for owned region in chunk...
   1.417 +			size = ServerMessage.GetDesMaxLength(2);
   1.418 +			test_NotNegative(size);
   1.419 +			if(size>KLocalIpcBufferSize)
   1.420 +				size = KLocalIpcBufferSize;
   1.421 +			TPtr8 local(LocalIpcBuffer,size,size);
   1.422 +
   1.423 +//			if(Random(2))
   1.424 +				{
   1.425 +				// IPC read from other slave...
   1.426 +				if(TRACE) RDebug::Printf("%d %d IPC Read<-%d",SlaveNumber,chunkNumber,sourceSlave);
   1.427 +				TInt panicTrace = Ldd.SetPanicTrace(EFalse);
   1.428 +				r = ServerMessage.Read(2,local);
   1.429 +				Ldd.SetPanicTrace(panicTrace);
   1.430 +				if(r!=KErrBadDescriptor)
   1.431 +					test_KErrNone(r);
   1.432 +				}
   1.433 +//			else
   1.434 +//				{
   1.435 +//				// IPC write to other slave...
   1.436 +//				if(TRACE) RDebug::Printf("%d %d IPC Write->%d",SlaveNumber,chunkNumber,sourceSlave);
   1.437 +//				r = ServerMessage.Write(2,local,offset);
   1.438 +//				if(r!=KErrBadDescriptor)
   1.439 +//					test_KErrNone(r);
   1.440 +//				if(Committed[chunkNumber]==1)
   1.441 +//					ChunkMarkRegion(chunkNumber,offset,size);
   1.442 +//				}
   1.443 +			}
   1.444 +
   1.445 +			ServerMessage.Complete(KErrNone);
   1.446 +			Server.Receive(ServerMessage,ServerStatus);
   1.447 +			break;
   1.448 +
   1.449 +		case 10:
   1.450 +		case 11:
   1.451 +			// pin memory...
   1.452 +			{
   1.453 +			test_KErrNone(Ldd.UnpinVirtualMemory());
   1.454 +			for(TInt tries=10; tries>0; --tries)
   1.455 +				{
   1.456 +				TInt chunkSize = ChunkSize(chunkNumber);
   1.457 +				offset = Random(chunkSize);
   1.458 +				TInt maxSize = chunkSize-offset;
   1.459 +				if(maxSize>0x1000)
   1.460 +					maxSize = 0x1000;
   1.461 +				size = Random(maxSize);
   1.462 +				r = Ldd.PinVirtualMemory((TLinAddr)chunk.Base()+offset, size);
   1.463 +				if(r!=KErrNotFound && r!=KErrNoMemory)
   1.464 +					{
   1.465 +					test_KErrNone(r);
   1.466 +					break;
   1.467 +					}
   1.468 +				}
   1.469 +			}
   1.470 +			break;
   1.471 +		case 12:
   1.472 +		case 13:
   1.473 +			// Move any page in the chunk, not just the owned region.
   1.474 +			{
   1.475 +#if !defined(__WINS__) && !defined(__X86__)
   1.476 +			for(TInt tries=10; tries>0; --tries)
   1.477 +				{
   1.478 +				TInt chunkSize = ChunkSize(chunkNumber);
   1.479 +				offset = Random(chunkSize);
   1.480 +				MoveLdd.TryMovingUserPage((TAny*)(chunk.Base()+offset), ETrue);
   1.481 +				// Allow the move to fail for any reason as the page of the chunk
   1.482 +				// may or may not be currently committed, pinned, or accessed.
   1.483 +				}
   1.484 +#endif
   1.485 +			}
   1.486 +			break;
   1.487 +		default:
   1.488 +			test(false); // can't happen
   1.489 +			break;
   1.490 +			}
   1.491 +		}
   1.492 +	}
   1.493 +
   1.494 +
   1.495 +
   1.496 +TInt E32Main()
   1.497 +	{
   1.498 +	// get system info...
   1.499 +	MemModelAttributes = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
   1.500 +	MemModel = MemModelAttributes&EMemModelTypeMask;
   1.501 +	UserHal::PageSizeInBytes(PageSize);
   1.502 +	PageMask = PageSize-1;
   1.503 +
   1.504 +	// see if we are a slave process...
   1.505 +	if(User::GetTIntParameter(1,SlaveNumber)==KErrNone)
   1.506 +		{
   1.507 +		// do testing...
   1.508 +		SlaveInit();
   1.509 +		DoTest();
   1.510 +		return KErrGeneral; // shouldn't have returned from testing
   1.511 +		}
   1.512 +
   1.513 +	// master process...
   1.514 +	TBool pass = true; // final test result
   1.515 +	test.Title();
   1.516 +	if((MemModelAttributes&EMemModelAttrVA)==false)
   1.517 +		{
   1.518 +		test.Start(_L("TESTS NOT RUN - Not relevent for the memory model"));
   1.519 +		test.End();
   1.520 +		return KErrNone;
   1.521 +		}
   1.522 +
   1.523 +	// get time to run tests for...
   1.524 +	TInt timeout = 10; // time in seconds
   1.525 +	TInt cmdLineLen = User::CommandLineLength();
   1.526 +	if(cmdLineLen)
   1.527 +		{
   1.528 +		// get timeout value from command line
   1.529 +		RBuf cmdLine;
   1.530 +		test_KErrNone(cmdLine.Create(cmdLineLen));
   1.531 +		User::CommandLine(cmdLine);
   1.532 +		test_KErrNone(TLex(cmdLine).Val(timeout));
   1.533 +		if(timeout==0)
   1.534 +			timeout = KMaxTInt;
   1.535 +		}
   1.536 +	TTimeIntervalMicroSeconds32 tickTime;
   1.537 +	test_KErrNone(UserHal::TickPeriod(tickTime));
   1.538 +	TInt ticksPerSecond = 1000000/tickTime.Int();
   1.539 +	TInt timeoutTicks;
   1.540 +	if(timeout<KMaxTInt/ticksPerSecond)
   1.541 +		timeoutTicks = timeout*ticksPerSecond;
   1.542 +	else
   1.543 +		{
   1.544 +		timeoutTicks = KMaxTInt;
   1.545 +		timeout = timeoutTicks/ticksPerSecond;
   1.546 +		}
   1.547 +
   1.548 +	// master process runs at higher priority than slaves so it can timeout and kill them...
   1.549 +	RThread().SetPriority(EPriorityMore);
   1.550 +
   1.551 +	test.Start(_L("Creating test chunks"));
   1.552 +	TUint i;
   1.553 +	for(i=0; i<KNumTestChunks; i++)
   1.554 +		{
   1.555 +		test.Printf(_L("Size %dkB\r\n"),ChunkSize(i)>>10);
   1.556 +		test_KErrNone(Chunks[i].CreateDisconnectedGlobal(ChunkName(i),0,0,ChunkSize(i)));
   1.557 +		}
   1.558 +
   1.559 +	test.Next(_L("Spawning slave processes"));
   1.560 +	test_KErrNone(StartSemaphore.CreateGlobal(KNullDesC,0));
   1.561 +	TFileName processFile(RProcess().FileName());
   1.562 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.563 +		{
   1.564 +		test.Printf(_L("Slave %d\r\n"),i);
   1.565 +		RProcess& slave = Slaves[i];
   1.566 +		test_KErrNone(slave.Create(processFile,KNullDesC));
   1.567 +		test_KErrNone(slave.SetParameter(1,i));
   1.568 +		test_KErrNone(slave.SetParameter(2,StartSemaphore));
   1.569 +		slave.Logon(SlaveLogons[i]);
   1.570 +		test_Equal(KRequestPending,SlaveLogons[i].Int());
   1.571 +		slave.Rendezvous(SlaveRendezvous[i]);
   1.572 +		test_Equal(KRequestPending,SlaveRendezvous[i].Int());
   1.573 +		}
   1.574 +
   1.575 +	test.Next(_L("Create timer"));
   1.576 +	RTimer timer;
   1.577 +	test_KErrNone(timer.CreateLocal());
   1.578 +
   1.579 +	test.Next(_L("Resuming slave processes"));
   1.580 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.581 +		Slaves[i].Resume();
   1.582 +
   1.583 +	// this test must now take care not to die (e.g. panic due to assert fail)
   1.584 +	// until it has killed the slave processes
   1.585 +
   1.586 +	test.Next(_L("Change paging cache size"));
   1.587 +	TUint cacheOriginalMin = 0;
   1.588 +	TUint cacheOriginalMax = 0;
   1.589 +	TUint cacheCurrentSize = 0;
   1.590 +	DPTest::CacheSize(cacheOriginalMin, cacheOriginalMax, cacheCurrentSize);
   1.591 +	DPTest::SetCacheSize(1, 2*ChunkSize(0)); // big enough for all the test chunks
   1.592 +
   1.593 +	test.Next(_L("Wait for slaves to initialise"));
   1.594 +	TRequestStatus timeoutStatus;
   1.595 +	timer.After(timeoutStatus,10*1000000); // allow short time for slaves to initialise
   1.596 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.597 +		{
   1.598 +		User::WaitForAnyRequest(); // wait for a rendexvous
   1.599 +		if(timeoutStatus.Int()!=KRequestPending)
   1.600 +			{
   1.601 +			test.Printf(_L("Timeout waiting for slaves to initialise\r\n"));
   1.602 +			pass = false;
   1.603 +			break;
   1.604 +			}
   1.605 +		}
   1.606 +
   1.607 +	test.Next(_L("Restore paging cache size"));
   1.608 +	DPTest::SetCacheSize(cacheOriginalMin, cacheOriginalMax);
   1.609 +
   1.610 +	if(pass)
   1.611 +		{
   1.612 +		timer.Cancel();
   1.613 +		User::WaitForAnyRequest(); // swallow timer signal
   1.614 +
   1.615 +		test.Next(_L("Check slaves are ready"));
   1.616 +		for(i=0; i<KNumSlaveProcesses; i++)
   1.617 +			{
   1.618 +			if(SlaveRendezvous[i].Int()!=KErrNone || Slaves[i].ExitType()!=EExitPending)
   1.619 +				{
   1.620 +				test.Printf(_L("Slaves not ready or died!\r\n"));
   1.621 +				pass = false;
   1.622 +				break;
   1.623 +				}
   1.624 +			}
   1.625 +		}
   1.626 +
   1.627 +	if(pass)
   1.628 +		{
   1.629 +		test.Next(_L("Setup simulated kernel heap failure"));
   1.630 +		__KHEAP_SETFAIL(RAllocator::EDeterministic,100);
   1.631 +
   1.632 +		TBuf<80> text;
   1.633 +		text.Format(_L("Stressing for %d seconds..."),timeout);
   1.634 +		test.Next(text);
   1.635 +		timer.AfterTicks(timeoutStatus,timeoutTicks);
   1.636 +		StartSemaphore.Signal(KNumSlaveProcesses); // release slaves to start testing
   1.637 +		User::WaitForAnyRequest(); // wait for timeout or slave death via logon completion
   1.638 +
   1.639 +		pass = timeoutStatus.Int()==KErrNone; // timeout means slaves are still running OK
   1.640 +
   1.641 +		test.Next(_L("Check slaves still running"));
   1.642 +		for(i=0; i<KNumSlaveProcesses; i++)
   1.643 +			if(Slaves[i].ExitType()!=EExitPending)
   1.644 +				pass = false;
   1.645 +
   1.646 +		test.Next(_L("Clear kernel heap failure"));
   1.647 +		TUint kheapFails = __KHEAP_CHECKFAILURE;
   1.648 +		__KHEAP_RESET;
   1.649 +		test.Printf(_L("Number of simulated memory failures = %d\r\n"),kheapFails);
   1.650 +		}
   1.651 +
   1.652 +	test.Next(_L("Killing slave processes"));
   1.653 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.654 +		Slaves[i].Kill(0);
   1.655 +
   1.656 +	test.Next(_L("Assert test passed"));
   1.657 +	test(pass);
   1.658 +
   1.659 +	test.End();
   1.660 +
   1.661 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.662 +		Slaves[i].Close();
   1.663 +	for(i=0; i<KNumTestChunks; i++)
   1.664 +		Chunks[i].Close();
   1.665 +	timer.Close();
   1.666 +	for(i=0; i<KNumSlaveProcesses; i++)
   1.667 +		User::WaitForRequest(SlaveLogons[i]);
   1.668 +
   1.669 +	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0);
   1.670 +
   1.671 +	return KErrNone;
   1.672 +	}