diff -r f497542af8e4 -r 538db54a451d kerneltest/e32test/mmu/t_alias_remove.cpp --- /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 +#include +#include +#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; + }