os/kernelhwsrv/kerneltest/e32test/mmu/t_alias_remove.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}