// Copyright (c) 2001-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:
//
// INCLUDES
#include "ctlbsclientpostp208.h"
#include <EPos_CPosModules.h>
#include <EPos_CPosModuleUpdate.h>
#include <EPos_CPosModuleIdList.h>
// CONSTANTS
static const TInt KNrOfClients = 5;
static const TInt KNrOfRuns = 20;
static const TInt KServerMinHeapSize = 4096;
static const TInt KServerMaxHeapSize = 128000;
_LIT(KThread2Name, "req_location1");
_LIT(KThread3Name, "req_location2");
_LIT(KErrMsgThreadCreation, "failed to create thread");
// ================= MEMBER FUNCTIONS =======================
// Constructor.
CT_LbsClientPosTp208::CT_LbsClientPosTp208(CT_LbsServer& aParent): CT_LbsPortedStepBase(aParent)
{
_LIT(KTestName, "TP208-Multi Thread Connection");
SetTestStepName(KTestName);
}
// ---------------------------------------------------------
// Destructor.
// ---------------------------------------------------------
CT_LbsClientPosTp208::~CT_LbsClientPosTp208()
{
}
// ---------------------------------------------------------
// CPosTp208::CloseTest
// Always called after the test, even if the test leaves
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CT_LbsClientPosTp208::CloseTest()
{
ClosePositioner();
Disconnect();
}
// Struct passed to the thread in a TAny*
struct MyAnyData
{
TBool iFullTest; // If fulltest defined
TInt iNrOfRuns; // number if requests to make for each thread
};
//
// Performes the test by connecting to MLFW
// (and makes a number of Location requests if aFullTest is true
//
void DoTestL(TBool aFullTest, TInt aNumberOfRuns, TInt *aResult)
{
RPositionServer posServer;
TInt errorCode = errorCode = posServer.Connect();
if (errorCode != KErrNone)
{
*aResult = KErrCouldNotConnect;
return;
}
CleanupClosePushL(posServer);
RPositioner positioner;
// Full test means requesting position updates
if (aFullTest)
{
TPositionInfo positionInfo = TPositionInfo();
const TInt32 KUidMultiPsy = 0x01010176;
TUid uidMultiPsy;
uidMultiPsy.iUid = KUidMultiPsy;
errorCode = positioner.Open(posServer, uidMultiPsy);
if (errorCode != KErrNone)
{
*aResult = errorCode;
return;
}
CleanupClosePushL(positioner);
_LIT(KService ,"Service");
errorCode = positioner.SetRequestor(CRequestor::ERequestorService,
CRequestor::EFormatApplication, KService);
if (errorCode != KErrNone)
{
*aResult = 1001;
return;
}
TRequestStatus status;
TLocality loca(TCoordinate(0,0,0),0);
TPosition pos(loca, TTime(0));
for (TInt i = 0; i < aNumberOfRuns; i++)
{
positionInfo.SetPosition(pos);
positioner.NotifyPositionUpdate(positionInfo, status);
User::WaitForRequest(status);
TInt err = status.Int();
if (err != KErrNone)
{
*aResult = err;
}
TPosition result;
positionInfo.GetPosition(result);
//sanity check
if (result.Latitude() == pos.Latitude() ||
result.Longitude() == pos.Longitude() ||
result.Altitude() == pos.Altitude())
{
//_LIT(KErrorPositon, "ERROR:: The postion was not updated");
errorCode = 1005;
}
}
positioner.Close();
CleanupStack::PopAndDestroy(&positioner);
}
posServer.Close();
CleanupStack::PopAndDestroy(&posServer);
}
// ---------------------------------------------------------
// LOCAL_C TInt MyThreadFunctionL(TAny* aData)
// Runs the DoTestL in a TRAP nest
// Panics this thread if any errors occurred
// ---------------------------------------------------------
//
LOCAL_C TInt MyThreadFunctionL(TAny* aData)
{
__UHEAP_MARK;
CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack
// Read parameters from TAny*
MyAnyData* info = (MyAnyData*) aData;
TInt result = KErrNone;
TInt err = KErrNone;
// Why must this function be TRAPPED?
TRAP(err, DoTestL(info->iFullTest, info->iNrOfRuns, &result));
_LIT(KErrorConnect, "Error when connecting to RPositionServer");
__ASSERT_ALWAYS(!err, User::Panic(KErrorConnect, err));
__ASSERT_ALWAYS(result == KErrNone, User::Panic(KErrorConnect, result));
delete cleanup; // destroy clean-up stack
__UHEAP_MARKEND;
return 0;
}
// ---------------------------------------------------------
// CPosTp208::StartThreads
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CT_LbsClientPosTp208::StartThreads(TBool aFullTest)
{
TFixedArray<TRequestStatus, KNrOfClients> statusArray;
TFixedArray<RThread, KNrOfClients> threadArray;
TFixedArray<TInt, KNrOfClients> retArray;
TBuf<150> buf;
TInt errorsFound = KErrNone;
_LIT(KInfoCreate, "Creating threads");
INFO_PRINTF1(KInfoCreate);
_LIT(KThreadName, "Thread %d");
// Introduce parameters for each thread.
MyAnyData info;
info.iNrOfRuns = KNrOfRuns;
info.iFullTest = aFullTest;
// Make sure that if one of the threads panic, whole emulator is not
// paniced (this has effect only in Wins).
TBool jit = User::JustInTime();
User::SetJustInTime(EFalse);
TInt i=0;
for (i=0; i<KNrOfClients; i++)
{
iThreadCount++;
buf.Zero();
buf.Format(KThreadName, iThreadCount);
retArray[i] = threadArray[i].Create(buf, MyThreadFunctionL, KDefaultStackSize, KServerMinHeapSize, KServerMaxHeapSize, &info);
if (retArray[i] != KErrNone)
{
_LIT(KErr, "Error when creating thread%d, errorcode %d");
buf.Format(KErr, i, retArray[i]);
INFO_PRINTF1(buf);
errorsFound++;
}
else
{
_LIT(KErr, "Created thread %d");
buf.Format(KErr, i);
INFO_PRINTF1(buf);
threadArray[i].Logon(statusArray[i]);
}
}
for (TInt j=0; j<KNrOfClients; j++)
{
if (retArray[j] == KErrNone)
{
buf.Zero();
_LIT(KInfoResume, "Resuming thread %d");
buf.Format(KInfoResume, j);
//if (bDEBUG)
INFO_PRINTF1(buf);
User::After(6000000);
threadArray[j].Resume();
}
}
for (i = KNrOfClients-1; i>=0; i--)
{
if (retArray[i] == KErrNone) User::WaitForRequest(statusArray[i]);
buf.Zero();
buf.Format(KThreadName, i);
_LIT(KWaitForRequest, " User::WaitForRequest ");
buf.Append(KWaitForRequest);
INFO_PRINTF1(buf);
buf.Zero();
buf.Format(KThreadName, i);
if (threadArray[i].ExitType() == EExitPanic)
{
_LIT(KPanicExit, " EExitPanic ");
buf.Append(KPanicExit);
INFO_PRINTF1(buf);
errorsFound++;
}
else if (threadArray[i].ExitType() == EExitKill)
{
_LIT(KKillExit, " EExitKill");
buf.Append(KKillExit);
INFO_PRINTF1(buf);
}
else if (threadArray[i].ExitType() == EExitPending)
{
_LIT(KPendingExit, " EExitPending");
buf.Append(KPendingExit);
INFO_PRINTF1(buf);
errorsFound++;
}
else
{
_LIT(KOtherExit, " other ");
buf.Append(KOtherExit);
INFO_PRINTF1(buf);
errorsFound++;
}
}
for (i=0; i<KNrOfClients; i++)
{
buf.Zero();
_LIT(KDEBUG, "Wrong reasoncode from Thread %d reasoncode %d");
buf.Format(KDEBUG, i, threadArray[i].ExitReason());
if (threadArray[i].ExitReason() != KErrNone) INFO_PRINTF1(buf);
threadArray[i].Close();
}
// Only affected on WINS emulator
User::SetJustInTime(jit);
return errorsFound;
}
/**
* Connection is opened to location server,and closed
*
* If anything fails during the execution of this test, then function
* leaves with proper error code.
*
* Parameters:
**/
void LocationRequestThreadMainPartL(TDes& aErrorBuf)
{
// Open connection to Location server
RPositionServer server;
TInt err = server.Connect();
if (err != KErrNone)
{
_LIT(KErrOpen, "Server open failed with code %d\r\n");
aErrorBuf.Format(KErrOpen, err);
}
else
{
_LIT(KOkOpen, "Server open ok\r\n");
aErrorBuf.Copy(KOkOpen);
}
User::LeaveIfError(err);
CleanupClosePushL(server);
CleanupStack::PopAndDestroy(1); // server, positioner
_LIT(KInfTestComplet, "Test completed ok for this thread\r\n");
aErrorBuf.Append(KInfTestComplet);
}
/**
* This is the main function for threads that connects and
* disconnect from MLFW
*
* Function returns 0 if running of the test did not leave.
*Otherwise the leave code is returned.
**/
LOCAL_C TInt LocationRequestThread(TAny* aData)
{
// Create cleanupstack for this thread
CTrapCleanup* cleanup = CTrapCleanup::New();
// No parameters to read, just start main function.
HBufC* buf = HBufC::NewL(1024);
TPtr ptr = buf->Des();
// Run the actual test, and trap possible leave
TRAPD(leave, LocationRequestThreadMainPartL(ptr));
// Open connection to file server
RFs fs;
User::LeaveIfError(fs.Connect());
TInt index = *((TInt*) aData);
TBuf<30> errorFile;
_LIT(KInfThread, "c:\\logs\\thread%derrinfo.txt");
errorFile.Format(KInfThread, index);
// Open log file
RFile file;
TInt err = file.Replace(fs,errorFile,EFileStreamText|EFileWrite);
if (err != KErrNone)
{
User::Leave(err);
}
_LIT(KErrLeave, "*** This thread (thread %d) leave code: %d\r\n");
ptr.AppendFormat(KErrLeave, index, leave);
TFileText fileText;
fileText.Set(file);
fileText.Write(ptr);
// Close log file
file.Close();
fs.Close();
// Delete cleanup stack
delete cleanup;
// Exit this thread with leave code (KErrNone in successful case)
User::Exit(leave);
return 0;
}
// ---------------------------------------------------------
// CPosTp208::DoFastConnectionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CT_LbsClientPosTp208::DoFastConnectionL()
{
TInt err;
// Create two different threads. Each thread connects
// and disconnect from MLFW very fast.
const TInt KMinHeapSize = 4096;
const TInt KMaxHeapSize = 128000;
RThread thread2;
RThread thread3;
TInt thread2Id = 2;
TInt thread3Id = 3;
// Make sure that if one of the threads panic, whole emulator is not
// paniced (this has effect only in Wins).
User::SetJustInTime(EFalse);
_LIT(KInfo, "Create two threads");
INFO_PRINTF1(KInfo);
err = thread2.Create(KThread2Name, LocationRequestThread, KDefaultStackSize,
KMinHeapSize, KMaxHeapSize, &thread2Id);
AssertTrueL(err == KErrNone, KErrMsgThreadCreation, err);
err = thread3.Create(KThread3Name, LocationRequestThread, KDefaultStackSize,
KMinHeapSize, KMaxHeapSize, &thread3Id);
AssertTrueL(err == KErrNone, KErrMsgThreadCreation, err);
// Logon to each thread, so we can get a notification when they kill
// themselves.
TRequestStatus status2, status3;
thread2.Logon(status2);
thread3.Logon(status3);
_LIT(KStart, "Start the threads will connect to and disconnect to MLFW,");
INFO_PRINTF1(KStart);
// Start all treads.
thread2.Resume();
User::After(2000000);
thread3.Resume();
// Wait for all threads to exit
User::WaitForRequest(status2);
User::WaitForRequest(status3);
// Actual test is now run.
_LIT(KInfoExit, "All threads have exited, exit reasons:");
INFO_PRINTF1(KInfoExit);
// Check that all threads had correct exit reason. Also log
// all the exit reasons into log file.
TInt exitReasonsCorrect = 0;
exitReasonsCorrect |= thread2.ExitReason();
exitReasonsCorrect |= thread3.ExitReason();
// Close all handles to threads.
thread2.Close();
thread3.Close();
// Return back to normal mode
User::SetJustInTime(ETrue);
return exitReasonsCorrect;
}
// ---------------------------------------------------------
// CPosTp208::StartL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CT_LbsClientPosTp208::StartL()
{
//first do a simple connection test
TInt fasterr = DoFastConnectionL();
_LIT(KFailConnect, "Fast connection failed");
AssertTrueL(fasterr == KErrNone, KFailConnect, fasterr);
SetupPsyL(iUidMultiPsy);
TInt nrOfRounds = 1;
TBuf<100> buf;
_LIT(KPsitionUpdate,
">>>>>>>>>>Running StartThreads(ETrue) requesting position updates<<<<<<<<");
INFO_PRINTF1(KPsitionUpdate);
_LIT(KEmptySpace, "");
_LIT(KRound, ">>>>>>Round nr %d :");
_LIT(KErrorsFound, "Errors found!!!");
for (TInt i=0; i<nrOfRounds; i++)
{
INFO_PRINTF1(KEmptySpace);
buf.Format(KRound, i);
INFO_PRINTF1(buf);
TTime now, startTime;
TTimeIntervalMicroSeconds requestTime;
startTime.UniversalTime();
TInt res = StartThreads(ETrue);
if (res != KErrNone)
LogErrorAndLeaveL(KErrorsFound, res);
now.UniversalTime();
requestTime = now.MicroSecondsFrom(startTime);
_LIT(KDebug, "%d requests from %d threads took: %d microsecs.");
buf.Zero();
TInt64 reqTime = requestTime.Int64();
buf.Format(KDebug, KNrOfClients * KNrOfRuns, KNrOfClients, reqTime);
INFO_PRINTF1(buf);
}
_LIT(KConnectDisconnect,
">>>>>>>>>>Running StartThreads(EFalse) connect/disconnect Epos<<<<<<<<");
INFO_PRINTF1(KConnectDisconnect);
nrOfRounds = 5;
for (TInt j=0; j<nrOfRounds; j++)
{
INFO_PRINTF1(KEmptySpace);
buf.Format(KRound, j);
INFO_PRINTF1(buf);
TTime now, startTime;
TTimeIntervalMicroSeconds requestTime;
startTime.UniversalTime();
// Threads only connects to Epos server and then disconnect
TInt res = StartThreads(EFalse);
if (res != KErrNone)
LogErrorAndLeaveL(KErrorsFound, res);
now.UniversalTime();
requestTime = now.MicroSecondsFrom(startTime);
_LIT(KDebug, "%d threads connecting and disconnecting to Epos server took: %d microsecs.");
buf.Zero();
TInt64 reqTime = requestTime.Int64();
buf.Format(KDebug, KNrOfClients, reqTime);
INFO_PRINTF1(buf);
}
}
// End of File