os/kernelhwsrv/kerneltest/e32test/mmu/t_alias_remove.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) 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_alias_remove.cpp
sl@0
    15
// Overview:
sl@0
    16
// Test interactions when free memory being aliases.
sl@0
    17
// Details:
sl@0
    18
// Create 3 mappings to one chunk one that owns the chunk, one to map it again another process 
sl@0
    19
// and another alias mapping.
sl@0
    20
// Then while the alias mapping is accessing the chunk close the second mapping.
sl@0
    21
// Platforms/Drives/Compatibility:
sl@0
    22
// All.
sl@0
    23
// Assumptions/Requirement/Pre-requisites:
sl@0
    24
// Failures and causes:
sl@0
    25
// Base Port information:
sl@0
    26
// 
sl@0
    27
//
sl@0
    28
sl@0
    29
#define __E32TEST_EXTENSION__
sl@0
    30
#include <e32test.h>
sl@0
    31
#include <e32hal.h>
sl@0
    32
#include <e32svr.h>
sl@0
    33
#include "..\defrag\d_pagemove.h"
sl@0
    34
sl@0
    35
const TPtrC KAliasProcessName = _L("T_ALIAS_REMOVE");
sl@0
    36
const TPtrC KAliasChunkName = _L("AliasChunk");
sl@0
    37
const TPtrC KAliasServerName = _L("AliasServer");
sl@0
    38
const TPtrC KMasterServerName = _L("MasterServer");
sl@0
    39
sl@0
    40
RBuf ChunkName;
sl@0
    41
RBuf MasterServerName;
sl@0
    42
RBuf AliasServerName;
sl@0
    43
sl@0
    44
RTest test(KAliasProcessName);
sl@0
    45
sl@0
    46
//#define ENABLE_PRINTFS
sl@0
    47
#ifndef __MSVC6__	// VC6 can't cope with variable arguments in macros.
sl@0
    48
sl@0
    49
#define T_PRINTF(x...) test.Printf(x)
sl@0
    50
#define D_PRINTF(x...) RDebug::Printf(x)
sl@0
    51
#ifdef ENABLE_PRINTFS
sl@0
    52
#define PRINTF(x) x
sl@0
    53
#else
sl@0
    54
#define PRINTF(x)
sl@0
    55
#endif // ENABLE_PRINTFS
sl@0
    56
sl@0
    57
#else
sl@0
    58
#define PRINTF(x)
sl@0
    59
#endif	// __MSCV6__
sl@0
    60
sl@0
    61
enum TSlaveMsgType
sl@0
    62
	{
sl@0
    63
	ESlaveConnect = -1,
sl@0
    64
	ESlaveDisconnect = -2,
sl@0
    65
	ESlaveReadChunk = 0,
sl@0
    66
	ESlaveClosedChunk = 1,
sl@0
    67
	};
sl@0
    68
sl@0
    69
sl@0
    70
struct SThreadData 
sl@0
    71
	{
sl@0
    72
	TUint8 iFillValue;
sl@0
    73
	TUint iChunkSize;
sl@0
    74
	RThread* iMasterThread;
sl@0
    75
	TUint iProcessId;
sl@0
    76
	};
sl@0
    77
sl@0
    78
sl@0
    79
class RAliasSession : public RSessionBase
sl@0
    80
	{
sl@0
    81
public:
sl@0
    82
	TInt CreateSession(const TDesC& aServerName, TInt aMsgSlots) 
sl@0
    83
		{ 
sl@0
    84
		return RSessionBase::CreateSession(aServerName,User::Version(),aMsgSlots);
sl@0
    85
		}
sl@0
    86
	TInt PublicSendReceive(TInt aFunction, const TIpcArgs &aPtr)
sl@0
    87
		{
sl@0
    88
		return (SendReceive(aFunction, aPtr));
sl@0
    89
		}
sl@0
    90
	TInt PublicSend(TInt aFunction, const TIpcArgs &aPtr)
sl@0
    91
		{
sl@0
    92
		return (Send(aFunction, aPtr));
sl@0
    93
		}
sl@0
    94
	};
sl@0
    95
sl@0
    96
sl@0
    97
TInt SlaveProcess(TUint aProcessId, TUint aFillValue)
sl@0
    98
	{		
sl@0
    99
	// Connect to the master server to indicate that we're ready to receive ipc messages.
sl@0
   100
	RAliasSession masterSession;
sl@0
   101
	test_KErrNone(masterSession.CreateSession(MasterServerName, 1));
sl@0
   102
sl@0
   103
	PRINTF(T_PRINTF(_L("Process ID %d Slave open chunk\n"), aProcessId));
sl@0
   104
	// Open the global chunk.
sl@0
   105
	RChunk chunk;
sl@0
   106
	TInt r = chunk.OpenGlobal(ChunkName, ETrue);
sl@0
   107
	test_KErrNone(r);
sl@0
   108
sl@0
   109
	// Connect to alias server.
sl@0
   110
	PRINTF(T_PRINTF(_L("Process ID %d Slave connect to alias server\n"), aProcessId));
sl@0
   111
	RAliasSession aliasSession;
sl@0
   112
	test_KErrNone(aliasSession.CreateSession(AliasServerName, 1));
sl@0
   113
sl@0
   114
	PRINTF(T_PRINTF(_L("Process ID %d Slave send data to alias server\n"), aProcessId));
sl@0
   115
	TPtr8 arg0(chunk.Base(), chunk.Size(), chunk.Size());
sl@0
   116
	r = aliasSession.PublicSend(ESlaveReadChunk, TIpcArgs(&arg0));
sl@0
   117
	test_KErrNone(r);
sl@0
   118
	
sl@0
   119
	// Close the chunk removing its mapping before the server has read it.
sl@0
   120
	chunk.Close();
sl@0
   121
	PRINTF(T_PRINTF(_L("Process ID %d Slave closed chunk\n"), aProcessId));
sl@0
   122
sl@0
   123
	r = masterSession.PublicSendReceive(ESlaveClosedChunk, TIpcArgs());
sl@0
   124
	test_KErrNone(r);
sl@0
   125
	aliasSession.Close();
sl@0
   126
	masterSession.Close();
sl@0
   127
	return KErrNone;
sl@0
   128
	}
sl@0
   129
sl@0
   130
sl@0
   131
TInt ChunkReadThread(TAny* aThreadData)
sl@0
   132
	{
sl@0
   133
	SThreadData* threadData =  (SThreadData*)aThreadData;
sl@0
   134
	RServer2 aliasServer;
sl@0
   135
	TInt r = aliasServer.CreateGlobal(AliasServerName);
sl@0
   136
	if (r != KErrNone)
sl@0
   137
		{
sl@0
   138
		RDebug::Printf("Process ID %d Error creating alias server r=%d", threadData->iProcessId, r);
sl@0
   139
		return r;
sl@0
   140
		}
sl@0
   141
	// Connect to the master server to indicate that we're ready to receive ipc messages.
sl@0
   142
	RAliasSession masterSession;
sl@0
   143
	test_KErrNone(masterSession.CreateSession(MasterServerName, 1));
sl@0
   144
sl@0
   145
	PRINTF(D_PRINTF("Process ID %d Alias wait for slave connection", threadData->iProcessId));
sl@0
   146
	RMessage2 aliasMessage;
sl@0
   147
	// Read and complete the connect message from the slave.
sl@0
   148
	aliasServer.Receive(aliasMessage);
sl@0
   149
	test_Equal(ESlaveConnect, aliasMessage.Function());
sl@0
   150
	aliasMessage.Complete(KErrNone);
sl@0
   151
sl@0
   152
	// Read the data of the remote chunk.
sl@0
   153
	PRINTF(D_PRINTF("Process ID %d Alias read chunk data", threadData->iProcessId));
sl@0
   154
	HBufC8* argTmp = HBufC8::New(threadData->iChunkSize);
sl@0
   155
	test_NotNull(argTmp);
sl@0
   156
	RBuf8 argBuf(argTmp);
sl@0
   157
	aliasServer.Receive(aliasMessage);
sl@0
   158
	test_Equal(ESlaveReadChunk, aliasMessage.Function());
sl@0
   159
	r = aliasMessage.Read(0, argBuf);
sl@0
   160
	if (r == KErrNone)
sl@0
   161
		{// Successfully read the chunk so verify it.
sl@0
   162
		aliasMessage.Complete(KErrNone);
sl@0
   163
sl@0
   164
		PRINTF(D_PRINTF("Process ID %d Alias verify chunk data", threadData->iProcessId));
sl@0
   165
		const TUint8* bufPtr = argBuf.Ptr();
sl@0
   166
		const TUint8* bufEnd = bufPtr + threadData->iChunkSize;
sl@0
   167
		for (; bufPtr < bufEnd; bufPtr++)
sl@0
   168
			{
sl@0
   169
			if (*bufPtr != threadData->iFillValue)
sl@0
   170
				{
sl@0
   171
				RDebug::Printf("Process ID %d Read incorrect data exp 0x%x got 0x%x", 
sl@0
   172
								threadData->iProcessId, threadData->iFillValue, *bufPtr);
sl@0
   173
				r = *bufPtr;
sl@0
   174
				break;
sl@0
   175
				}
sl@0
   176
			}
sl@0
   177
		}
sl@0
   178
	else
sl@0
   179
		{
sl@0
   180
		PRINTF(D_PRINTF("Process ID %d Error reading chunk remotely %d", threadData->iProcessId, r));
sl@0
   181
		}
sl@0
   182
	argBuf.Close();
sl@0
   183
	masterSession.Close();
sl@0
   184
	return r;
sl@0
   185
	}
sl@0
   186
sl@0
   187
sl@0
   188
TInt MasterProcess(TInt aProcessId)
sl@0
   189
	{
sl@0
   190
	TInt pageSize;
sl@0
   191
	UserHal::PageSizeInBytes(pageSize);
sl@0
   192
	// Need a large chunk so that alias that reads it is held for a long
sl@0
   193
	// enough period for there to be conflicts with the chunk closure in 
sl@0
   194
	// the slave process.
sl@0
   195
	const TUint KChunkSize = pageSize * 1024;
sl@0
   196
sl@0
   197
	PRINTF(T_PRINTF(_L("Process ID %d Create chunk\n"), aProcessId));
sl@0
   198
	RChunk chunk;
sl@0
   199
	TInt r = chunk.CreateGlobal(ChunkName, KChunkSize, KChunkSize);
sl@0
   200
	test_KErrNone(r);
sl@0
   201
sl@0
   202
sl@0
   203
	for (TUint8 fillValue = 1; fillValue < 255; fillValue++)
sl@0
   204
		{
sl@0
   205
		// Output a character every 16 iterations so test machines 
sl@0
   206
		// don't time out.
sl@0
   207
		if ((fillValue & 0xf) == 1)
sl@0
   208
			test.Printf(_L("."));
sl@0
   209
sl@0
   210
		PRINTF(T_PRINTF(_L("Process ID %d start slave fill value %d\n"), aProcessId, fillValue));
sl@0
   211
		RServer2 masterServer;
sl@0
   212
		r = masterServer.CreateGlobal(MasterServerName);
sl@0
   213
		test_KErrNone(r);
sl@0
   214
		RMessage2 masterMessage;
sl@0
   215
sl@0
   216
		// Update the chunk to new fill value.
sl@0
   217
		memset(chunk.Base(), fillValue, KChunkSize);
sl@0
   218
sl@0
   219
		PRINTF(T_PRINTF(_L("Process ID %d Start the slave process\n"), aProcessId));
sl@0
   220
		RProcess slaveProcess;
sl@0
   221
		test_KErrNone(slaveProcess.Create(KAliasProcessName, KNullDesC));
sl@0
   222
		test_KErrNone(slaveProcess.SetParameter(1, aProcessId));
sl@0
   223
		test_KErrNone(slaveProcess.SetParameter(2, fillValue));
sl@0
   224
		TRequestStatus slaveStatus;
sl@0
   225
		slaveProcess.Logon(slaveStatus);
sl@0
   226
		test_Equal(KRequestPending, slaveStatus.Int());
sl@0
   227
		slaveProcess.Resume();
sl@0
   228
sl@0
   229
		// Wait for the connect message from the slave process.
sl@0
   230
		masterServer.Receive(masterMessage);
sl@0
   231
		test_Equal(ESlaveConnect, masterMessage.Function());
sl@0
   232
sl@0
   233
		SThreadData threadData;
sl@0
   234
		threadData.iFillValue = fillValue;
sl@0
   235
		threadData.iChunkSize = KChunkSize;
sl@0
   236
		threadData.iProcessId = aProcessId;
sl@0
   237
		RThread readThread;
sl@0
   238
		r = readThread.Create(KNullDesC, ChunkReadThread, 10 * pageSize, KChunkSize, KChunkSize * 2, &threadData);
sl@0
   239
		test_KErrNone(r);
sl@0
   240
		TRequestStatus threadStatus;
sl@0
   241
		readThread.Logon(threadStatus);
sl@0
   242
		test_Equal(KRequestPending, threadStatus.Int());
sl@0
   243
		readThread.Resume();
sl@0
   244
sl@0
   245
		PRINTF(T_PRINTF(_L("Process ID %d Wait for alias thread to start server\n"), aProcessId));
sl@0
   246
		RMessage2 aliasMessage;
sl@0
   247
		masterServer.Receive(aliasMessage);
sl@0
   248
		test_Equal(ESlaveConnect, aliasMessage.Function());
sl@0
   249
		aliasMessage.Complete(KErrNone);
sl@0
   250
sl@0
   251
		// Signal to the slave process to send chunk to alias thread.
sl@0
   252
		PRINTF(T_PRINTF(_L("Process ID %d Signal to slave to send chunk to alias\n"), aProcessId));
sl@0
   253
		masterMessage.Complete(KErrNone);
sl@0
   254
sl@0
   255
		// Wait for slave to close the chunk and fill it with new value.
sl@0
   256
		for (;;)
sl@0
   257
			{
sl@0
   258
			masterServer.Receive(masterMessage);
sl@0
   259
			TInt func = masterMessage.Function();
sl@0
   260
			PRINTF(T_PRINTF(_L("Process ID %d rxd %d\n"), aProcessId, func));
sl@0
   261
			if (func == ESlaveClosedChunk)
sl@0
   262
				{// Slave closed the chunk.
sl@0
   263
				memset(chunk.Base(), ++fillValue, KChunkSize);
sl@0
   264
				break;
sl@0
   265
				}
sl@0
   266
			else
sl@0
   267
				{// Alias has read the chunk and completed.
sl@0
   268
				test_Equal(ESlaveDisconnect, func);
sl@0
   269
				}
sl@0
   270
			}
sl@0
   271
		
sl@0
   272
		PRINTF(T_PRINTF(_L("Process ID %d Wait for alias to complete\n"), aProcessId));
sl@0
   273
		masterMessage.Complete(KErrNone);
sl@0
   274
		User::WaitForRequest(threadStatus);
sl@0
   275
		TInt statusInt = threadStatus.Int();
sl@0
   276
		test_Value(	statusInt, 
sl@0
   277
					statusInt == KErrNone || 
sl@0
   278
					statusInt == KErrBadDescriptor ||
sl@0
   279
					statusInt == KErrDied);
sl@0
   280
		test_Equal(EExitKill, readThread.ExitType());
sl@0
   281
		readThread.Close();
sl@0
   282
sl@0
   283
		PRINTF(T_PRINTF(_L("Process ID %d Wait for slave to complete\n"), aProcessId));
sl@0
   284
		User::WaitForRequest(slaveStatus);
sl@0
   285
		test_Equal(EExitKill, slaveProcess.ExitType());
sl@0
   286
		test_Equal(KErrNone, slaveProcess.ExitReason());
sl@0
   287
		slaveProcess.Close();
sl@0
   288
		masterServer.Close();
sl@0
   289
		}
sl@0
   290
sl@0
   291
	chunk.Close();
sl@0
   292
sl@0
   293
	return 0;
sl@0
   294
	}
sl@0
   295
sl@0
   296
sl@0
   297
GLDEF_C TInt E32Main()
sl@0
   298
	{
sl@0
   299
	TInt processId;
sl@0
   300
	if(User::GetTIntParameter(1, processId)==KErrNone)
sl@0
   301
		{
sl@0
   302
		test_KErrNone(ChunkName.Create(KAliasChunkName.Length() + 3));
sl@0
   303
		ChunkName.Copy(KAliasChunkName);
sl@0
   304
		ChunkName.AppendNum(processId);
sl@0
   305
sl@0
   306
		test_KErrNone(MasterServerName.Create(KMasterServerName.Length() + 3));
sl@0
   307
		MasterServerName.Copy(KMasterServerName);
sl@0
   308
		MasterServerName.AppendNum(processId);
sl@0
   309
sl@0
   310
		test_KErrNone(AliasServerName.Create(KAliasServerName.Length() + 3));
sl@0
   311
		AliasServerName.Copy(KAliasServerName);
sl@0
   312
		AliasServerName.AppendNum(processId);
sl@0
   313
sl@0
   314
		TInt fillValue;
sl@0
   315
		if(User::GetTIntParameter(2, fillValue)==KErrNone)
sl@0
   316
			{
sl@0
   317
			return SlaveProcess(processId, fillValue);
sl@0
   318
			}
sl@0
   319
		return MasterProcess(processId);
sl@0
   320
		}
sl@0
   321
sl@0
   322
	// Get the number of cpus and use it to determine how many processes to execute.
sl@0
   323
	RPageMove pagemove;
sl@0
   324
	test_KErrNone(pagemove.Open());
sl@0
   325
	TUint masterProcesses = pagemove.NumberOfCpus() + 1;
sl@0
   326
	pagemove.Close();
sl@0
   327
sl@0
   328
	TInt cmdLineLen = User::CommandLineLength();
sl@0
   329
	if(cmdLineLen)
sl@0
   330
		{
sl@0
   331
		RBuf cmdLine;
sl@0
   332
		test_KErrNone(cmdLine.Create(cmdLineLen));
sl@0
   333
		User::CommandLine(cmdLine);
sl@0
   334
		test_KErrNone(TLex(cmdLine).Val(masterProcesses));
sl@0
   335
		}
sl@0
   336
sl@0
   337
	test.Title();
sl@0
   338
	test.Start(_L(""));
sl@0
   339
	test.Printf(_L("Create %d processes for accessing aliases being removed\n"), masterProcesses); 
sl@0
   340
sl@0
   341
	TUint32 debugMask = UserSvr::DebugMask();
sl@0
   342
	User::SetDebugMask(0);
sl@0
   343
sl@0
   344
	// Start master processes to alias memory between each other.
sl@0
   345
	RProcess* masters = new RProcess[masterProcesses];
sl@0
   346
	TRequestStatus* masterStatus = new TRequestStatus[masterProcesses];
sl@0
   347
	TUint i = 0;
sl@0
   348
	for (; i < masterProcesses; i++)
sl@0
   349
		{
sl@0
   350
		test_KErrNone(masters[i].Create(KAliasProcessName, KNullDesC));
sl@0
   351
		test_KErrNone(masters[i].SetParameter(1, i));
sl@0
   352
		masters[i].Logon(masterStatus[i]);
sl@0
   353
		test_Equal(KRequestPending, masterStatus[i].Int());
sl@0
   354
		}
sl@0
   355
	test.Next(_L("Resume the processes")); 
sl@0
   356
	for (i = 0; i < masterProcesses; i++)
sl@0
   357
		{
sl@0
   358
		masters[i].Resume();
sl@0
   359
		}
sl@0
   360
sl@0
   361
	test.Next(_L("Wait for processes to exit")); 
sl@0
   362
	for (i = 0; i < masterProcesses; i++)
sl@0
   363
		{
sl@0
   364
		User::WaitForRequest(masterStatus[i]);
sl@0
   365
		test_Equal(EExitKill, masters[i].ExitType());
sl@0
   366
		test_Equal(KErrNone, masters[i].ExitReason());
sl@0
   367
		}
sl@0
   368
	User::SetDebugMask(debugMask);
sl@0
   369
	delete masterStatus;
sl@0
   370
	delete masters;
sl@0
   371
	test.Printf(_L("\n"));
sl@0
   372
	test.End();
sl@0
   373
	return KErrNone;
sl@0
   374
	}