kerneltest/e32test/smpsoak/t_smpsoak.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 136 743008598095
parent 36 538db54a451d
child 252 0a40b8675b23
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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 <e32hal.h>
#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<TChar>(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;
		}
	}