1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/mmu/t_alias_remove.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,374 @@
1.4 +// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\mmu\t_alias_remove.cpp
1.18 +// Overview:
1.19 +// Test interactions when free memory being aliases.
1.20 +// Details:
1.21 +// Create 3 mappings to one chunk one that owns the chunk, one to map it again another process
1.22 +// and another alias mapping.
1.23 +// Then while the alias mapping is accessing the chunk close the second mapping.
1.24 +// Platforms/Drives/Compatibility:
1.25 +// All.
1.26 +// Assumptions/Requirement/Pre-requisites:
1.27 +// Failures and causes:
1.28 +// Base Port information:
1.29 +//
1.30 +//
1.31 +
1.32 +#define __E32TEST_EXTENSION__
1.33 +#include <e32test.h>
1.34 +#include <e32hal.h>
1.35 +#include <e32svr.h>
1.36 +#include "..\defrag\d_pagemove.h"
1.37 +
1.38 +const TPtrC KAliasProcessName = _L("T_ALIAS_REMOVE");
1.39 +const TPtrC KAliasChunkName = _L("AliasChunk");
1.40 +const TPtrC KAliasServerName = _L("AliasServer");
1.41 +const TPtrC KMasterServerName = _L("MasterServer");
1.42 +
1.43 +RBuf ChunkName;
1.44 +RBuf MasterServerName;
1.45 +RBuf AliasServerName;
1.46 +
1.47 +RTest test(KAliasProcessName);
1.48 +
1.49 +//#define ENABLE_PRINTFS
1.50 +#ifndef __MSVC6__ // VC6 can't cope with variable arguments in macros.
1.51 +
1.52 +#define T_PRINTF(x...) test.Printf(x)
1.53 +#define D_PRINTF(x...) RDebug::Printf(x)
1.54 +#ifdef ENABLE_PRINTFS
1.55 +#define PRINTF(x) x
1.56 +#else
1.57 +#define PRINTF(x)
1.58 +#endif // ENABLE_PRINTFS
1.59 +
1.60 +#else
1.61 +#define PRINTF(x)
1.62 +#endif // __MSCV6__
1.63 +
1.64 +enum TSlaveMsgType
1.65 + {
1.66 + ESlaveConnect = -1,
1.67 + ESlaveDisconnect = -2,
1.68 + ESlaveReadChunk = 0,
1.69 + ESlaveClosedChunk = 1,
1.70 + };
1.71 +
1.72 +
1.73 +struct SThreadData
1.74 + {
1.75 + TUint8 iFillValue;
1.76 + TUint iChunkSize;
1.77 + RThread* iMasterThread;
1.78 + TUint iProcessId;
1.79 + };
1.80 +
1.81 +
1.82 +class RAliasSession : public RSessionBase
1.83 + {
1.84 +public:
1.85 + TInt CreateSession(const TDesC& aServerName, TInt aMsgSlots)
1.86 + {
1.87 + return RSessionBase::CreateSession(aServerName,User::Version(),aMsgSlots);
1.88 + }
1.89 + TInt PublicSendReceive(TInt aFunction, const TIpcArgs &aPtr)
1.90 + {
1.91 + return (SendReceive(aFunction, aPtr));
1.92 + }
1.93 + TInt PublicSend(TInt aFunction, const TIpcArgs &aPtr)
1.94 + {
1.95 + return (Send(aFunction, aPtr));
1.96 + }
1.97 + };
1.98 +
1.99 +
1.100 +TInt SlaveProcess(TUint aProcessId, TUint aFillValue)
1.101 + {
1.102 + // Connect to the master server to indicate that we're ready to receive ipc messages.
1.103 + RAliasSession masterSession;
1.104 + test_KErrNone(masterSession.CreateSession(MasterServerName, 1));
1.105 +
1.106 + PRINTF(T_PRINTF(_L("Process ID %d Slave open chunk\n"), aProcessId));
1.107 + // Open the global chunk.
1.108 + RChunk chunk;
1.109 + TInt r = chunk.OpenGlobal(ChunkName, ETrue);
1.110 + test_KErrNone(r);
1.111 +
1.112 + // Connect to alias server.
1.113 + PRINTF(T_PRINTF(_L("Process ID %d Slave connect to alias server\n"), aProcessId));
1.114 + RAliasSession aliasSession;
1.115 + test_KErrNone(aliasSession.CreateSession(AliasServerName, 1));
1.116 +
1.117 + PRINTF(T_PRINTF(_L("Process ID %d Slave send data to alias server\n"), aProcessId));
1.118 + TPtr8 arg0(chunk.Base(), chunk.Size(), chunk.Size());
1.119 + r = aliasSession.PublicSend(ESlaveReadChunk, TIpcArgs(&arg0));
1.120 + test_KErrNone(r);
1.121 +
1.122 + // Close the chunk removing its mapping before the server has read it.
1.123 + chunk.Close();
1.124 + PRINTF(T_PRINTF(_L("Process ID %d Slave closed chunk\n"), aProcessId));
1.125 +
1.126 + r = masterSession.PublicSendReceive(ESlaveClosedChunk, TIpcArgs());
1.127 + test_KErrNone(r);
1.128 + aliasSession.Close();
1.129 + masterSession.Close();
1.130 + return KErrNone;
1.131 + }
1.132 +
1.133 +
1.134 +TInt ChunkReadThread(TAny* aThreadData)
1.135 + {
1.136 + SThreadData* threadData = (SThreadData*)aThreadData;
1.137 + RServer2 aliasServer;
1.138 + TInt r = aliasServer.CreateGlobal(AliasServerName);
1.139 + if (r != KErrNone)
1.140 + {
1.141 + RDebug::Printf("Process ID %d Error creating alias server r=%d", threadData->iProcessId, r);
1.142 + return r;
1.143 + }
1.144 + // Connect to the master server to indicate that we're ready to receive ipc messages.
1.145 + RAliasSession masterSession;
1.146 + test_KErrNone(masterSession.CreateSession(MasterServerName, 1));
1.147 +
1.148 + PRINTF(D_PRINTF("Process ID %d Alias wait for slave connection", threadData->iProcessId));
1.149 + RMessage2 aliasMessage;
1.150 + // Read and complete the connect message from the slave.
1.151 + aliasServer.Receive(aliasMessage);
1.152 + test_Equal(ESlaveConnect, aliasMessage.Function());
1.153 + aliasMessage.Complete(KErrNone);
1.154 +
1.155 + // Read the data of the remote chunk.
1.156 + PRINTF(D_PRINTF("Process ID %d Alias read chunk data", threadData->iProcessId));
1.157 + HBufC8* argTmp = HBufC8::New(threadData->iChunkSize);
1.158 + test_NotNull(argTmp);
1.159 + RBuf8 argBuf(argTmp);
1.160 + aliasServer.Receive(aliasMessage);
1.161 + test_Equal(ESlaveReadChunk, aliasMessage.Function());
1.162 + r = aliasMessage.Read(0, argBuf);
1.163 + if (r == KErrNone)
1.164 + {// Successfully read the chunk so verify it.
1.165 + aliasMessage.Complete(KErrNone);
1.166 +
1.167 + PRINTF(D_PRINTF("Process ID %d Alias verify chunk data", threadData->iProcessId));
1.168 + const TUint8* bufPtr = argBuf.Ptr();
1.169 + const TUint8* bufEnd = bufPtr + threadData->iChunkSize;
1.170 + for (; bufPtr < bufEnd; bufPtr++)
1.171 + {
1.172 + if (*bufPtr != threadData->iFillValue)
1.173 + {
1.174 + RDebug::Printf("Process ID %d Read incorrect data exp 0x%x got 0x%x",
1.175 + threadData->iProcessId, threadData->iFillValue, *bufPtr);
1.176 + r = *bufPtr;
1.177 + break;
1.178 + }
1.179 + }
1.180 + }
1.181 + else
1.182 + {
1.183 + PRINTF(D_PRINTF("Process ID %d Error reading chunk remotely %d", threadData->iProcessId, r));
1.184 + }
1.185 + argBuf.Close();
1.186 + masterSession.Close();
1.187 + return r;
1.188 + }
1.189 +
1.190 +
1.191 +TInt MasterProcess(TInt aProcessId)
1.192 + {
1.193 + TInt pageSize;
1.194 + UserHal::PageSizeInBytes(pageSize);
1.195 + // Need a large chunk so that alias that reads it is held for a long
1.196 + // enough period for there to be conflicts with the chunk closure in
1.197 + // the slave process.
1.198 + const TUint KChunkSize = pageSize * 1024;
1.199 +
1.200 + PRINTF(T_PRINTF(_L("Process ID %d Create chunk\n"), aProcessId));
1.201 + RChunk chunk;
1.202 + TInt r = chunk.CreateGlobal(ChunkName, KChunkSize, KChunkSize);
1.203 + test_KErrNone(r);
1.204 +
1.205 +
1.206 + for (TUint8 fillValue = 1; fillValue < 255; fillValue++)
1.207 + {
1.208 + // Output a character every 16 iterations so test machines
1.209 + // don't time out.
1.210 + if ((fillValue & 0xf) == 1)
1.211 + test.Printf(_L("."));
1.212 +
1.213 + PRINTF(T_PRINTF(_L("Process ID %d start slave fill value %d\n"), aProcessId, fillValue));
1.214 + RServer2 masterServer;
1.215 + r = masterServer.CreateGlobal(MasterServerName);
1.216 + test_KErrNone(r);
1.217 + RMessage2 masterMessage;
1.218 +
1.219 + // Update the chunk to new fill value.
1.220 + memset(chunk.Base(), fillValue, KChunkSize);
1.221 +
1.222 + PRINTF(T_PRINTF(_L("Process ID %d Start the slave process\n"), aProcessId));
1.223 + RProcess slaveProcess;
1.224 + test_KErrNone(slaveProcess.Create(KAliasProcessName, KNullDesC));
1.225 + test_KErrNone(slaveProcess.SetParameter(1, aProcessId));
1.226 + test_KErrNone(slaveProcess.SetParameter(2, fillValue));
1.227 + TRequestStatus slaveStatus;
1.228 + slaveProcess.Logon(slaveStatus);
1.229 + test_Equal(KRequestPending, slaveStatus.Int());
1.230 + slaveProcess.Resume();
1.231 +
1.232 + // Wait for the connect message from the slave process.
1.233 + masterServer.Receive(masterMessage);
1.234 + test_Equal(ESlaveConnect, masterMessage.Function());
1.235 +
1.236 + SThreadData threadData;
1.237 + threadData.iFillValue = fillValue;
1.238 + threadData.iChunkSize = KChunkSize;
1.239 + threadData.iProcessId = aProcessId;
1.240 + RThread readThread;
1.241 + r = readThread.Create(KNullDesC, ChunkReadThread, 10 * pageSize, KChunkSize, KChunkSize * 2, &threadData);
1.242 + test_KErrNone(r);
1.243 + TRequestStatus threadStatus;
1.244 + readThread.Logon(threadStatus);
1.245 + test_Equal(KRequestPending, threadStatus.Int());
1.246 + readThread.Resume();
1.247 +
1.248 + PRINTF(T_PRINTF(_L("Process ID %d Wait for alias thread to start server\n"), aProcessId));
1.249 + RMessage2 aliasMessage;
1.250 + masterServer.Receive(aliasMessage);
1.251 + test_Equal(ESlaveConnect, aliasMessage.Function());
1.252 + aliasMessage.Complete(KErrNone);
1.253 +
1.254 + // Signal to the slave process to send chunk to alias thread.
1.255 + PRINTF(T_PRINTF(_L("Process ID %d Signal to slave to send chunk to alias\n"), aProcessId));
1.256 + masterMessage.Complete(KErrNone);
1.257 +
1.258 + // Wait for slave to close the chunk and fill it with new value.
1.259 + for (;;)
1.260 + {
1.261 + masterServer.Receive(masterMessage);
1.262 + TInt func = masterMessage.Function();
1.263 + PRINTF(T_PRINTF(_L("Process ID %d rxd %d\n"), aProcessId, func));
1.264 + if (func == ESlaveClosedChunk)
1.265 + {// Slave closed the chunk.
1.266 + memset(chunk.Base(), ++fillValue, KChunkSize);
1.267 + break;
1.268 + }
1.269 + else
1.270 + {// Alias has read the chunk and completed.
1.271 + test_Equal(ESlaveDisconnect, func);
1.272 + }
1.273 + }
1.274 +
1.275 + PRINTF(T_PRINTF(_L("Process ID %d Wait for alias to complete\n"), aProcessId));
1.276 + masterMessage.Complete(KErrNone);
1.277 + User::WaitForRequest(threadStatus);
1.278 + TInt statusInt = threadStatus.Int();
1.279 + test_Value( statusInt,
1.280 + statusInt == KErrNone ||
1.281 + statusInt == KErrBadDescriptor ||
1.282 + statusInt == KErrDied);
1.283 + test_Equal(EExitKill, readThread.ExitType());
1.284 + readThread.Close();
1.285 +
1.286 + PRINTF(T_PRINTF(_L("Process ID %d Wait for slave to complete\n"), aProcessId));
1.287 + User::WaitForRequest(slaveStatus);
1.288 + test_Equal(EExitKill, slaveProcess.ExitType());
1.289 + test_Equal(KErrNone, slaveProcess.ExitReason());
1.290 + slaveProcess.Close();
1.291 + masterServer.Close();
1.292 + }
1.293 +
1.294 + chunk.Close();
1.295 +
1.296 + return 0;
1.297 + }
1.298 +
1.299 +
1.300 +GLDEF_C TInt E32Main()
1.301 + {
1.302 + TInt processId;
1.303 + if(User::GetTIntParameter(1, processId)==KErrNone)
1.304 + {
1.305 + test_KErrNone(ChunkName.Create(KAliasChunkName.Length() + 3));
1.306 + ChunkName.Copy(KAliasChunkName);
1.307 + ChunkName.AppendNum(processId);
1.308 +
1.309 + test_KErrNone(MasterServerName.Create(KMasterServerName.Length() + 3));
1.310 + MasterServerName.Copy(KMasterServerName);
1.311 + MasterServerName.AppendNum(processId);
1.312 +
1.313 + test_KErrNone(AliasServerName.Create(KAliasServerName.Length() + 3));
1.314 + AliasServerName.Copy(KAliasServerName);
1.315 + AliasServerName.AppendNum(processId);
1.316 +
1.317 + TInt fillValue;
1.318 + if(User::GetTIntParameter(2, fillValue)==KErrNone)
1.319 + {
1.320 + return SlaveProcess(processId, fillValue);
1.321 + }
1.322 + return MasterProcess(processId);
1.323 + }
1.324 +
1.325 + // Get the number of cpus and use it to determine how many processes to execute.
1.326 + RPageMove pagemove;
1.327 + test_KErrNone(pagemove.Open());
1.328 + TUint masterProcesses = pagemove.NumberOfCpus() + 1;
1.329 + pagemove.Close();
1.330 +
1.331 + TInt cmdLineLen = User::CommandLineLength();
1.332 + if(cmdLineLen)
1.333 + {
1.334 + RBuf cmdLine;
1.335 + test_KErrNone(cmdLine.Create(cmdLineLen));
1.336 + User::CommandLine(cmdLine);
1.337 + test_KErrNone(TLex(cmdLine).Val(masterProcesses));
1.338 + }
1.339 +
1.340 + test.Title();
1.341 + test.Start(_L(""));
1.342 + test.Printf(_L("Create %d processes for accessing aliases being removed\n"), masterProcesses);
1.343 +
1.344 + TUint32 debugMask = UserSvr::DebugMask();
1.345 + User::SetDebugMask(0);
1.346 +
1.347 + // Start master processes to alias memory between each other.
1.348 + RProcess* masters = new RProcess[masterProcesses];
1.349 + TRequestStatus* masterStatus = new TRequestStatus[masterProcesses];
1.350 + TUint i = 0;
1.351 + for (; i < masterProcesses; i++)
1.352 + {
1.353 + test_KErrNone(masters[i].Create(KAliasProcessName, KNullDesC));
1.354 + test_KErrNone(masters[i].SetParameter(1, i));
1.355 + masters[i].Logon(masterStatus[i]);
1.356 + test_Equal(KRequestPending, masterStatus[i].Int());
1.357 + }
1.358 + test.Next(_L("Resume the processes"));
1.359 + for (i = 0; i < masterProcesses; i++)
1.360 + {
1.361 + masters[i].Resume();
1.362 + }
1.363 +
1.364 + test.Next(_L("Wait for processes to exit"));
1.365 + for (i = 0; i < masterProcesses; i++)
1.366 + {
1.367 + User::WaitForRequest(masterStatus[i]);
1.368 + test_Equal(EExitKill, masters[i].ExitType());
1.369 + test_Equal(KErrNone, masters[i].ExitReason());
1.370 + }
1.371 + User::SetDebugMask(debugMask);
1.372 + delete masterStatus;
1.373 + delete masters;
1.374 + test.Printf(_L("\n"));
1.375 + test.End();
1.376 + return KErrNone;
1.377 + }