kerneltest/e32test/mmu/t_alias_remove.cpp
changeset 8 538db54a451d
child 42 a179b74831c9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/t_alias_remove.cpp	Mon Jan 18 21:31:10 2010 +0200
@@ -0,0 +1,374 @@
+// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\mmu\t_alias_remove.cpp
+// Overview:
+// Test interactions when free memory being aliases.
+// Details:
+// Create 3 mappings to one chunk one that owns the chunk, one to map it again another process 
+// and another alias mapping.
+// Then while the alias mapping is accessing the chunk close the second mapping.
+// Platforms/Drives/Compatibility:
+// All.
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+// 
+//
+
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32hal.h>
+#include <e32svr.h>
+#include "..\defrag\d_pagemove.h"
+
+const TPtrC KAliasProcessName = _L("T_ALIAS_REMOVE");
+const TPtrC KAliasChunkName = _L("AliasChunk");
+const TPtrC KAliasServerName = _L("AliasServer");
+const TPtrC KMasterServerName = _L("MasterServer");
+
+RBuf ChunkName;
+RBuf MasterServerName;
+RBuf AliasServerName;
+
+RTest test(KAliasProcessName);
+
+//#define ENABLE_PRINTFS
+#ifndef __MSVC6__	// VC6 can't cope with variable arguments in macros.
+
+#define T_PRINTF(x...) test.Printf(x)
+#define D_PRINTF(x...) RDebug::Printf(x)
+#ifdef ENABLE_PRINTFS
+#define PRINTF(x) x
+#else
+#define PRINTF(x)
+#endif // ENABLE_PRINTFS
+
+#else
+#define PRINTF(x)
+#endif	// __MSCV6__
+
+enum TSlaveMsgType
+	{
+	ESlaveConnect = -1,
+	ESlaveDisconnect = -2,
+	ESlaveReadChunk = 0,
+	ESlaveClosedChunk = 1,
+	};
+
+
+struct SThreadData 
+	{
+	TUint8 iFillValue;
+	TUint iChunkSize;
+	RThread* iMasterThread;
+	TUint iProcessId;
+	};
+
+
+class RAliasSession : public RSessionBase
+	{
+public:
+	TInt CreateSession(const TDesC& aServerName, TInt aMsgSlots) 
+		{ 
+		return RSessionBase::CreateSession(aServerName,User::Version(),aMsgSlots);
+		}
+	TInt PublicSendReceive(TInt aFunction, const TIpcArgs &aPtr)
+		{
+		return (SendReceive(aFunction, aPtr));
+		}
+	TInt PublicSend(TInt aFunction, const TIpcArgs &aPtr)
+		{
+		return (Send(aFunction, aPtr));
+		}
+	};
+
+
+TInt SlaveProcess(TUint aProcessId, TUint aFillValue)
+	{		
+	// Connect to the master server to indicate that we're ready to receive ipc messages.
+	RAliasSession masterSession;
+	test_KErrNone(masterSession.CreateSession(MasterServerName, 1));
+
+	PRINTF(T_PRINTF(_L("Process ID %d Slave open chunk\n"), aProcessId));
+	// Open the global chunk.
+	RChunk chunk;
+	TInt r = chunk.OpenGlobal(ChunkName, ETrue);
+	test_KErrNone(r);
+
+	// Connect to alias server.
+	PRINTF(T_PRINTF(_L("Process ID %d Slave connect to alias server\n"), aProcessId));
+	RAliasSession aliasSession;
+	test_KErrNone(aliasSession.CreateSession(AliasServerName, 1));
+
+	PRINTF(T_PRINTF(_L("Process ID %d Slave send data to alias server\n"), aProcessId));
+	TPtr8 arg0(chunk.Base(), chunk.Size(), chunk.Size());
+	r = aliasSession.PublicSend(ESlaveReadChunk, TIpcArgs(&arg0));
+	test_KErrNone(r);
+	
+	// Close the chunk removing its mapping before the server has read it.
+	chunk.Close();
+	PRINTF(T_PRINTF(_L("Process ID %d Slave closed chunk\n"), aProcessId));
+
+	r = masterSession.PublicSendReceive(ESlaveClosedChunk, TIpcArgs());
+	test_KErrNone(r);
+	aliasSession.Close();
+	masterSession.Close();
+	return KErrNone;
+	}
+
+
+TInt ChunkReadThread(TAny* aThreadData)
+	{
+	SThreadData* threadData =  (SThreadData*)aThreadData;
+	RServer2 aliasServer;
+	TInt r = aliasServer.CreateGlobal(AliasServerName);
+	if (r != KErrNone)
+		{
+		RDebug::Printf("Process ID %d Error creating alias server r=%d", threadData->iProcessId, r);
+		return r;
+		}
+	// Connect to the master server to indicate that we're ready to receive ipc messages.
+	RAliasSession masterSession;
+	test_KErrNone(masterSession.CreateSession(MasterServerName, 1));
+
+	PRINTF(D_PRINTF("Process ID %d Alias wait for slave connection", threadData->iProcessId));
+	RMessage2 aliasMessage;
+	// Read and complete the connect message from the slave.
+	aliasServer.Receive(aliasMessage);
+	test_Equal(ESlaveConnect, aliasMessage.Function());
+	aliasMessage.Complete(KErrNone);
+
+	// Read the data of the remote chunk.
+	PRINTF(D_PRINTF("Process ID %d Alias read chunk data", threadData->iProcessId));
+	HBufC8* argTmp = HBufC8::New(threadData->iChunkSize);
+	test_NotNull(argTmp);
+	RBuf8 argBuf(argTmp);
+	aliasServer.Receive(aliasMessage);
+	test_Equal(ESlaveReadChunk, aliasMessage.Function());
+	r = aliasMessage.Read(0, argBuf);
+	if (r == KErrNone)
+		{// Successfully read the chunk so verify it.
+		aliasMessage.Complete(KErrNone);
+
+		PRINTF(D_PRINTF("Process ID %d Alias verify chunk data", threadData->iProcessId));
+		const TUint8* bufPtr = argBuf.Ptr();
+		const TUint8* bufEnd = bufPtr + threadData->iChunkSize;
+		for (; bufPtr < bufEnd; bufPtr++)
+			{
+			if (*bufPtr != threadData->iFillValue)
+				{
+				RDebug::Printf("Process ID %d Read incorrect data exp 0x%x got 0x%x", 
+								threadData->iProcessId, threadData->iFillValue, *bufPtr);
+				r = *bufPtr;
+				break;
+				}
+			}
+		}
+	else
+		{
+		PRINTF(D_PRINTF("Process ID %d Error reading chunk remotely %d", threadData->iProcessId, r));
+		}
+	argBuf.Close();
+	masterSession.Close();
+	return r;
+	}
+
+
+TInt MasterProcess(TInt aProcessId)
+	{
+	TInt pageSize;
+	UserHal::PageSizeInBytes(pageSize);
+	// Need a large chunk so that alias that reads it is held for a long
+	// enough period for there to be conflicts with the chunk closure in 
+	// the slave process.
+	const TUint KChunkSize = pageSize * 1024;
+
+	PRINTF(T_PRINTF(_L("Process ID %d Create chunk\n"), aProcessId));
+	RChunk chunk;
+	TInt r = chunk.CreateGlobal(ChunkName, KChunkSize, KChunkSize);
+	test_KErrNone(r);
+
+
+	for (TUint8 fillValue = 1; fillValue < 255; fillValue++)
+		{
+		// Output a character every 16 iterations so test machines 
+		// don't time out.
+		if ((fillValue & 0xf) == 1)
+			test.Printf(_L("."));
+
+		PRINTF(T_PRINTF(_L("Process ID %d start slave fill value %d\n"), aProcessId, fillValue));
+		RServer2 masterServer;
+		r = masterServer.CreateGlobal(MasterServerName);
+		test_KErrNone(r);
+		RMessage2 masterMessage;
+
+		// Update the chunk to new fill value.
+		memset(chunk.Base(), fillValue, KChunkSize);
+
+		PRINTF(T_PRINTF(_L("Process ID %d Start the slave process\n"), aProcessId));
+		RProcess slaveProcess;
+		test_KErrNone(slaveProcess.Create(KAliasProcessName, KNullDesC));
+		test_KErrNone(slaveProcess.SetParameter(1, aProcessId));
+		test_KErrNone(slaveProcess.SetParameter(2, fillValue));
+		TRequestStatus slaveStatus;
+		slaveProcess.Logon(slaveStatus);
+		test_Equal(KRequestPending, slaveStatus.Int());
+		slaveProcess.Resume();
+
+		// Wait for the connect message from the slave process.
+		masterServer.Receive(masterMessage);
+		test_Equal(ESlaveConnect, masterMessage.Function());
+
+		SThreadData threadData;
+		threadData.iFillValue = fillValue;
+		threadData.iChunkSize = KChunkSize;
+		threadData.iProcessId = aProcessId;
+		RThread readThread;
+		r = readThread.Create(KNullDesC, ChunkReadThread, 10 * pageSize, KChunkSize, KChunkSize * 2, &threadData);
+		test_KErrNone(r);
+		TRequestStatus threadStatus;
+		readThread.Logon(threadStatus);
+		test_Equal(KRequestPending, threadStatus.Int());
+		readThread.Resume();
+
+		PRINTF(T_PRINTF(_L("Process ID %d Wait for alias thread to start server\n"), aProcessId));
+		RMessage2 aliasMessage;
+		masterServer.Receive(aliasMessage);
+		test_Equal(ESlaveConnect, aliasMessage.Function());
+		aliasMessage.Complete(KErrNone);
+
+		// Signal to the slave process to send chunk to alias thread.
+		PRINTF(T_PRINTF(_L("Process ID %d Signal to slave to send chunk to alias\n"), aProcessId));
+		masterMessage.Complete(KErrNone);
+
+		// Wait for slave to close the chunk and fill it with new value.
+		for (;;)
+			{
+			masterServer.Receive(masterMessage);
+			TInt func = masterMessage.Function();
+			PRINTF(T_PRINTF(_L("Process ID %d rxd %d\n"), aProcessId, func));
+			if (func == ESlaveClosedChunk)
+				{// Slave closed the chunk.
+				memset(chunk.Base(), ++fillValue, KChunkSize);
+				break;
+				}
+			else
+				{// Alias has read the chunk and completed.
+				test_Equal(ESlaveDisconnect, func);
+				}
+			}
+		
+		PRINTF(T_PRINTF(_L("Process ID %d Wait for alias to complete\n"), aProcessId));
+		masterMessage.Complete(KErrNone);
+		User::WaitForRequest(threadStatus);
+		TInt statusInt = threadStatus.Int();
+		test_Value(	statusInt, 
+					statusInt == KErrNone || 
+					statusInt == KErrBadDescriptor ||
+					statusInt == KErrDied);
+		test_Equal(EExitKill, readThread.ExitType());
+		readThread.Close();
+
+		PRINTF(T_PRINTF(_L("Process ID %d Wait for slave to complete\n"), aProcessId));
+		User::WaitForRequest(slaveStatus);
+		test_Equal(EExitKill, slaveProcess.ExitType());
+		test_Equal(KErrNone, slaveProcess.ExitReason());
+		slaveProcess.Close();
+		masterServer.Close();
+		}
+
+	chunk.Close();
+
+	return 0;
+	}
+
+
+GLDEF_C TInt E32Main()
+	{
+	TInt processId;
+	if(User::GetTIntParameter(1, processId)==KErrNone)
+		{
+		test_KErrNone(ChunkName.Create(KAliasChunkName.Length() + 3));
+		ChunkName.Copy(KAliasChunkName);
+		ChunkName.AppendNum(processId);
+
+		test_KErrNone(MasterServerName.Create(KMasterServerName.Length() + 3));
+		MasterServerName.Copy(KMasterServerName);
+		MasterServerName.AppendNum(processId);
+
+		test_KErrNone(AliasServerName.Create(KAliasServerName.Length() + 3));
+		AliasServerName.Copy(KAliasServerName);
+		AliasServerName.AppendNum(processId);
+
+		TInt fillValue;
+		if(User::GetTIntParameter(2, fillValue)==KErrNone)
+			{
+			return SlaveProcess(processId, fillValue);
+			}
+		return MasterProcess(processId);
+		}
+
+	// Get the number of cpus and use it to determine how many processes to execute.
+	RPageMove pagemove;
+	test_KErrNone(pagemove.Open());
+	TUint masterProcesses = pagemove.NumberOfCpus() + 1;
+	pagemove.Close();
+
+	TInt cmdLineLen = User::CommandLineLength();
+	if(cmdLineLen)
+		{
+		RBuf cmdLine;
+		test_KErrNone(cmdLine.Create(cmdLineLen));
+		User::CommandLine(cmdLine);
+		test_KErrNone(TLex(cmdLine).Val(masterProcesses));
+		}
+
+	test.Title();
+	test.Start(_L(""));
+	test.Printf(_L("Create %d processes for accessing aliases being removed\n"), masterProcesses); 
+
+	TUint32 debugMask = UserSvr::DebugMask();
+	User::SetDebugMask(0);
+
+	// Start master processes to alias memory between each other.
+	RProcess* masters = new RProcess[masterProcesses];
+	TRequestStatus* masterStatus = new TRequestStatus[masterProcesses];
+	TUint i = 0;
+	for (; i < masterProcesses; i++)
+		{
+		test_KErrNone(masters[i].Create(KAliasProcessName, KNullDesC));
+		test_KErrNone(masters[i].SetParameter(1, i));
+		masters[i].Logon(masterStatus[i]);
+		test_Equal(KRequestPending, masterStatus[i].Int());
+		}
+	test.Next(_L("Resume the processes")); 
+	for (i = 0; i < masterProcesses; i++)
+		{
+		masters[i].Resume();
+		}
+
+	test.Next(_L("Wait for processes to exit")); 
+	for (i = 0; i < masterProcesses; i++)
+		{
+		User::WaitForRequest(masterStatus[i]);
+		test_Equal(EExitKill, masters[i].ExitType());
+		test_Equal(KErrNone, masters[i].ExitReason());
+		}
+	User::SetDebugMask(debugMask);
+	delete masterStatus;
+	delete masters;
+	test.Printf(_L("\n"));
+	test.End();
+	return KErrNone;
+	}