diff -r 56f325a607ea -r 0173bcd7697c kerneltest/e32test/smpsoak/t_smpsoak.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/smpsoak/t_smpsoak.cpp Thu Jan 07 13:38:45 2010 +0200 @@ -0,0 +1,903 @@ +// Copyright (c) 2002-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\smpsoak\t_smpsoak.cpp + +// User Includes +#include "t_smpsoak.h" + +void ParseCommandLine (); + +// Global Variables +static TInt gPageSize; +//Timeout 2 Minutes +static TUint gTimeout = 120; + +//class for smpsoak thread and it creates memory, device, timer and spin threads. +class CSMPSoakThread + { +public: + CSMPSoakThread(); + ~CSMPSoakThread(); + void CreateThread(); + void ResumeThread(); + void CreateChildProcess(TInt aIndex); + void ResumeChildProcess(); + void TerminateChildProcess(); +private: + //Thread Functions + static TInt SMPStressMemoryThread(TAny*); + static TInt SMPStressDeviceThread(TAny*); + static TInt SMPStressTimerThread(TAny*); + static TInt SMPStressSpinThread(TAny*); + //Thread Priority + void DoCreateThread(TAny*); + void SetThreadPriority(); +private: + //Utils for memory thread + void CreateChunk(TChunkInfo * aChunkInfo, TMemory * aMemoryTablePtr); + void CommitChunk(TChunkInfo * aChunkInfo, TMemory * aMemoryTablePtr); + void WriteReadChunk(TChunkInfo * aChunkInfo, TMemory * aMemoryTablePtr); +private: + //Memebers for threads + TInt DoSMPStressMemoryThread(); + TInt DoSMPStressDeviceThread(); + TInt DoSMPStressTimerThread(); + TInt DoSMPStressSpinThread(); +private: + TThreadData iThreadData; + RProcess iProcess; + RThread iThread; + TInt iPriority; +private: +// Thread Data for each thread- low priority +static TThread KThreadTableLow[]; +// Thread Data for each thread- high priority +static TThread KThreadTableHigh[]; +//Process Data for each process +static const TProcess KProcessTable[]; +//Memory table for memory thread +static const TMemory KMemoryTable[]; +//Device table for device thread +static const TDesC* KDeviceTable[]; + + }; +TThread CSMPSoakThread::KThreadTableLow[] = + { + { _L("Memory Thread"), CSMPSoakThread::SMPStressMemoryThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 250, 1, (TAny *)&KMemoryTable, NULL, NULL}}, + { _L("Device Thread"), CSMPSoakThread::SMPStressDeviceThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 300, 1, &KDeviceTable, NULL, NULL}}, + { _L("Spin Thread 0"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityAbsoluteVeryLow, EPriorityNormal, EPriorityNormal, EPriorityNormal}, EPriorityList, KCpuAffinityAny, 200, 0, NULL, NULL, NULL}}, + { _L("Spin Thread 1"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityNormal, EPriorityAbsoluteVeryLow, EPriorityNormal, EPriorityNormal}, EPriorityList, KCpuAffinityAny, 300, 0, NULL, NULL, NULL}}, + { _L("Spin Thread 2"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityNormal, EPriorityNormal, EPriorityAbsoluteVeryLow, EPriorityNormal}, EPriorityList, KCpuAffinityAny, 400, 0, NULL, NULL, NULL}}, + { _L("Spin Thread 3"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityNormal, EPriorityNormal, EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow}, EPriorityList, KCpuAffinityAny, 500, 0, NULL, NULL, NULL}}, + { _L("Timer Thread"), CSMPSoakThread::SMPStressTimerThread, {{EPriorityNormal, 0, 0, 0}, EPriorityList, KCpuAffinityAny, 1000, 4, NULL}}, + }; +TThread CSMPSoakThread::KThreadTableHigh[] = + { + { _L("Memory Thread"), CSMPSoakThread::SMPStressMemoryThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 250, 1, (TAny *)&KMemoryTable, NULL, NULL}}, + { _L("Device Thread"), CSMPSoakThread::SMPStressDeviceThread, {{EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow, EPriorityNormal, 0}, EPriorityList, KCpuAffinityAny, 300, 1, &KDeviceTable, NULL, NULL}}, + { _L("Spin Thread 0"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityAbsoluteVeryLow, EPriorityNormal, EPriorityNormal, EPriorityNormal}, EPriorityList, KCpuAffinityAny, 200, 0, NULL, NULL, NULL}}, + { _L("Spin Thread 1"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityNormal, EPriorityAbsoluteVeryLow, EPriorityNormal, EPriorityNormal}, EPriorityList, KCpuAffinityAny, 300, 0, NULL, NULL, NULL}}, + { _L("Spin Thread 2"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityNormal, EPriorityNormal, EPriorityAbsoluteVeryLow, EPriorityNormal}, EPriorityList, KCpuAffinityAny, 400, 0, NULL, NULL, NULL}}, + { _L("Spin Thread 3"), CSMPSoakThread::SMPStressSpinThread, {{EPriorityNormal, EPriorityNormal, EPriorityAbsoluteLow, EPriorityAbsoluteVeryLow}, EPriorityList, KCpuAffinityAny, 500, 0, NULL, NULL, NULL}}, + { _L("Timer Thread"), CSMPSoakThread::SMPStressTimerThread, {{EPriorityNormal, 0, 0, 0}, EPriorityList, KCpuAffinityAny, 1000, 4, NULL}}, + }; +const TProcess CSMPSoakThread::KProcessTable[] = + { + { _L("t_smpsoakprocess.exe"), _L("-W"), KCpuAffinityAny}, + { _L("t_smpsoakprocess.exe"), _L("-R"), KCpuAffinityAny}, + { _L("t_smpsoakprocess.exe"), _L("-F"), KCpuAffinityAny}, + { _L("t_smpsoakprocess.exe"), _L("-T"), KCpuAffinityAny}, + { _L("t_smpsoakprocess.exe"), _L("-O"), KCpuAffinityAny}, + }; +const TMemory CSMPSoakThread::KMemoryTable[] = + { + {_L(""), EChunkNormalThread, 0, 10, 100 }, + {_L("Global Chunk 1"), EChunkNormalThread, 0, 20, 200 }, + {_L(""), EChunkDisconnectedThread, 3, 30, 300 }, + {_L("Global Chunk 2"), EChunkDisconnectedThread, 4, 40, 400 }, + {_L(""), EChunkDoubleEndedThread, 5, 50, 500 }, + {_L("Global Chunk 3"), EChunkDoubleEndedThread, 6, 60, 600 }, + {_L(""), EChunkNormalProcess, 0, 10, 100 }, + {_L("Global Chunk 4"), EChunkNormalProcess, 0, 20, 200 }, + {_L(""), EChunkDisconnectedProcess, 3, 30, 300 }, + {_L("Global Chunk 5"), EChunkDisconnectedProcess, 4, 40, 400 }, + {_L(""), EChunkDoubleEndedProcess, 5, 50, 500 }, + {_L("Global Chunk 6"), EChunkDoubleEndedProcess, 6, 60, 600 }, + {_L(""), EChunkNone, 0, 0, 0 }, + }; +const TDesC* CSMPSoakThread::KDeviceTable[] = + { + &KDevices, &KDevLdd1, &KDevLdd1Name, &KDevLdd2, &KDevLdd2Name, &KDevLdd3, &KDevLdd3Name, + &KDevLdd4, &KDevLdd4Name, &KDevLdd5, &KDevLdd5Name, NULL + }; + +//Constructor +CSMPSoakThread::CSMPSoakThread() + { + } +//Destructor +CSMPSoakThread::~CSMPSoakThread() + { + } +//All child process creation +void CSMPSoakThread::CreateChildProcess(TInt aIndex) + { + if(TestSilent) + gCmdLine.Format(KCmdLineBackground,(KProcessTable[aIndex].operation).Ptr()); + else if (Period) + gCmdLine.Format(KCmdLinePeriod,gPeriod,(KProcessTable[aIndex].operation).Ptr()); + else + gCmdLine.Format(KCmdLineProcess,(KProcessTable[aIndex].operation).Ptr()); + + TInt r = iProcess.Create(KProcessTable[aIndex].processFileName,gCmdLine); + test_KErrNone(r); + iProcess.SetPriority(EPriorityLow); + gSMPStressDrv.ChangeThreadAffinity(&iThread, KProcessTable[aIndex].cpuAffinity); + PRINT ((_L("SetProcessPriority CPU %d Priority %d\n"),gSMPStressDrv.GetThreadCPU(&iThread), iProcess.Priority())); + } +//Terminate process when user press "Esc key" +void CSMPSoakThread::ResumeChildProcess() + { + iProcess.Resume(); + } +//Terminate process when user press "Esc key" +void CSMPSoakThread::TerminateChildProcess() + { + iProcess.Kill(KErrNone); + } +//Changes the thread priority each time time, for each thread by Random, Increment, from List, Fixed. +//pick up the priority option from thread table +void CSMPSoakThread::SetThreadPriority() + { + static TInt64 randSeed = KRandSeed; + static const TThreadPriority priorityTable[]= + { + EPriorityMuchLess, EPriorityLess, EPriorityNormal, EPriorityMore, EPriorityMuchMore, + EPriorityRealTime, EPriorityRealTime, EPriorityAbsoluteVeryLow, EPriorityAbsoluteLowNormal, + EPriorityAbsoluteLow, EPriorityAbsoluteBackgroundNormal, EPriorityAbsoluteBackground, + EPriorityAbsoluteForegroundNormal, EPriorityAbsoluteForeground, EPriorityAbsoluteHighNormal, EPriorityAbsoluteHigh + }; + TInt priorityIndex = 0; + switch (iThreadData.threadPriorityChange) + { + case EpriorityFixed: + break; + + case EPriorityList: + if (++iPriority >= KPriorityOrder) + iPriority = 0; + if (iThreadData.threadPriorities[iPriority] == 0) + iPriority = 0; + // PRINT(_L("SetPriority List CPU %d index %d priority %d\n"),gSMPStressDrv.GetThreadCPU(&iThread),iPriority, iThreadData.threadPriorities[iPriority]); + iThread.SetPriority((TThreadPriority)iThreadData.threadPriorities[iPriority]); + break; + + case EPriorityIncrement: + while (priorityTable[priorityIndex] <= iPriority) + { + priorityIndex++; + } + iPriority = priorityTable[priorityIndex]; + if (iPriority > iThreadData.threadPriorities[2]) + iPriority = iThreadData.threadPriorities[1]; + // PRINT(_L("SetPriority Increment CPU %d iPriority %d\n"),gSMPStressDrv.GetThreadCPU(&iThread), iPriority); + iThread.SetPriority((TThreadPriority)iPriority); + break; + + case EPriorityRandom: + iPriority = Math::Rand(randSeed) % (iThreadData.threadPriorities[2] - iThreadData.threadPriorities[1] + 1); + iPriority += iThreadData.threadPriorities[1]; + while (priorityTable[priorityIndex] < iPriority) + { + priorityIndex++; + } + iPriority = priorityTable[priorityIndex]; + // PRINT(_L("SetPriority Random CPU %d priority %d\n"),gSMPStressDrv.GetThreadCPU(&iThread), iPriority); + iThread.SetPriority((TThreadPriority)iPriority); + break; + } + } +//Resume each thread +void CSMPSoakThread::ResumeThread() + { + iThread.Resume(); + } +//thread creation +void CSMPSoakThread::CreateThread() + { + CSMPSoakThread* smpthread = new CSMPSoakThread[KNumThreads]; + for (TInt i = 0; i < KNumThreads ; i++) + { + if(ThreadPriorityLow) + { + PRINT ((_L("Thread Table - Priority Low \n"))); + smpthread[i].DoCreateThread(&KThreadTableLow[i]); + } + else + { + PRINT ((_L("Thread Table - Priority High \n"))); + smpthread[i].DoCreateThread(&KThreadTableHigh[i]); + } + } + PRINT (_L("Resuming all threads\n")); + for (TInt i = 0; i < KNumThreads; i++) + smpthread[i].ResumeThread(); + } +/** + * CSMPSoakThread Thread Creation. + * @param aIndex to exercise each row(thread) in the thread table + * + * @return N/A + * + * @pre Initialize thread Table values + * @post None + */ +void CSMPSoakThread::DoCreateThread(TAny* aThread) + { + //Initialize each thread data + iThreadData = ((TThread*)aThread)->threadData; + test.Next(_L("Create Thread")); + PRINT ((_L("%s CPU affinity %d Priority %d\n"),((TThread*)aThread)->threadName.Ptr(),iThreadData.cpuAffinity,iThreadData.threadPriorities[0])); + TInt r = iThread.Create(((TThread*)aThread)->threadName, ((TThread*)aThread)->threadFunction, KDefaultStackSize, KHeapMinSize, KHeapMaxSize,(TAny*)this); + test_KErrNone(r); + if (iThreadData.threadPriorityChange == EPriorityList) + { + iPriority = 0; + } + else + { + iPriority = iThreadData.threadPriorities[0]; + } + iThread.SetPriority((TThreadPriority)iThreadData.threadPriorities[0]); + //Set the thread CPU Affinity + gSMPStressDrv.ChangeThreadAffinity(&iThread, iThreadData.cpuAffinity); + } +//Create Chunk - different types +void CSMPSoakThread::CreateChunk (TChunkInfo * aChunkInfo, TMemory * aMemoryTablePtr) + { + //RDebug::Print(_L("Creating chunk name %s type %d bottom %d top %d max %d\n"),aMemoryTablePtr->globalChunkName.Ptr(),aMemoryTablePtr->chunkType,aMemoryTablePtr->initialBottom,aMemoryTablePtr->initialTop,aMemoryTablePtr->maxSize); + TOwnerType ownerType = EOwnerProcess; + aChunkInfo->lastBottom = aMemoryTablePtr->initialBottom; + aChunkInfo->lastTop = aMemoryTablePtr->initialTop; + switch (aMemoryTablePtr->chunkType) + { + case EChunkNormalThread: + ownerType = EOwnerThread; // drop through to create chunk + case EChunkNormalProcess: + if (aMemoryTablePtr->globalChunkName.Length()) + { + test_KErrNone(aChunkInfo->chunk.CreateGlobal(aMemoryTablePtr->globalChunkName,aMemoryTablePtr->initialTop*gPageSize,aMemoryTablePtr->maxSize*gPageSize,ownerType)); + } + else + { + test_KErrNone(aChunkInfo->chunk.CreateLocal(aMemoryTablePtr->initialTop*gPageSize,aMemoryTablePtr->maxSize*gPageSize,ownerType)); + } + aChunkInfo->lastBottom = 0; // ensure that this is zero + break; + + case EChunkDisconnectedThread: + ownerType = EOwnerThread; // drop through to create chunk + case EChunkDisconnectedProcess: + if (aMemoryTablePtr->globalChunkName.Length()) + { + test_KErrNone(aChunkInfo->chunk.CreateDisconnectedGlobal(aMemoryTablePtr->globalChunkName,aMemoryTablePtr->initialBottom*gPageSize,aMemoryTablePtr->initialTop*gPageSize,aMemoryTablePtr->maxSize*gPageSize,ownerType)); + } + else + { + test_KErrNone(aChunkInfo->chunk.CreateDisconnectedLocal(aMemoryTablePtr->initialBottom*gPageSize,aMemoryTablePtr->initialTop*gPageSize,aMemoryTablePtr->maxSize*gPageSize,ownerType)); + } + break; + + case EChunkDoubleEndedThread: + ownerType = EOwnerThread; // drop through to create chunk + case EChunkDoubleEndedProcess: + if (aMemoryTablePtr->globalChunkName.Length()) + { + test_KErrNone(aChunkInfo->chunk.CreateDoubleEndedGlobal(aMemoryTablePtr->globalChunkName,aMemoryTablePtr->initialBottom*gPageSize,aMemoryTablePtr->initialTop*gPageSize,aMemoryTablePtr->maxSize*gPageSize,ownerType)); + } + else + { + test_KErrNone(aChunkInfo->chunk.CreateDoubleEndedLocal(aMemoryTablePtr->initialBottom*gPageSize,aMemoryTablePtr->initialTop*gPageSize,aMemoryTablePtr->maxSize*gPageSize,ownerType)); + } + break; + } + } +//Commit chunk +void CSMPSoakThread::CommitChunk (TChunkInfo * aChunkInfo, TMemory * aMemoryTablePtr) + { + TInt commitPages; + + switch (aMemoryTablePtr->chunkType) + { + case EChunkNormalThread: + case EChunkNormalProcess: + if (aChunkInfo->lastTop < (aMemoryTablePtr->maxSize - 1)) + { + aChunkInfo->lastTop += (aMemoryTablePtr->maxSize - 1 - aChunkInfo->lastTop) / 2 + 1; + //PRINT(_L("Adjust chunk memory - top %d pagesize %d\n"),aChunkInfo->lastTop,gPageSize); + test_KErrNone(aChunkInfo->chunk.Adjust(aChunkInfo->lastTop*gPageSize)); + } + break; + + case EChunkDisconnectedThread: + case EChunkDisconnectedProcess: + commitPages = ((aChunkInfo->lastTop - aChunkInfo->lastBottom) / 2) + 1; + //PRINT(_L("Decommitting from bottom %d of %d pages\n"),aChunkInfo->lastBottom,commitPages); + test_KErrNone(aChunkInfo->chunk.Decommit(aChunkInfo->lastBottom*gPageSize,commitPages * gPageSize)); + if ((aChunkInfo->lastBottom > 0) && (aChunkInfo->lastTop <= aMemoryTablePtr->initialTop)) + { + aChunkInfo->lastTop = aChunkInfo->lastBottom + commitPages - 1; + aChunkInfo->lastBottom /= 2; + commitPages = aChunkInfo->lastTop - aChunkInfo->lastBottom + 1; + } + else + { + if (aChunkInfo->lastTop < (aMemoryTablePtr->maxSize -1)) + { + if (aChunkInfo->lastTop <= aMemoryTablePtr->initialTop) + { + aChunkInfo->lastBottom = aMemoryTablePtr->initialTop + 1; + } + else + { + aChunkInfo->lastBottom = aChunkInfo->lastTop + 1; + } + commitPages = ((aMemoryTablePtr->maxSize - aChunkInfo->lastBottom) / 2) + 1; + aChunkInfo->lastTop = aChunkInfo->lastBottom + commitPages - 1; + } + else + { + commitPages = 0; + } + } + if (commitPages) + { + //PRINT(_L("Commit chunk memory bottom %d size %d pages\n"),aChunkInfo->lastBottom,commitPages); + test_KErrNone(aChunkInfo->chunk.Commit(aChunkInfo->lastBottom*gPageSize,commitPages*gPageSize)); + } + break; + + case EChunkDoubleEndedThread: + case EChunkDoubleEndedProcess: + if (aChunkInfo->lastBottom > 0 || aChunkInfo->lastTop < (aMemoryTablePtr->maxSize - 1)) + { + if (aChunkInfo->lastBottom > 0) + { + aChunkInfo->lastBottom--; + } + if (aChunkInfo->lastTop < (aMemoryTablePtr->maxSize - 1)) + { + aChunkInfo->lastTop++; + } + // PRINT(_L("Adjust Double Ended bottom %d top %d\n"),aChunkInfo->lastBottom,aChunkInfo->lastTop); + test_KErrNone(aChunkInfo->chunk.AdjustDoubleEnded(aChunkInfo->lastBottom*gPageSize,aChunkInfo->lastTop*gPageSize)); + } + break; + } + } +//Write then read chunk +void CSMPSoakThread::WriteReadChunk (TChunkInfo * aChunkInfo, TMemory * aMemoryTablePtr) + { + if (aChunkInfo->lastTop < (aMemoryTablePtr->maxSize - 1)) + { + TInt chunkSize = aChunkInfo->lastTop*gPageSize - aChunkInfo->lastBottom*gPageSize; + //RDebug::Print(_L("WriteReadChunk Last Top %d lastBottom %d\n"),aChunkInfo->lastTop,aChunkInfo->lastBottom); + TUint8 *writeaddr = aChunkInfo->chunk.Base()+ aChunkInfo->lastBottom*gPageSize; + TPtr8 write(writeaddr,chunkSize); + write.Copy(pattern,sizeof(pattern)); + test_KErrNone(Mem::Compare(writeaddr,sizeof(pattern),pattern,sizeof(pattern))); + } + } +//Memory Thread : will do memory associated operation +//param aSmp - CSMPSoakUtil pointer +TInt CSMPSoakThread::SMPStressMemoryThread(TAny* aSmp) + { + CSMPSoakThread* self = (CSMPSoakThread*)aSmp; + __ASSERT_ALWAYS(self !=NULL, User::Panic(_L("CSMPSoakThread::SMPStressMemoryThread Panic"),0)); + return self->DoSMPStressMemoryThread(); + } +// Member for thread function +TInt CSMPSoakThread::DoSMPStressMemoryThread() + { + RTest test(_L("SMPStressMemoryThread")); + + TMemory *memoryTablePtr; + TChunkInfo chunkTable[KNumChunks]; + TInt ctIndex = 0; + test_KErrNone(UserHal::PageSizeInBytes(gPageSize)); + + FOREVER + { + SetThreadPriority(); + + if (gAbort) + break; + + memoryTablePtr = (TMemory *) (iThreadData.listPtr); + ctIndex = 0; + + //Create different type of chunks and write/read/verfiy it + while (memoryTablePtr->chunkType != EChunkNone) + { + PRINT((_L("Create Chunk"))); + CreateChunk (&chunkTable[ctIndex],memoryTablePtr); + + PRINT(_L("Write and Read Chunk")); + WriteReadChunk (&chunkTable[ctIndex],memoryTablePtr); + + ctIndex++; + memoryTablePtr++; + } + + //Commit different type of chunks + TBool anyCommit; + do + { + anyCommit = EFalse; + memoryTablePtr = (TMemory *) (iThreadData.listPtr); + ctIndex = 0; + while (memoryTablePtr->chunkType != EChunkNone) + { + //Commit Chunks + PRINT((_L("Commit Chunk Memory"))); + PRINT ((_L("CommitChunk %d bottom %d top %d\n"),ctIndex,memoryTablePtr->initialBottom,memoryTablePtr->initialTop)); + CommitChunk (&chunkTable[ctIndex],memoryTablePtr); + anyCommit = ETrue; + + //Write into Chunks + WriteReadChunk (&chunkTable[ctIndex],memoryTablePtr); + PRINT((_L("Write Read Chunk Size %d\n"), (memoryTablePtr->initialTop) - (memoryTablePtr->initialBottom))); + ctIndex++; + memoryTablePtr++; + } + } + while (anyCommit); + + //Close the Chunks + memoryTablePtr = (TMemory *) (iThreadData.listPtr); + ctIndex = 0; + while (memoryTablePtr->chunkType != EChunkNone) + { + chunkTable[ctIndex].chunk.Close(); + + ctIndex++; + memoryTablePtr++; + } + User::After(gPeriod); + } + return 0x00; + } +//Device Thread : will do device associated operation +//param aSmp - CSMPSoakUtil pointer +TInt CSMPSoakThread::SMPStressDeviceThread(TAny* aSmp) + { + CSMPSoakThread* self = (CSMPSoakThread*)aSmp; + __ASSERT_ALWAYS(self !=NULL, User::Panic(_L("CSMPSoakThread::SMPStressDeviceThread Panic"),0)); + return self->DoSMPStressDeviceThread(); + } +// Member for thread function +TInt CSMPSoakThread::DoSMPStressDeviceThread() + { + RTest test(_L("SMPStressDeviceThread")); + + RTimer timer; + RFs session; + TFileName sessionPath; + + test_KErrNone(timer.CreateLocal()); + TRequestStatus s; + + TDesC** ptrDevices = (TDesC**) (iThreadData.listPtr); + PRINT ((_L("Devices Number %d [%s]\n"), ptrDevices[0]->Length(), ptrDevices[0]->Ptr())); + for (TInt i = 1; ptrDevices[i] ; i++) + PRINT ((_L("LDD%d=%s "),i,ptrDevices[i]->Ptr())); + PRINT (_L("\n")); + + FOREVER + { + for (TInt i = 0; i < ptrDevices[0]->Length(); i++) + { + TText driveLetter = (*ptrDevices[0])[i]; + PRINT ((_L("Device %c\n"),driveLetter)); + + test_KErrNone(session.Connect()); + + sessionPath=(_L("?:\\SESSION_TEST\\")); + sessionPath[0]=driveLetter; + test_KErrNone(session.SetSessionPath(sessionPath)); + + TInt driveNumber; + test_KErrNone(session.CharToDrive(driveLetter, driveNumber)); + + TBuf<64> fileSystemName; + test_KErrNone(session.FileSystemName(fileSystemName,driveNumber)); + + PRINT ((_L("File System Name %s\n"),fileSystemName.PtrZ())); + + TDriveInfo driveInfo; + test_KErrNone(session.Drive(driveInfo, driveNumber)); + + TVolumeInfo volumeInfo; + test_KErrNone(session.Volume(volumeInfo, driveNumber)); + + session.Close(); + } + for (TInt i = 1; ptrDevices[i] ; i += 2) + { + RDevice device; + + TInt r = User::LoadLogicalDevice(*ptrDevices[i]); + test(r == KErrNone || r == KErrAlreadyExists); + + test_KErrNone(device.Open(*ptrDevices[i+1])); + + TBuf8<64> deviceCaps; + device.GetCaps(deviceCaps); + + TVersion deviceVersion; + device.QueryVersionSupported(deviceVersion); + + device.Close(); + } + SetThreadPriority(); + timer.After(s, iThreadData.delayTime*1000); + User::WaitForRequest(s); + test (s == KErrNone); + + if (gAbort) + break; + User::After(gPeriod); + } + timer.Close(); + PRINT((_L("SMPStressDeviceThread MyTimer.Cancel() called\n"))); + return 0x00; + } +//Spin Thread : will do thread sync +//param aSmp - CSMPSoakUtil pointer +TInt CSMPSoakThread::SMPStressSpinThread(TAny* aSmp) + { + CSMPSoakThread* self = (CSMPSoakThread*)aSmp; + __ASSERT_ALWAYS(self !=NULL, User::Panic(_L("CSMPSoakThread::SMPStressSpinThread Panic"),0)); + return self->DoSMPStressSpinThread(); + } +// Member for thread function +TInt CSMPSoakThread::DoSMPStressSpinThread() + { + RTest test(_L("SMPStressSpinThread")); + + TTime startTime; + TTime endTime; + TTimeIntervalMicroSeconds loopTimeMicroSeconds; + PRINT (_L("SMPStressSpinThread\n")); + FOREVER + { + SetThreadPriority(); + gSwitchSem.Wait(); + startTime.UniversalTime(); + do + { + endTime.UniversalTime(); + loopTimeMicroSeconds = endTime.MicroSecondsFrom(startTime); + }while (loopTimeMicroSeconds <= iThreadData.delayTime*1000); + + if (gAbort) + break; + User::After(gPeriod); + } + return 0x00; + } +//Timer Thread : Timer operation and thread sync +//param aSmp - CSMPSoakUtil pointer +TInt CSMPSoakThread::SMPStressTimerThread(TAny* aSmp) + { + CSMPSoakThread* self = (CSMPSoakThread*)aSmp; + __ASSERT_ALWAYS(self !=NULL, User::Panic(_L("CSMPSoakThread::SMPStressTimerThread Panic"),0)); + return self->DoSMPStressTimerThread(); + } +// Member for thread function +TInt CSMPSoakThread::DoSMPStressTimerThread() + { + RTest test(_L("SMPStressTimerThread")); + + PRINT (_L("SMPStressTimerThread\n")); + RTimer timer; + test_KErrNone(timer.CreateLocal()); + TRequestStatus s; + + FOREVER + { + timer.After(s, iThreadData.delayTime*1000); + User::WaitForRequest(s); + test (s == KErrNone); + PRINT ((_L("*"))); + gSwitchSem.Signal(iThreadData.numThreads); + + if (gAbort) + break; + User::After(gPeriod); + } + timer.Cancel(); + PRINT((_L("SMPStressTimerThread MyTimer.Cancel() called\n"))); + return 0x00; + } +// CActive class to monitor KeyStrokes from User +class CActiveConsole : public CActive + { +public: + CActiveConsole(); + ~CActiveConsole(); + void GetCharacter(); + static TInt Callback(TAny* aCtrl); + static CPeriodic* TimerL(); +private: + // Defined as pure virtual by CActive; + // implementation provided by this class. + virtual void DoCancel(); + // Defined as pure virtual by CActive; + // implementation provided by this class, + virtual void RunL(); + void ProcessKeyPressL(TChar aChar); +private: + + }; +// Class CActiveConsole +CActiveConsole::CActiveConsole() + : CActive(EPriorityHigh) + { + CActiveScheduler::Add(this); + } + +CActiveConsole::~CActiveConsole() + { + Cancel(); + } +CPeriodic* CActiveConsole::TimerL() + { + return(CPeriodic::NewL(EPriorityNormal)); + } +// Callback function for timer expiry +TInt CActiveConsole::Callback(TAny* aControl) + { + return KErrNone; + } + +void CActiveConsole::GetCharacter() + { + test.Console()->Read(iStatus); + SetActive(); + } + +void CActiveConsole::DoCancel() + { + PRINT(_L("CActiveConsole::DoCancel\n")); + test.Console()->ReadCancel(); + } + +void CActiveConsole::ProcessKeyPressL(TChar aChar) + { + if (aChar == EKeyEscape) + { + PRINT(_L("CActiveConsole: ESC key pressed -> stopping active scheduler...\n")); + gAbort = ETrue; + CActiveScheduler::Stop(); + return; + } + aChar.UpperCase(); + GetCharacter(); + } + +void CActiveConsole::RunL() + { + ProcessKeyPressL(static_cast(test.Console()->KeyCode())); + } + +// CActiveTimer class to monitor timeout expiry +class CActiveTimer : public CActive + { +public: + CActiveTimer(); + ~CActiveTimer(); + void Delay(TTimeIntervalMicroSeconds32 aDelay); +private: + RTimer iTimer; + // Defined as pure virtual by CActive; + // implementation provided by this class. + virtual void DoCancel(); + // Defined as pure virtual by CActive; + // implementation provided by this class, + virtual void RunL(); + + }; +// Class CActiveConsole +CActiveTimer::CActiveTimer() + : CActive(EPriorityHigh) + { + CActiveScheduler::Add(this); + User::LeaveIfError(iTimer.CreateLocal()); + } + +CActiveTimer::~CActiveTimer() + { + Cancel(); + iTimer.Close(); + } + + +void CActiveTimer::Delay(TTimeIntervalMicroSeconds32 aDelay) + { + iTimer.After(iStatus, aDelay); + SetActive(); + } + +void CActiveTimer::DoCancel() + { + iTimer.Cancel(); + } + +void CActiveTimer::RunL() + { + PRINT(_L("CActiveTimer: Application runtime expired...")); + gAbort = ETrue; + CActiveScheduler::Stop(); + return; + } + +//T_SMPSOAK Entry Point +TInt E32Main() + { + test.Title(); + __UHEAP_MARK; + test.Start(_L("t_smpsoak.exe")); + + // When running as a stand alone test, + // there needs to be a timeout + timeout = ETrue; + + ParseCommandLine(); + if (gAbort) + return 0x00; + + PRINT (_L("Load device driver\n")); + TInt r = User::LoadLogicalDevice(_L("d_smpsoak.ldd")); + if (r == KErrNotFound) + { + PRINT (_L("Test not supported on this platform because the D_SMPSOAK.LDD Driver is Not Present\n")); + test(EFalse); + } + PRINT (_L("Calling SMPStressDrv Open\n")); + r = gSMPStressDrv.Open(); + test_KErrNone(r); + + PRINT (_L("Creating our local semaphore\n")); + r=gSwitchSem.CreateLocal(0); + test_KErrNone(r); + + CSMPSoakThread smpthread; + PRINT ((_L("Creating all threads =%d\n"),KNumThreads)); + smpthread.CreateThread(); + + CSMPSoakThread *smpprocess= new CSMPSoakThread[NumProcess]; + PRINT ((_L("Creating all process =%d\n"),NumProcess)); + for (TInt i = 0; i < NumProcess; i++) + smpprocess[i].CreateChildProcess(i); + + PRINT (_L("Resuming all process \n")); + for (TInt i = 0; i < NumProcess; i++) + smpprocess[i].ResumeChildProcess(); + + PRINT (_L("Starting ActiveScheduler\n")); + test.Next(_L("Press ESC Key to Shutdown SMPSoak...\n")); + CActiveScheduler* myScheduler = new (ELeave) CActiveScheduler(); + test(myScheduler != NULL); + CActiveScheduler::Install(myScheduler); + + CPeriodic* theTimer=NULL; + TRAPD(ret,theTimer=CActiveConsole::TimerL()) + test_KErrNone(ret); + theTimer->Start(0,KTimerPeriod,TCallBack(CActiveConsole::Callback)); + if(timeout) + { + CActiveTimer* myActiveTimer = new CActiveTimer(); + test(myActiveTimer != NULL); + myActiveTimer->Delay(gTimeout*1000000); + } + CActiveConsole* myActiveConsole = new CActiveConsole(); + test(myActiveConsole != NULL); + myActiveConsole->GetCharacter(); + CActiveScheduler::Start(); + if (gAbort) + { + PRINT (_L("gAbort TRUE \n")); + for (TInt i = 0; i < NumProcess; i++) + smpprocess[i].TerminateChildProcess(); + delete[] smpprocess; + delete theTimer; + gSMPStressDrv.Close(); + gSwitchSem.Close(); + return 0; + } + __UHEAP_MARKEND; + test.End(); + return 0; + } +void ParseCommandLine() + { + TBuf<256> args; + User::CommandLine(args); + TLex lex(args); + PRINT ((_L("****Command line = %s\n"), args.PtrZ())); + + FOREVER + { + TPtrC token=lex.NextToken(); + if(token.Length()!=0) + { + if (token.Length()==0) + break; // ignore trailing whitespace + else if (token.Mid(0) == _L("-h")) + { + PRINT (_L("T_SMPSOAK.EXE Usage Options:\n")); + PRINT (_L("Type t_smpsoak.exe -h\n")); + ShowHelp(); + gAbort = ETrue; + break; + } + else if (token.Mid(0) == _L("-l")) + { + //Read OOM entry from KProcessTable and run + test.Printf(_L("SMPSOAK:lowmem\n")); + NumProcess = KNumProcess+1; + break; + } + else if (token.Mid(0) == _L("-b")) + { + test.Printf(_L("SMPSOAK: Test Silent Mode\n")); + ThreadPriorityLow = ETrue; + TestSilent = ETrue; + // If we have tests running in the background + // we want an endless loop + timeout = EFalse; + break; + } + else if (token.Left(2) == _L("-t")) + { + test.Printf(_L("SMPSOAK:Timeout\n")); + lex.SkipSpaceAndMark(); + token.Set(lex.NextToken()); + TLex lexNum(token); + lexNum.Val(gTimeout,EDecimal); + test.Printf(_L("Timeout in Seconds=%u \n"),gTimeout); + timeout = ETrue; + break; + } + else if (token.Left(2) == _L("-p")) + { + test.Printf(_L("SMPSOAK:period\n")); + lex.SkipSpaceAndMark(); + token.Set(lex.NextToken()); + TLex lexNum(token); + lexNum.Val(gPeriod,EDecimal); + test.Printf(_L("period in mSeconds=%d \n"),gPeriod); + Period = ETrue; + break; + } + else + { + test.Printf(_L("Error- Invalid SMPSOAK CMD Line Argument")); + break; + } + } + break; + } + }