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