os/kernelhwsrv/kerneltest/e32test/mmu/t_mmustress.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32test\mmu\t_mmustress.cpp
sl@0
    15
// Stress test for memory management services performed by the kernel's memory model.
sl@0
    16
// 
sl@0
    17
//
sl@0
    18
sl@0
    19
/**
sl@0
    20
 @file
sl@0
    21
*/
sl@0
    22
sl@0
    23
#define __E32TEST_EXTENSION__
sl@0
    24
#include <e32test.h>
sl@0
    25
#include "u32std.h"
sl@0
    26
#include <u32hal.h>
sl@0
    27
#include <e32svr.h>
sl@0
    28
#include <dptest.h>
sl@0
    29
#include <e32def.h>
sl@0
    30
#include <e32def_private.h>
sl@0
    31
#include "d_memorytest.h"
sl@0
    32
#include "..\defrag\d_pagemove.h"
sl@0
    33
sl@0
    34
TBool TRACE = 0;
sl@0
    35
sl@0
    36
LOCAL_D RTest test(_L("T_MMUSTRESS"));
sl@0
    37
sl@0
    38
TUint32 MemModelAttributes;
sl@0
    39
TUint32 MemModel;
sl@0
    40
TInt PageSize;
sl@0
    41
TInt PageMask;
sl@0
    42
sl@0
    43
#if !defined(__WINS__) && !defined(__X86__)
sl@0
    44
const TPtrC KMoveLddFileName=_L("D_PAGEMOVE.LDD");
sl@0
    45
RPageMove MoveLdd;
sl@0
    46
#endif
sl@0
    47
sl@0
    48
RMemoryTestLdd Ldd;
sl@0
    49
sl@0
    50
const TUint KNumTestChunks = 6;
sl@0
    51
RChunk Chunks[KNumTestChunks];
sl@0
    52
TInt Committed[KNumTestChunks] = {0}; // for each chunk, is the 'owned' region uncommited(0), commited(1) or mixed(-1)
sl@0
    53
class TNicePtr8 : public TPtr8 { public: TNicePtr8() : TPtr8(0,0) {} } ChunkPtr[KNumTestChunks];
sl@0
    54
sl@0
    55
const TUint KNumSlaveProcesses = 4;
sl@0
    56
RProcess Slaves[KNumSlaveProcesses];
sl@0
    57
TRequestStatus SlaveLogons[KNumSlaveProcesses];
sl@0
    58
TRequestStatus SlaveRendezvous[KNumSlaveProcesses];
sl@0
    59
sl@0
    60
TInt SlaveNumber = -1; // master process is slave -1
sl@0
    61
sl@0
    62
const TInt KLocalIpcBufferSize = 0x10000;
sl@0
    63
TUint8* LocalIpcBuffer = 0;
sl@0
    64
sl@0
    65
RSemaphore StartSemaphore;
sl@0
    66
sl@0
    67
//
sl@0
    68
// Random number generation
sl@0
    69
//
sl@0
    70
sl@0
    71
TUint32 RandomSeed;
sl@0
    72
sl@0
    73
TUint32 Random()
sl@0
    74
	{
sl@0
    75
	RandomSeed = RandomSeed*69069+1;
sl@0
    76
	return RandomSeed;
sl@0
    77
	}
sl@0
    78
sl@0
    79
TUint32 Random(TUint32 aRange)
sl@0
    80
	{
sl@0
    81
	return (TUint32)((TUint64(Random())*TUint64(aRange))>>32);
sl@0
    82
	}
sl@0
    83
sl@0
    84
void RandomInit(TUint32 aSeed)
sl@0
    85
	{
sl@0
    86
	RandomSeed = aSeed+(aSeed<<8)+(aSeed<<16)+(aSeed<<24);
sl@0
    87
	Random();
sl@0
    88
	Random();
sl@0
    89
	}
sl@0
    90
sl@0
    91
sl@0
    92
sl@0
    93
//
sl@0
    94
// Chunk utils
sl@0
    95
//
sl@0
    96
sl@0
    97
TBuf<KMaxKernelName> ChunkName(TInt aChunkNumber)
sl@0
    98
	{
sl@0
    99
	TBuf<KMaxKernelName> name;
sl@0
   100
	name.Format(_L("T_MMUSTRESS-Chunk%d"),aChunkNumber);
sl@0
   101
	return name;
sl@0
   102
	}
sl@0
   103
sl@0
   104
#ifdef __WINS__
sl@0
   105
TInt KChunkShift = 16;
sl@0
   106
#elif defined(__X86__)
sl@0
   107
TInt KChunkShift = 22;
sl@0
   108
#else
sl@0
   109
TInt KChunkShift = 20;
sl@0
   110
#endif
sl@0
   111
sl@0
   112
TInt ChunkSize(TInt aChunkNumber)
sl@0
   113
	{
sl@0
   114
	// biggest chunk (number 0) is big enough for each slave to own a region which is
sl@0
   115
	// 2 page tables ('chunks') in size...
sl@0
   116
	return (2*KNumSlaveProcesses)<<(KChunkShift-aChunkNumber);
sl@0
   117
	}
sl@0
   118
sl@0
   119
// check smallest chunk is less than 'chunk' size...
sl@0
   120
__ASSERT_COMPILE((2*KNumSlaveProcesses>>(KNumTestChunks-1))==0);
sl@0
   121
sl@0
   122
sl@0
   123
/* Memory region 'owned' by this slave process */
sl@0
   124
void ChunkOwnedRegion(TInt aChunkNumber,TInt& aOffset,TInt& aSize)
sl@0
   125
	{
sl@0
   126
	TInt size = ChunkSize(aChunkNumber)/KNumSlaveProcesses;
sl@0
   127
	aSize = size;
sl@0
   128
	aOffset = SlaveNumber*size;
sl@0
   129
	test_Equal(0,size&PageMask);
sl@0
   130
	}
sl@0
   131
sl@0
   132
void ChunkMarkRegion(TInt aChunkNumber,TInt aOffset,TInt aSize)
sl@0
   133
	{
sl@0
   134
	TInt pageSize = PageSize;
sl@0
   135
	TUint32 mark = aOffset|aChunkNumber|(SlaveNumber<<4);
sl@0
   136
	TUint8* ptr = Chunks[aChunkNumber].Base()+aOffset;
sl@0
   137
	TUint8* ptrEnd = ptr+aSize;
sl@0
   138
	while(ptr<ptrEnd)
sl@0
   139
		{
sl@0
   140
		((TUint32*)ptr)[0] = mark;
sl@0
   141
		((TUint32*)ptr)[1] = ~mark;
sl@0
   142
		mark += pageSize;
sl@0
   143
		ptr += pageSize;
sl@0
   144
		}
sl@0
   145
	}
sl@0
   146
sl@0
   147
void ChunkCheckRegion(TInt aChunkNumber,TInt aOffset,TInt aSize)
sl@0
   148
	{
sl@0
   149
	TInt pageSize = PageSize;
sl@0
   150
	TUint32 mark = aOffset|aChunkNumber|(SlaveNumber<<4);
sl@0
   151
	TUint8* ptr = Chunks[aChunkNumber].Base()+aOffset;
sl@0
   152
	TUint8* ptrEnd = ptr+aSize;
sl@0
   153
	while(ptr<ptrEnd)
sl@0
   154
		{
sl@0
   155
		test_Equal(mark,((TUint32*)ptr)[0]);
sl@0
   156
		test_Equal(~mark,((TUint32*)ptr)[1]);
sl@0
   157
		mark += pageSize;
sl@0
   158
		ptr += pageSize;
sl@0
   159
		}
sl@0
   160
	}
sl@0
   161
sl@0
   162
TInt ChunkOpen(TInt aChunkNumber)
sl@0
   163
	{
sl@0
   164
	RChunk& chunk = Chunks[aChunkNumber];
sl@0
   165
	if(chunk.Handle()!=0)
sl@0
   166
		return KErrNone;
sl@0
   167
sl@0
   168
	if(TRACE) RDebug::Printf("%d %d Open",SlaveNumber,aChunkNumber);
sl@0
   169
	TInt r = chunk.OpenGlobal(ChunkName(aChunkNumber),false);
sl@0
   170
	if(r!=KErrNoMemory)
sl@0
   171
		test_KErrNone(r);
sl@0
   172
	return r;
sl@0
   173
	}
sl@0
   174
sl@0
   175
//
sl@0
   176
// Server utils
sl@0
   177
//
sl@0
   178
sl@0
   179
TBuf<KMaxKernelName> ServerName(TInt aSlaveNumber)
sl@0
   180
	{
sl@0
   181
	TBuf<KMaxKernelName> name;
sl@0
   182
	name.Format(_L("T_MMUSTRESS-Server%d"),aSlaveNumber);
sl@0
   183
	return name;
sl@0
   184
	}
sl@0
   185
sl@0
   186
RServer2 Server;
sl@0
   187
RMessage2 ServerMessage;
sl@0
   188
TRequestStatus ServerStatus;
sl@0
   189
sl@0
   190
class RTestSession : public RSessionBase
sl@0
   191
	{
sl@0
   192
public:
sl@0
   193
	TInt Connect(TInt aServerNumber)
sl@0
   194
		{
sl@0
   195
		return CreateSession(ServerName(aServerNumber),TVersion(),1,EIpcSession_Unsharable,0,&iStatus);
sl@0
   196
		}
sl@0
   197
	TInt Send(TInt aChunkNumber)
sl@0
   198
		{
sl@0
   199
		return RSessionBase::Send(0,TIpcArgs(SlaveNumber,aChunkNumber,&ChunkPtr[aChunkNumber]));
sl@0
   200
		}
sl@0
   201
	TRequestStatus iStatus;
sl@0
   202
	};
sl@0
   203
RTestSession Sessions[KNumSlaveProcesses];
sl@0
   204
sl@0
   205
sl@0
   206
//
sl@0
   207
//
sl@0
   208
//
sl@0
   209
sl@0
   210
void SlaveInit()
sl@0
   211
	{
sl@0
   212
	RDebug::Printf("Slave %d initialising",SlaveNumber);
sl@0
   213
sl@0
   214
	TBuf<KMaxKernelName> name;
sl@0
   215
	name.Format(_L("T_MMUSTRESS-Slave%d"),SlaveNumber);
sl@0
   216
	User::RenameThread(name);
sl@0
   217
sl@0
   218
	test_KErrNone(StartSemaphore.Open(2));
sl@0
   219
	TInt r;
sl@0
   220
#if !defined(__WINS__) && !defined(__X86__)
sl@0
   221
	// Move ldd may not be in the ROM so needs to be loaded.
sl@0
   222
	r=User::LoadLogicalDevice(KMoveLddFileName);
sl@0
   223
	test_Value(r, r==KErrNone || r==KErrAlreadyExists);
sl@0
   224
	test_KErrNone(MoveLdd.Open());
sl@0
   225
#endif
sl@0
   226
sl@0
   227
	test_KErrNone(Ldd.Open());
sl@0
   228
	test_KErrNone(Ldd.CreateVirtualPinObject());
sl@0
   229
sl@0
   230
	LocalIpcBuffer = (TUint8*)User::Alloc(KLocalIpcBufferSize);
sl@0
   231
	test(LocalIpcBuffer!=0);
sl@0
   232
sl@0
   233
	test_KErrNone(Server.CreateGlobal(ServerName(SlaveNumber)));
sl@0
   234
sl@0
   235
	TUint i;
sl@0
   236
sl@0
   237
	// create sessions with other slaves...
sl@0
   238
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   239
		{
sl@0
   240
		for(;;)
sl@0
   241
			{
sl@0
   242
			r = Sessions[i].Connect(i);
sl@0
   243
//			RDebug::Printf("%d Session %d = %d,%d",SlaveNumber,i,r,Sessions[i].iStatus.Int());
sl@0
   244
			if(r==KErrNotFound)
sl@0
   245
				{
sl@0
   246
				// give other slaves time to create their servers...
sl@0
   247
				User::After(10000);
sl@0
   248
				continue;
sl@0
   249
				}
sl@0
   250
			test_KErrNone(r);
sl@0
   251
			break;
sl@0
   252
			}
sl@0
   253
		}
sl@0
   254
sl@0
   255
	// process session connect messages...
sl@0
   256
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   257
		{
sl@0
   258
		RMessage2 m;
sl@0
   259
//		RDebug::Printf("%d Server waiting for connect message",SlaveNumber);
sl@0
   260
		Server.Receive(m);
sl@0
   261
		test_Equal(RMessage2::EConnect,m.Function())
sl@0
   262
		m.Complete(KErrNone);
sl@0
   263
		}
sl@0
   264
sl@0
   265
	// wait for our session connections...
sl@0
   266
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   267
		{
sl@0
   268
//		RDebug::Printf("%d Session wait %d",SlaveNumber,i);
sl@0
   269
		User::WaitForRequest(Sessions[i].iStatus);
sl@0
   270
		}
sl@0
   271
sl@0
   272
	// prime server for receiving mesages...
sl@0
   273
	Server.Receive(ServerMessage,ServerStatus);
sl@0
   274
sl@0
   275
	// synchronise with other processes...
sl@0
   276
	RDebug::Printf("Slave %d waiting for trigger",SlaveNumber);
sl@0
   277
	RProcess::Rendezvous(KErrNone);
sl@0
   278
	StartSemaphore.Wait();
sl@0
   279
	RDebug::Printf("Slave %d started",SlaveNumber);
sl@0
   280
	}
sl@0
   281
sl@0
   282
sl@0
   283
sl@0
   284
//
sl@0
   285
// Test by random operations...
sl@0
   286
//
sl@0
   287
sl@0
   288
void DoTest()
sl@0
   289
	{
sl@0
   290
	RandomInit(SlaveNumber);
sl@0
   291
	TInt r;
sl@0
   292
	for(;;)
sl@0
   293
		{
sl@0
   294
		// select random chunk...
sl@0
   295
		TInt chunkNumber = Random(KNumTestChunks);
sl@0
   296
		RChunk& chunk = Chunks[chunkNumber];
sl@0
   297
sl@0
   298
		// get the region of this chunk which this process 'owns'...
sl@0
   299
		TInt offset;
sl@0
   300
		TInt size;
sl@0
   301
		ChunkOwnedRegion(chunkNumber,offset,size);
sl@0
   302
sl@0
   303
		// calculate a random region in the owned part...
sl@0
   304
		TInt randomOffset = offset+(Random(size)&~PageMask);
sl@0
   305
		TInt randomSize = (Random(size-(randomOffset-offset))+PageMask)&~PageMask;
sl@0
   306
		if(!randomSize)
sl@0
   307
			continue; // try again
sl@0
   308
sl@0
   309
		// pick a random slave...
sl@0
   310
		TInt randomSlave = Random(KNumSlaveProcesses);
sl@0
   311
sl@0
   312
		// open chunk if it isn't already...
sl@0
   313
		r = ChunkOpen(chunkNumber);
sl@0
   314
		if(r==KErrNoMemory)
sl@0
   315
			continue; // can't do anything with chunk if we can't open it
sl@0
   316
sl@0
   317
		// check our contents of chunk...
sl@0
   318
		if(Committed[chunkNumber]==1)
sl@0
   319
			{
sl@0
   320
			if(TRACE) RDebug::Printf("%d %d Check %08x+%08x",SlaveNumber,chunkNumber,offset,size);
sl@0
   321
			ChunkCheckRegion(chunkNumber,offset,size);
sl@0
   322
			}
sl@0
   323
sl@0
   324
		// perform random operation...
sl@0
   325
		switch(Random(12))
sl@0
   326
			{
sl@0
   327
		case 0:
sl@0
   328
		case 1:
sl@0
   329
			// close chunk...
sl@0
   330
			if(TRACE) RDebug::Printf("%d %d Close",SlaveNumber,chunkNumber);
sl@0
   331
			chunk.Close();
sl@0
   332
			break;
sl@0
   333
sl@0
   334
		case 2:
sl@0
   335
			// commit all...
sl@0
   336
			if(TRACE) RDebug::Printf("%d %d Commit all %08x+%08x",SlaveNumber,chunkNumber,offset,size);
sl@0
   337
			if(Committed[chunkNumber]!=0)
sl@0
   338
				{
sl@0
   339
				r = chunk.Decommit(offset,size);
sl@0
   340
				test_KErrNone(r);
sl@0
   341
				Committed[chunkNumber] = 0;
sl@0
   342
				}
sl@0
   343
			r = chunk.Commit(offset,size);
sl@0
   344
			if(r!=KErrNoMemory)
sl@0
   345
				{
sl@0
   346
				test_KErrNone(r);
sl@0
   347
				Committed[chunkNumber] = 1;
sl@0
   348
				ChunkMarkRegion(chunkNumber,offset,size);
sl@0
   349
				}
sl@0
   350
			break;
sl@0
   351
sl@0
   352
		case 3:
sl@0
   353
			// decommit all...
sl@0
   354
			if(TRACE) RDebug::Printf("%d %d Decommit all %08x+%08x",SlaveNumber,chunkNumber,offset,size);
sl@0
   355
			r = chunk.Decommit(offset,size);
sl@0
   356
			test_KErrNone(r);
sl@0
   357
			Committed[chunkNumber] = 0;
sl@0
   358
			break;
sl@0
   359
sl@0
   360
		case 4:
sl@0
   361
		case 5:
sl@0
   362
			// commit random...
sl@0
   363
			if(TRACE) RDebug::Printf("%d %d Commit %08x+%08x",SlaveNumber,chunkNumber,randomOffset,randomSize);
sl@0
   364
			r = chunk.Commit(randomOffset,randomSize);
sl@0
   365
			if(r!=KErrNoMemory)
sl@0
   366
				{
sl@0
   367
				if(Committed[chunkNumber]==0)
sl@0
   368
					{
sl@0
   369
					test_KErrNone(r);
sl@0
   370
					Committed[chunkNumber] = -1;
sl@0
   371
					}
sl@0
   372
				else if(Committed[chunkNumber]==1)
sl@0
   373
					{
sl@0
   374
					test_Equal(KErrAlreadyExists,r);
sl@0
   375
					}
sl@0
   376
				else
sl@0
   377
					{
sl@0
   378
					if(r!=KErrAlreadyExists)
sl@0
   379
						test_KErrNone(r);
sl@0
   380
					}
sl@0
   381
				}
sl@0
   382
			break;
sl@0
   383
sl@0
   384
		case 6:
sl@0
   385
		case 7:
sl@0
   386
			// decommit random...
sl@0
   387
			if(TRACE) RDebug::Printf("%d %d Decommit %08x+%08x",SlaveNumber,chunkNumber,randomOffset,randomSize);
sl@0
   388
			r = chunk.Decommit(randomOffset,randomSize);
sl@0
   389
			test_KErrNone(r);
sl@0
   390
			if(Committed[chunkNumber]==1)
sl@0
   391
				Committed[chunkNumber] = -1;
sl@0
   392
			break;
sl@0
   393
sl@0
   394
		case 8:
sl@0
   395
			if(TRACE) RDebug::Printf("%d %d IPC Send->%d",SlaveNumber,chunkNumber,randomSlave);
sl@0
   396
//			ChunkPtr[chunkNumber].Set(chunk.Base(),ChunkSize(chunkNumber),ChunkSize(chunkNumber));
sl@0
   397
			ChunkPtr[chunkNumber].Set(chunk.Base()+offset,size,size);
sl@0
   398
			Sessions[randomSlave].Send(chunkNumber);
sl@0
   399
			break;
sl@0
   400
sl@0
   401
		case 9:
sl@0
   402
			// process IPC messages...
sl@0
   403
			if(ServerStatus.Int()==KRequestPending)
sl@0
   404
				continue;
sl@0
   405
			User::WaitForRequest(ServerStatus);
sl@0
   406
sl@0
   407
			{
sl@0
   408
			TInt sourceSlave = ServerMessage.Int0();
sl@0
   409
			chunkNumber = ServerMessage.Int1();
sl@0
   410
			if(TRACE) RDebug::Printf("%d %d IPC Receive<-%d",SlaveNumber,chunkNumber,sourceSlave);
sl@0
   411
			test_Equal(0,ServerMessage.Function());
sl@0
   412
sl@0
   413
			// get local descriptor for owned region in chunk...
sl@0
   414
			size = ServerMessage.GetDesMaxLength(2);
sl@0
   415
			test_NotNegative(size);
sl@0
   416
			if(size>KLocalIpcBufferSize)
sl@0
   417
				size = KLocalIpcBufferSize;
sl@0
   418
			TPtr8 local(LocalIpcBuffer,size,size);
sl@0
   419
sl@0
   420
//			if(Random(2))
sl@0
   421
				{
sl@0
   422
				// IPC read from other slave...
sl@0
   423
				if(TRACE) RDebug::Printf("%d %d IPC Read<-%d",SlaveNumber,chunkNumber,sourceSlave);
sl@0
   424
				TInt panicTrace = Ldd.SetPanicTrace(EFalse);
sl@0
   425
				r = ServerMessage.Read(2,local);
sl@0
   426
				Ldd.SetPanicTrace(panicTrace);
sl@0
   427
				if(r!=KErrBadDescriptor)
sl@0
   428
					test_KErrNone(r);
sl@0
   429
				}
sl@0
   430
//			else
sl@0
   431
//				{
sl@0
   432
//				// IPC write to other slave...
sl@0
   433
//				if(TRACE) RDebug::Printf("%d %d IPC Write->%d",SlaveNumber,chunkNumber,sourceSlave);
sl@0
   434
//				r = ServerMessage.Write(2,local,offset);
sl@0
   435
//				if(r!=KErrBadDescriptor)
sl@0
   436
//					test_KErrNone(r);
sl@0
   437
//				if(Committed[chunkNumber]==1)
sl@0
   438
//					ChunkMarkRegion(chunkNumber,offset,size);
sl@0
   439
//				}
sl@0
   440
			}
sl@0
   441
sl@0
   442
			ServerMessage.Complete(KErrNone);
sl@0
   443
			Server.Receive(ServerMessage,ServerStatus);
sl@0
   444
			break;
sl@0
   445
sl@0
   446
		case 10:
sl@0
   447
		case 11:
sl@0
   448
			// pin memory...
sl@0
   449
			{
sl@0
   450
			test_KErrNone(Ldd.UnpinVirtualMemory());
sl@0
   451
			for(TInt tries=10; tries>0; --tries)
sl@0
   452
				{
sl@0
   453
				TInt chunkSize = ChunkSize(chunkNumber);
sl@0
   454
				offset = Random(chunkSize);
sl@0
   455
				TInt maxSize = chunkSize-offset;
sl@0
   456
				if(maxSize>0x1000)
sl@0
   457
					maxSize = 0x1000;
sl@0
   458
				size = Random(maxSize);
sl@0
   459
				r = Ldd.PinVirtualMemory((TLinAddr)chunk.Base()+offset, size);
sl@0
   460
				if(r!=KErrNotFound && r!=KErrNoMemory)
sl@0
   461
					{
sl@0
   462
					test_KErrNone(r);
sl@0
   463
					break;
sl@0
   464
					}
sl@0
   465
				}
sl@0
   466
			}
sl@0
   467
			break;
sl@0
   468
		case 12:
sl@0
   469
		case 13:
sl@0
   470
			// Move any page in the chunk, not just the owned region.
sl@0
   471
			{
sl@0
   472
#if !defined(__WINS__) && !defined(__X86__)
sl@0
   473
			for(TInt tries=10; tries>0; --tries)
sl@0
   474
				{
sl@0
   475
				TInt chunkSize = ChunkSize(chunkNumber);
sl@0
   476
				offset = Random(chunkSize);
sl@0
   477
				MoveLdd.TryMovingUserPage((TAny*)(chunk.Base()+offset), ETrue);
sl@0
   478
				// Allow the move to fail for any reason as the page of the chunk
sl@0
   479
				// may or may not be currently committed, pinned, or accessed.
sl@0
   480
				}
sl@0
   481
#endif
sl@0
   482
			}
sl@0
   483
			break;
sl@0
   484
		default:
sl@0
   485
			test(false); // can't happen
sl@0
   486
			break;
sl@0
   487
			}
sl@0
   488
		}
sl@0
   489
	}
sl@0
   490
sl@0
   491
sl@0
   492
sl@0
   493
TInt E32Main()
sl@0
   494
	{
sl@0
   495
	// get system info...
sl@0
   496
	MemModelAttributes = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
sl@0
   497
	MemModel = MemModelAttributes&EMemModelTypeMask;
sl@0
   498
	UserHal::PageSizeInBytes(PageSize);
sl@0
   499
	PageMask = PageSize-1;
sl@0
   500
sl@0
   501
	// see if we are a slave process...
sl@0
   502
	if(User::GetTIntParameter(1,SlaveNumber)==KErrNone)
sl@0
   503
		{
sl@0
   504
		// do testing...
sl@0
   505
		SlaveInit();
sl@0
   506
		DoTest();
sl@0
   507
		return KErrGeneral; // shouldn't have returned from testing
sl@0
   508
		}
sl@0
   509
sl@0
   510
	// master process...
sl@0
   511
	TBool pass = true; // final test result
sl@0
   512
	test.Title();
sl@0
   513
	if((MemModelAttributes&EMemModelAttrVA)==false)
sl@0
   514
		{
sl@0
   515
		test.Start(_L("TESTS NOT RUN - Not relevent for the memory model"));
sl@0
   516
		test.End();
sl@0
   517
		return KErrNone;
sl@0
   518
		}
sl@0
   519
sl@0
   520
	// get time to run tests for...
sl@0
   521
	TInt timeout = 10; // time in seconds
sl@0
   522
	TInt cmdLineLen = User::CommandLineLength();
sl@0
   523
	if(cmdLineLen)
sl@0
   524
		{
sl@0
   525
		// get timeout value from command line
sl@0
   526
		RBuf cmdLine;
sl@0
   527
		test_KErrNone(cmdLine.Create(cmdLineLen));
sl@0
   528
		User::CommandLine(cmdLine);
sl@0
   529
		test_KErrNone(TLex(cmdLine).Val(timeout));
sl@0
   530
		if(timeout==0)
sl@0
   531
			timeout = KMaxTInt;
sl@0
   532
		}
sl@0
   533
	TTimeIntervalMicroSeconds32 tickTime;
sl@0
   534
	test_KErrNone(UserHal::TickPeriod(tickTime));
sl@0
   535
	TInt ticksPerSecond = 1000000/tickTime.Int();
sl@0
   536
	TInt timeoutTicks;
sl@0
   537
	if(timeout<KMaxTInt/ticksPerSecond)
sl@0
   538
		timeoutTicks = timeout*ticksPerSecond;
sl@0
   539
	else
sl@0
   540
		{
sl@0
   541
		timeoutTicks = KMaxTInt;
sl@0
   542
		timeout = timeoutTicks/ticksPerSecond;
sl@0
   543
		}
sl@0
   544
sl@0
   545
	// master process runs at higher priority than slaves so it can timeout and kill them...
sl@0
   546
	RThread().SetPriority(EPriorityMore);
sl@0
   547
sl@0
   548
	test.Start(_L("Creating test chunks"));
sl@0
   549
	TUint i;
sl@0
   550
	for(i=0; i<KNumTestChunks; i++)
sl@0
   551
		{
sl@0
   552
		test.Printf(_L("Size %dkB\r\n"),ChunkSize(i)>>10);
sl@0
   553
		test_KErrNone(Chunks[i].CreateDisconnectedGlobal(ChunkName(i),0,0,ChunkSize(i)));
sl@0
   554
		}
sl@0
   555
sl@0
   556
	test.Next(_L("Spawning slave processes"));
sl@0
   557
	test_KErrNone(StartSemaphore.CreateGlobal(KNullDesC,0));
sl@0
   558
	TFileName processFile(RProcess().FileName());
sl@0
   559
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   560
		{
sl@0
   561
		test.Printf(_L("Slave %d\r\n"),i);
sl@0
   562
		RProcess& slave = Slaves[i];
sl@0
   563
		test_KErrNone(slave.Create(processFile,KNullDesC));
sl@0
   564
		test_KErrNone(slave.SetParameter(1,i));
sl@0
   565
		test_KErrNone(slave.SetParameter(2,StartSemaphore));
sl@0
   566
		slave.Logon(SlaveLogons[i]);
sl@0
   567
		test_Equal(KRequestPending,SlaveLogons[i].Int());
sl@0
   568
		slave.Rendezvous(SlaveRendezvous[i]);
sl@0
   569
		test_Equal(KRequestPending,SlaveRendezvous[i].Int());
sl@0
   570
		}
sl@0
   571
sl@0
   572
	test.Next(_L("Create timer"));
sl@0
   573
	RTimer timer;
sl@0
   574
	test_KErrNone(timer.CreateLocal());
sl@0
   575
sl@0
   576
	test.Next(_L("Resuming slave processes"));
sl@0
   577
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   578
		Slaves[i].Resume();
sl@0
   579
sl@0
   580
	// this test must now take care not to die (e.g. panic due to assert fail)
sl@0
   581
	// until it has killed the slave processes
sl@0
   582
sl@0
   583
	test.Next(_L("Change paging cache size"));
sl@0
   584
	TUint cacheOriginalMin = 0;
sl@0
   585
	TUint cacheOriginalMax = 0;
sl@0
   586
	TUint cacheCurrentSize = 0;
sl@0
   587
	DPTest::CacheSize(cacheOriginalMin, cacheOriginalMax, cacheCurrentSize);
sl@0
   588
	DPTest::SetCacheSize(1, 2*ChunkSize(0)); // big enough for all the test chunks
sl@0
   589
sl@0
   590
	test.Next(_L("Wait for slaves to initialise"));
sl@0
   591
	TRequestStatus timeoutStatus;
sl@0
   592
	timer.After(timeoutStatus,10*1000000); // allow short time for slaves to initialise
sl@0
   593
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   594
		{
sl@0
   595
		User::WaitForAnyRequest(); // wait for a rendexvous
sl@0
   596
		if(timeoutStatus.Int()!=KRequestPending)
sl@0
   597
			{
sl@0
   598
			test.Printf(_L("Timeout waiting for slaves to initialise\r\n"));
sl@0
   599
			pass = false;
sl@0
   600
			break;
sl@0
   601
			}
sl@0
   602
		}
sl@0
   603
sl@0
   604
	test.Next(_L("Restore paging cache size"));
sl@0
   605
	DPTest::SetCacheSize(cacheOriginalMin, cacheOriginalMax);
sl@0
   606
sl@0
   607
	if(pass)
sl@0
   608
		{
sl@0
   609
		timer.Cancel();
sl@0
   610
		User::WaitForAnyRequest(); // swallow timer signal
sl@0
   611
sl@0
   612
		test.Next(_L("Check slaves are ready"));
sl@0
   613
		for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   614
			{
sl@0
   615
			if(SlaveRendezvous[i].Int()!=KErrNone || Slaves[i].ExitType()!=EExitPending)
sl@0
   616
				{
sl@0
   617
				test.Printf(_L("Slaves not ready or died!\r\n"));
sl@0
   618
				pass = false;
sl@0
   619
				break;
sl@0
   620
				}
sl@0
   621
			}
sl@0
   622
		}
sl@0
   623
sl@0
   624
	if(pass)
sl@0
   625
		{
sl@0
   626
		test.Next(_L("Setup simulated kernel heap failure"));
sl@0
   627
		__KHEAP_SETFAIL(RAllocator::EDeterministic,100);
sl@0
   628
sl@0
   629
		TBuf<80> text;
sl@0
   630
		text.Format(_L("Stressing for %d seconds..."),timeout);
sl@0
   631
		test.Next(text);
sl@0
   632
		timer.AfterTicks(timeoutStatus,timeoutTicks);
sl@0
   633
		StartSemaphore.Signal(KNumSlaveProcesses); // release slaves to start testing
sl@0
   634
		User::WaitForAnyRequest(); // wait for timeout or slave death via logon completion
sl@0
   635
sl@0
   636
		pass = timeoutStatus.Int()==KErrNone; // timeout means slaves are still running OK
sl@0
   637
sl@0
   638
		test.Next(_L("Check slaves still running"));
sl@0
   639
		for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   640
			if(Slaves[i].ExitType()!=EExitPending)
sl@0
   641
				pass = false;
sl@0
   642
sl@0
   643
		test.Next(_L("Clear kernel heap failure"));
sl@0
   644
		TUint kheapFails = __KHEAP_CHECKFAILURE;
sl@0
   645
		__KHEAP_RESET;
sl@0
   646
		test.Printf(_L("Number of simulated memory failures = %d\r\n"),kheapFails);
sl@0
   647
		}
sl@0
   648
sl@0
   649
	test.Next(_L("Killing slave processes"));
sl@0
   650
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   651
		Slaves[i].Kill(0);
sl@0
   652
sl@0
   653
	test.Next(_L("Assert test passed"));
sl@0
   654
	test(pass);
sl@0
   655
sl@0
   656
	test.End();
sl@0
   657
sl@0
   658
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   659
		Slaves[i].Close();
sl@0
   660
	for(i=0; i<KNumTestChunks; i++)
sl@0
   661
		Chunks[i].Close();
sl@0
   662
	timer.Close();
sl@0
   663
	for(i=0; i<KNumSlaveProcesses; i++)
sl@0
   664
		User::WaitForRequest(SlaveLogons[i]);
sl@0
   665
sl@0
   666
	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0);
sl@0
   667
sl@0
   668
	return KErrNone;
sl@0
   669
	}