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) 2006-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\smp_demo\smp_demo.cpp
// Demonstration for SMP
//
//
#include <e32test.h>
#include <u32hal.h>
#include <e32svr.h>
#include <f32file.h>
#include <hal.h>
#include <e32math.h>
RTest test(_L("SMP_DEMO"));
#define DEBUG_PRINT(__args) test.Printf __args ;
TBool TestThreadsExit = EFalse;
_LIT(KTestBlank, "");
//#define LOCK_TYPE RMutex
//#define LOCK_TYPE_CREATE_PARAM
#define LOCK_TYPE RFastLock
#define LOCK_TYPE_CREATE_PARAM
//#define LOCK_TYPE RSemaphore
//#define LOCK_TYPE_CREATE_PARAM 0
#define MAX_THREADS 8
#define MAX_CHAPTERS 28
TUint8 TestGuess[MAX_THREADS];
TInt TestGuessReady[MAX_THREADS];
LOCK_TYPE TestGuessLock[MAX_THREADS];
TInt TestGuessChanged[MAX_THREADS];
LOCK_TYPE TestChangedLock[MAX_THREADS];
TUint8 TestNext[MAX_THREADS];
TUint TestGuessMisses[MAX_THREADS];
TUint TestGuessCorrect[MAX_THREADS];
TUint TestGuessIncorrect[MAX_THREADS];
TUint TestGuessCollision[MAX_THREADS];
TInt TestCpuCount = 0;
TBool TestUseMathRandom = ETrue;
TBool TestSingleCpu = EFalse;
TBool TestDualCpu = EFalse;
TBool TestNoPrint = EFalse;
TBool TestSingleThread = EFalse;
TBool TestUseAffinity = ETrue;
TInt LoadChapter(TInt chapterIndex, HBufC8 **aChapterPtrPtr)
{
RFile file;
RFs fs;
if (KErrNone != fs.Connect())
{
DEBUG_PRINT(_L("LoadChapter : Can't connect to the FS\n"));
return KErrGeneral;
}
TBuf<32> filename;
filename.Format(_L("z:\\Test\\war_and_peace_ch%d.txt"), chapterIndex);
TInt ret = file.Open(fs,filename,EFileRead);
if (ret == KErrNone)
{
TInt fileSize = 0;
ret = file.Size(fileSize);
if (ret == KErrNone)
{
HBufC8 *theBuf = HBufC8::New(fileSize + 10);
if (theBuf != NULL)
{
TPtr8 des2=theBuf->Des();
ret = file.Read((TInt)0, des2,fileSize);
if (ret == KErrNone)
{
*aChapterPtrPtr = theBuf;
}
else
{
DEBUG_PRINT((_L("LoadChapter : Read Failed for %S of %d\n"), &filename, fileSize));
}
}
else
{
DEBUG_PRINT((_L("LoadChapter : Buffer Alloc Failed for %S\n"), &filename));
}
}
else
{
DEBUG_PRINT((_L("LoadChapter : Size Failed for %S\n"), &filename));
}
file.Close();
}
else
{
DEBUG_PRINT((_L("LoadChapter : Open Failed for %S\n"), &filename));
}
return ret;
}
TInt SetCpuAffinity(TInt aThreadId)
{
if (TestUseAffinity)
{
TUint32 cpu;
if (TestCpuCount == 4)
cpu = (TUint32)(aThreadId % 3) + 1;
else if (TestCpuCount == 2)
cpu = (TUint32)1;
else
cpu = 0;
TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0);
test(r==KErrNone);
return r;
}
return KErrNone;
}
LOCAL_C TInt DemoThread(TAny* aUseTb)
{
TInt threadId = (TInt)aUseTb;
SetCpuAffinity(threadId);
User::After(100);
TestGuessChanged[threadId] = EFalse;
TestGuessReady[threadId] = EFalse;
TestGuessMisses[threadId] = 0;
TestGuessCorrect[threadId] = 0;
TestGuessIncorrect[threadId] = 0;
TestGuessCollision[threadId] = 0;
TUint8 guess = 0;
TUint8 nextChar = TestNext[threadId];
TBool correct = EFalse;
while (!TestThreadsExit)
{
correct = EFalse;
if (TestUseMathRandom)
guess = (TUint8)Math::Random();
else
guess ++;
if (TestGuessChanged[threadId])
{
TestChangedLock[threadId].Wait();
nextChar = TestNext[threadId];
TestGuessChanged[threadId] = EFalse;
TestChangedLock[threadId].Signal();
}
correct = (nextChar == guess);
if (correct)
{
if (TestGuessReady[threadId] == EFalse)
{
TestGuessLock[threadId].Wait();
TestGuess[threadId] = guess;
TestGuessReady[threadId] = ETrue;
TestGuessLock[threadId].Signal();
TestGuessCorrect[threadId] ++;
}
else
{
TestGuessMisses[threadId] ++;
}
}
else
{
TestGuessIncorrect[threadId] ++;
}
if (TestCpuCount == 1)
{
User::After(0);
}
}
return KErrNone;
}
TInt NumberOfCpus()
{
TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
test(r>0);
return r;
}
TInt ParseArgs(void)
{
TBuf<256> args;
User::CommandLine(args);
TLex lex(args);
FOREVER
{
TPtrC token=lex.NextToken();
if(token.Length()!=0)
{
if (token == _L("unbound"))
{
TestUseMathRandom = EFalse;
}
if (token == _L("single"))
{
TestSingleCpu = ETrue;
}
if (token == _L("dual"))
{
TestDualCpu = ETrue;
}
if (token == _L("silent"))
{
TestNoPrint = ETrue;
}
if (token == _L("onethread"))
{
TestSingleCpu = ETrue;
TestSingleThread = ETrue;
}
if (token == _L("help"))
{
test.Printf(_L("smp_demo: unbound | single | onethread | silent | dual | noaffinity | help \n"));
return -1;
}
if (token == _L("noaffinity"))
{
TestUseAffinity = EFalse;
}
}
else
{
break;
}
}
return KErrNone;
}
TInt E32Main()
{
test.Title();
test.Start(_L("SMP Demonstration guessing War and Peace...."));
if (ParseArgs() != KErrNone)
{
test.Getch();
test.End();
return KErrNone;
}
TUint start = User::TickCount();
TInt tickPeriod = 0;
HAL::Get(HAL::ESystemTickPeriod, tickPeriod);
if (TestSingleCpu)
{
TestCpuCount = 1;
}
else if (TestDualCpu)
{
TestCpuCount = 2;
}
else
{
TestCpuCount = NumberOfCpus();
}
DEBUG_PRINT((_L("CPU Count %d\n"), TestCpuCount));
TRequestStatus theStatus[MAX_THREADS];
RThread theThreads[MAX_THREADS];
TBool threadInUse[MAX_THREADS];
TInt index;
TInt maxChapters = MAX_CHAPTERS;
if (TestUseMathRandom)
{
maxChapters = 2;
}
TInt maxIndex = TestCpuCount - 1;
if (maxIndex == 0)
{
maxChapters = 2;
maxIndex = 1;
}
else if ((maxIndex == 1) && (TestUseMathRandom))
{
maxChapters = 4;
}
TInt ret;
TUint32 cpu = 0;
if (TestUseAffinity)
{
UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0);
}
if (TestSingleThread)
{
TInt chapterIndex;
TUint8 guess = 0;
maxChapters = MAX_CHAPTERS;
TRequestStatus keyStatus;
CConsoleBase* console=test.Console();
console->Read(keyStatus);
for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++)
{
HBufC8 *chapterPtr = NULL;
ret = LoadChapter(chapterIndex + 1, &chapterPtr);
if ((ret != KErrNone) || (chapterPtr == NULL))
{
DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret));
}
else
{
TPtr8 theDes = chapterPtr->Des();
TUint8 *pData = (TUint8 *)theDes.Ptr();
TInt dataLength = chapterPtr->Length();
while (dataLength > 0)
{
if (TestUseMathRandom)
guess = (TUint8)Math::Random();
else
guess ++;
if (*pData == guess)
{
pData ++;
dataLength --;
if (!TestNoPrint)
{
test.Printf(_L("%c"), (TUint8)guess);
}
}
if (keyStatus != KRequestPending)
{
if (console->KeyCode() == EKeyEscape)
{
TestThreadsExit = ETrue;
break;
}
console->Read(keyStatus);
}
}
// clean up
delete chapterPtr;
test.Printf(_L("\n\n"));
if (TestThreadsExit)
{
break;
}
}
}
console->ReadCancel();
test.Printf(_L("Finished after %d chapters!\n"),chapterIndex);
}
else
{
for (index = 0; index < maxIndex; index ++)
{
TestGuessLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM);
TestChangedLock[index].CreateLocal(LOCK_TYPE_CREATE_PARAM);
ret = theThreads[index].Create(KTestBlank,DemoThread,KDefaultStackSize,NULL,(TAny*) index);
if (ret == KErrNone)
{
theThreads[index].Logon(theStatus[index]);
if (theStatus[index] != KRequestPending)
{
DEBUG_PRINT((_L("E32Main: !KRequestPending %d\n"), theStatus[index].Int() ));
}
theThreads[index].Resume();
threadInUse[index] = ETrue;
DEBUG_PRINT((_L("E32Main: starting thread %d %d\n"), index, index % TestCpuCount));
}
else
{
DEBUG_PRINT((_L("E32Main: Create thread failed %d\n"), ret));
return KErrGeneral;
}
}
TInt chapterIndex;
TInt index2;
TRequestStatus keyStatus;
CConsoleBase* console=test.Console();
console->Read(keyStatus);
for (chapterIndex = 0; chapterIndex < maxChapters; chapterIndex ++)
{
HBufC8 *chapterPtr = NULL;
ret = LoadChapter(chapterIndex + 1, &chapterPtr);
if ((ret != KErrNone) || (chapterPtr == NULL))
{
DEBUG_PRINT((_L("E32Main: LoadChapter failed %d\n"), ret));
}
else
{
TPtr8 theDes = chapterPtr->Des();
TUint8 *pData = (TUint8 *)theDes.Ptr();
TInt dataLength = chapterPtr->Length();
for (index2 = 0; index2 < maxIndex; index2 ++)
{
TestChangedLock[index2].Wait();
TestGuessChanged[index2] = ETrue;
TestNext[index2] = (TUint8)*pData;
TestChangedLock[index2].Signal();
}
// where the real code goes!!
TUint8 guess = 0;
TBool wasReady = EFalse;
while (dataLength > 0)
{
for (index = 0; index < maxIndex; index ++)
{
wasReady = EFalse;
if (TestGuessReady[index])
{
wasReady = ETrue;
TestGuessLock[index].Wait();
guess = (TUint8)TestGuess[index];
TestGuessReady[index] = EFalse;
TestGuessLock[index].Signal();
}
if (wasReady)
{
if (*pData == guess)
{
pData ++;
dataLength --;
for (index2 = 0; index2 < maxIndex; index2 ++)
{
TestChangedLock[index2].Wait();
TestNext[index2] = (TUint8)*pData;
TestGuessChanged[index2] = ETrue;
TestChangedLock[index2].Signal();
}
if (!TestNoPrint)
{
test.Printf(_L("%c"), (TUint8)guess);
}
}
else
{
TestGuessCollision[index] ++;
}
}
if (TestCpuCount == 1)
{
User::After(0);
}
}
if (keyStatus != KRequestPending)
{
if (console->KeyCode() == EKeyEscape)
{
TestThreadsExit = ETrue;
break;
}
console->Read(keyStatus);
}
}
// clean up
delete chapterPtr;
test.Printf(_L("\n\n"));
if (TestThreadsExit)
{
break;
}
}
}
console->ReadCancel();
test.Printf(_L("Finished after %d chapters!\n"),chapterIndex);
for (index = 0; index < maxIndex; index ++)
{
test.Printf(_L("Thread %d stalls %u correct %u incorrect %u collision %u\n"), index, TestGuessMisses[index],TestGuessCorrect[index],TestGuessIncorrect[index], TestGuessCollision[index]);
}
// real code ends!!
TestThreadsExit = ETrue;
TBool anyUsed = ETrue;
while(anyUsed)
{
anyUsed = EFalse;
for (index = 0; index < maxIndex; index++)
{
if (threadInUse[index])
{
if (theThreads[index].ExitType() != EExitPending)
{
threadInUse[index] = EFalse;
TestGuessLock[index].Close();
TestChangedLock[index].Close();
}
else
{
anyUsed = ETrue;
}
}
}
}
}
TUint time = TUint((TUint64)(User::TickCount()-start)*(TUint64)tickPeriod/(TUint64)1000000);
test.Printf(_L("Complete in %u seconds\n"), time);
test.Getch();
test.End();
return KErrNone;
}