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) 2008-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\misc\t_svrstress.cpp
// This is a stress test for client server session connect and disconnect
//
#include <e32base.h>
#include <e32base_private.h>
#define __E32TEST_EXTENSION__
#include <e32test.h>
#include <e32svr.h>
#include "u32std.h"
#include <e32atomics.h>
#include <e32panic.h>
#include <e32def.h>
#include <e32def_private.h>
RTest test(_L("T_SVRSTRESS"));
RSemaphore SyncSemaphore;
TUint32 WaitABit;
TInt NumMessageSlots;
TInt UseGlobalMessagePool;
const TInt BigDesLength = 256 * 1024;
#if 1
#define TRACE(t) RDebug::RawPrint(_L8(t))
#else
#define TRACE(t)
#endif
//
// utility functions...
//
void WaitForRequest()
{
User::WaitForAnyRequest();
RThread().RequestSignal(); // put request semaphore count back
}
TInt WaitForRequest(TRequestStatus& aStatus,TTimeIntervalMicroSeconds32 aTimeout=2*1000000)
{
RTimer timer;
test_Equal(KErrNone,timer.CreateLocal());
TRequestStatus timeoutStatus;
timer.After(timeoutStatus,aTimeout);
User::WaitForRequest(aStatus,timeoutStatus);
TInt r;
if(aStatus.Int()==KRequestPending)
{
r = KErrTimedOut;
}
else
{
r = KErrNone;
timer.Cancel();
User::WaitForRequest(timeoutStatus);
}
CLOSE_AND_WAIT(timer);
return r;
}
//
// CMyServer
//
_LIT(KMyServerName,"StressSvr");
class CMyServer : public CServer2
{
public:
CMyServer(TInt aPriority);
static CMyServer* New(TInt aPriority);
virtual CSession2* NewSessionL(const TVersion&, const RMessage2&) const;
};
class CMySession : public CSession2
{
public:
virtual void ServiceL(const RMessage2& aMessage);
};
CMyServer* CMyServer::New(TInt aPriority)
{
return new CMyServer(aPriority);
}
CMyServer::CMyServer(TInt aPriority)
: CServer2(aPriority, ESharableSessions)
{}
CSession2* CMyServer::NewSessionL(const TVersion&, const RMessage2&) const
{
TRACE("O");
return new(ELeave) CMySession;
}
TBool RestartServer;
TInt MyServerThread(TAny*)
{
CActiveScheduler* pR=new CActiveScheduler;
if(!pR)
return KErrNoMemory;
CActiveScheduler::Install(pR);
RestartServer = ETrue;
while(RestartServer)
{
__UHEAP_MARK;
CMyServer* pS=CMyServer::New(0);
if(!pS)
return KErrNoMemory;
TInt r = pS->Start(KMyServerName);
if(r!=KErrNone)
return r;
TRACE("S");
RThread::Rendezvous(KErrNone);
CActiveScheduler::Start();
delete pS;
__UHEAP_MARKEND;
}
delete pR;
return KErrNone;
}
//
// RMyServer
//
class RMyServer : public RSessionBase
{
public:
enum TFunction
{
EStop,
ESync,
EPing,
EShutdown,
ECompleteWhileCopying
};
public:
TInt Connect();
inline TInt Send(TFunction aFunction) const
{ return SendReceive(aFunction); }
inline TInt Send(TFunction aFunction, const TIpcArgs& aArgs) const
{ return SendReceive(aFunction, aArgs); }
inline void Send(TFunction aFunction, TRequestStatus& aStatus) const
{ SendReceive(aFunction, aStatus); }
inline void Send(TFunction aFunction, const TIpcArgs& aArgs, TRequestStatus& aStatus) const
{ SendReceive(aFunction, aArgs, aStatus); }
};
TInt RMyServer::Connect()
{
RMyServer temp;
TInt r = temp.CreateSession(KMyServerName, TVersion(), UseGlobalMessagePool ? -1 : NumMessageSlots);
if(r!=KErrNone)
return r;
// turn handle into process owned...
RMyServer temp2(temp);
r = temp2.Duplicate(RThread());
temp.Close();
*this = temp2;
return r;
}
//
// CMySession
//
TInt CopierThread(TAny* aPtr)
{
RMessage2& msg = *(RMessage2*)aPtr;
HBufC* bigdes = HBufC::NewMax(BigDesLength);
if (bigdes == NULL)
return KErrNoMemory;
TPtr ptr = bigdes->Des();
RThread().Rendezvous(KErrNone);
RDebug::Print(_L("START\n"));
TInt r = msg.Read(2, ptr);
RDebug::Print(_L("DONE\n"));
delete bigdes;
return r;
}
void CMySession::ServiceL(const RMessage2& aMessage)
{
RThread client;
RThread copier;
aMessage.Client(client);
TRequestStatus* s;
TRequestStatus* s2;
TRequestStatus logon, rendez;
TInt r;
s = (TRequestStatus*)aMessage.Ptr0();
switch(aMessage.Function())
{
case RMyServer::EStop:
TRACE("E");
CActiveScheduler::Stop();
break;
case RMyServer::ESync:
TRACE("Y");
client.RequestComplete(s,KErrNone); // let client know we've received the message
SyncSemaphore.Wait(); // wait for signal from client
s = (TRequestStatus*)aMessage.Ptr1(); // use second status for later end signal
aMessage.Complete(KErrNone); // complete the message
break;
case RMyServer::EPing:
TRACE("P");
aMessage.Complete(KErrNone);
break;
case RMyServer::EShutdown:
TRACE("D");
RestartServer = EFalse;
CActiveScheduler::Stop();
break;
case RMyServer::ECompleteWhileCopying:
s2 = (TRequestStatus*)aMessage.Ptr1();
r = copier.Create(_L("Copier"),CopierThread,KDefaultStackSize,&User::Allocator(),(TAny*)&aMessage);
if (r == KErrNone)
{
copier.Logon(logon);
copier.Rendezvous(rendez);
copier.SetPriority(EPriorityLess);
copier.Resume();
User::WaitForRequest(rendez);
User::AfterHighRes(5000); // 5ms delay to let copy actually start
RDebug::Print(_L("COMPLETING\n"));
aMessage.Complete(KErrNone);
User::WaitForRequest(logon);
copier.Close();
}
client.RequestComplete(s,r);
s = s2;
break;
default:
TRACE("?");
aMessage.Complete(KErrNotSupported);
break;
}
// let client know we've completed the message...
TRACE("X");
client.RequestComplete(s,KErrNone);
client.Close();
}
//
// RStressThread
//
class RStressThread
{
public:
RStressThread(TThreadFunction aThreadFunction, const char* aName, TInt aDelay=-1);
~RStressThread();
void Start();
void Restart();
void Stop();
// for use by thread...
static RStressThread& Begin(TAny* aInfo);
TBool Loop();
private:
TThreadFunction iThreadFunction;
const char* iName;
RThread iThread;
TRequestStatus iLogon;
TUint iCount;
TBool iStop;
TInt iDelay;
private:
static TInt iInstanceCounter;
};
TInt RStressThread::iInstanceCounter = 0;
RStressThread::RStressThread(TThreadFunction aThreadFunction, const char* aName, TInt aDelay)
: iThreadFunction(aThreadFunction), iName(aName), iLogon(KErrNone), iDelay(aDelay)
{
iThread.SetHandle(0);
}
RStressThread::~RStressThread()
{
Stop();
}
void RStressThread::Start()
{
iStop = false;
iCount = 0;
TBuf<KMaxKernelName> name;
name.Copy(TPtrC8((const TUint8*)iName));
name.Append((TText)'-');
name.AppendNum(iInstanceCounter++);
test_Equal(KErrNone,iThread.Create(name,iThreadFunction,KDefaultStackSize,&User::Allocator(),this));
iThread.Logon(iLogon);
test_Equal(KRequestPending,iLogon.Int());
TRequestStatus rendezvous;
iThread.Rendezvous(rendezvous);
iThread.Resume();
User::WaitForRequest(rendezvous);
test_Equal(KErrNone,rendezvous.Int());
}
void RStressThread::Stop()
{
if(!iThread.Handle())
return; // thread not running
iStop = true;
RDebug::Printf("RStressThread::Stop %s (count=%d)",iName,iCount);
if(WaitForRequest(iLogon,10*1000000)!=KErrNone)
test(0);
CLOSE_AND_WAIT(iThread);
}
void RStressThread::Restart()
{
if(iThread.Handle())
{
if(iLogon==KRequestPending)
return; // thread still running
User::WaitForRequest(iLogon);
CLOSE_AND_WAIT(iThread);
}
Start();
}
TBool RStressThread::Loop()
{
if(iDelay>=0)
User::AfterHighRes(iDelay);
++iCount;
return !iStop;
}
RStressThread& RStressThread::Begin(TAny* aInfo)
{
RStressThread& t = *(RStressThread*)aInfo;
if(t.iDelay>=0)
RThread().SetPriority(EPriorityMore); // so this preempts threads after delay
RThread::Rendezvous(KErrNone);
return t;
}
//
//
//
RMyServer Session;
RThread ServerThread;
void NewSession()
{
RMyServer newSession;
TRACE("o");
test_Equal(KErrNone,newSession.Connect());
RMyServer oldSession(Session);
Session = newSession;
TRACE("c");
if(oldSession.Handle())
CLOSE_AND_WAIT(oldSession);
}
TInt SessionCloserThread(TAny* aInfo)
{
RStressThread& t = RStressThread::Begin(aInfo);
do
{
NewSession();
}
while(t.Loop());
return KErrNone;
}
TInt ServerStopperThread(TAny* aInfo)
{
RStressThread& t = RStressThread::Begin(aInfo);
do
{
TRACE("s");
TRequestStatus rendezvous;
ServerThread.Rendezvous(rendezvous);
TRequestStatus s1 = KRequestPending;
TRequestStatus s2;
Session.Send(RMyServer::EStop,TIpcArgs(&s1),s2);
User::WaitForRequest(s1,s2);
if(s2!=KRequestPending)
{
test_Equal(KErrServerTerminated,s2.Int());
User::WaitForRequest(s1);
}
User::WaitForRequest(rendezvous);
NewSession();
}
while(t.Loop());
return KErrNone;
}
TInt SessionPingerThread(TAny* aInfo)
{
RStressThread& t = RStressThread::Begin(aInfo);
do
{
TRACE("p");
TRequestStatus s1 = KRequestPending;
TRequestStatus s2;
Session.Send(RMyServer::EPing,TIpcArgs(&s1),s2);
User::WaitForRequest(s1,s2);
if(s2.Int()==KErrNone)
{
// message completed OK, wait for servers extra signal
User::WaitForRequest(s1);
}
else if(s2.Int()==KErrServerTerminated)
{
// server died before message processed, there shouldn't be an extra signal
test_Equal(KRequestPending,s1.Int());
}
else
{
// assume message was completed by server, but we didn't get signalled because session was closed
test_Equal(KRequestPending,s2.Int());
test_Equal(KErrNone,s1.Int());
}
}
while(t.Loop());
return KErrNone;
}
void TestInit()
{
RThread().SetPriority(EPriorityMuchMore); // so this main thread is higher priority than workers
test_Equal(KErrNone,SyncSemaphore.CreateLocal(0,EOwnerProcess));
// calculate async cleanup timeout value...
TInt factor = UserSvr::HalFunction(EHalGroupVariant, EVariantHalTimeoutExpansion, 0, 0);
if (factor<=0)
factor = 1;
if (factor>1024)
factor = 1024;
WaitABit = 200000 * (TUint32)factor;
}
void StartServer()
{
// start test server...
test_Equal(KErrNone,ServerThread.Create(_L("Server"),MyServerThread,KDefaultStackSize,1<<12,1<<20,0));
TRequestStatus rendezvous;
ServerThread.Rendezvous(rendezvous);
ServerThread.Resume();
User::WaitForRequest(rendezvous);
test_Equal(KErrNone,rendezvous.Int());
test_Equal(EExitPending,ServerThread.ExitType());
}
void StopServer()
{
TRequestStatus logon;
NewSession();
TRequestStatus s1 = KRequestPending;
TRequestStatus s2;
ServerThread.Logon(logon);
Session.Send(RMyServer::EShutdown,TIpcArgs(&s1),s2);
User::WaitForRequest(s1,s2);
if(s2!=KRequestPending)
{
test_Equal(KErrServerTerminated,s2.Int());
User::WaitForRequest(s1);
}
CLOSE_AND_WAIT(Session);
User::WaitForRequest(logon);
test_KErrNone(logon.Int());
test_Equal(EExitKill, ServerThread.ExitType());
CLOSE_AND_WAIT(ServerThread);
}
void TestMessageCompleteOnClosedSession()
{
__KHEAP_MARK;
test.Start(_L("Start server"));
StartServer();
test.Next(_L("Connect"));
test_Equal(KErrNone,Session.Connect());
test.Next(_L("Send message"));
TRequestStatus s1 = KRequestPending;
TRequestStatus s2 = KRequestPending;
TRequestStatus s3;
Session.Send(RMyServer::ESync,TIpcArgs(&s1,&s2),s3);
test_Equal(KRequestPending,s3.Int());
test.Next(_L("Wait for s1"));
test_Equal(KErrNone,WaitForRequest(s1));
test_Equal(KErrNone,s1.Int());
test_Equal(KRequestPending,s2.Int());
test_Equal(KRequestPending,s3.Int());
test.Next(_L("Close session"));
Session.Close();
test_Equal(KRequestPending,s2.Int());
test_Equal(KRequestPending,s3.Int());
test.Next(_L("Trigger message completion"));
SyncSemaphore.Signal();
test.Next(_L("Wait for s2"));
test_Equal(KErrNone,WaitForRequest(s2));
test_Equal(KErrNone,s2.Int());
test_Equal(KRequestPending,s3.Int());
test.Next(_L("Stop server"));
StopServer();
test.End();
User::After(WaitABit); // allow asynchronous cleanup to happen
__KHEAP_MARKEND;
}
void TestMessageCompleteWhileCopying()
{
__KHEAP_MARK;
test.Start(_L("Start server"));
StartServer();
test.Next(_L("Connect"));
test_Equal(KErrNone,Session.Connect());
test.Next(_L("Create large descriptor"));
HBufC* bigdes = HBufC::NewMax(BigDesLength);
test_NotNull(bigdes);
TPtr ptr = bigdes->Des();
test.Next(_L("Send message"));
TRequestStatus s1 = KRequestPending;
TRequestStatus s2 = KRequestPending;
TRequestStatus s3;
Session.Send(RMyServer::ECompleteWhileCopying,TIpcArgs(&s1,&s2,&ptr),s3);
test.Next(_L("Wait for s3"));
test_Equal(KErrNone,WaitForRequest(s3,10*1000000));
test_Equal(KErrNone,s3.Int());
test.Next(_L("Wait for s2"));
test_Equal(KErrNone,WaitForRequest(s2,10*1000000));
test_Equal(KErrNone,s2.Int());
test.Next(_L("Wait for s1"));
test_Equal(KErrNone,WaitForRequest(s1,10*1000000));
test_Equal(KErrNone,s1.Int());
test.Next(_L("Close session"));
Session.Close();
test.Next(_L("Stop server"));
StopServer();
test.End();
User::After(WaitABit); // allow asynchronous cleanup to happen
__KHEAP_MARKEND;
}
void RunStressThreads(RStressThread& aThread1, RStressThread& aThread2, TInt aTimeout=1000000)
{
__KHEAP_MARK;
StartServer();
NewSession();
aThread1.Start();
aThread2.Start();
RTimer timer;
test_Equal(KErrNone,timer.CreateLocal());
TRequestStatus timeoutStatus;
timer.After(timeoutStatus,aTimeout);
do
{
aThread1.Restart();
aThread2.Restart();
WaitForRequest();
}
while(timeoutStatus==KRequestPending);
User::WaitForRequest(timeoutStatus);
CLOSE_AND_WAIT(timer);
aThread2.Stop();
aThread1.Stop();
CLOSE_AND_WAIT(Session);
StopServer();
User::After(WaitABit); // allow asynchronous cleanup to happen
__KHEAP_MARKEND;
}
GLDEF_C TInt E32Main()
{
TInt i;
test.Title();
test.Start(_L("Initialise"));
TestInit();
for(UseGlobalMessagePool=0; UseGlobalMessagePool<2; ++UseGlobalMessagePool)
{
if(UseGlobalMessagePool)
test.Next(_L("Tests using global message pool"));
else
test.Next(_L("Tests using local message pool"));
NumMessageSlots = 1;
test.Start(_L("Check completing messages on dead session"));
TestMessageCompleteOnClosedSession();
for (i=0; i<10; i++)
{
test.Next(_L("Check completing message while IPC copying"));
TestMessageCompleteWhileCopying();
}
test.Next(_L("Stress closing session whilst in use"));
RStressThread closer(SessionCloserThread,"SessionCloser",0);
RStressThread pinger1(SessionPingerThread,"Pinger");
RunStressThreads(closer, pinger1);
NumMessageSlots = 2;
test.Next(_L("Stress stopping server whilst in use"));
RStressThread stopper(ServerStopperThread,"ServerStopper",0);
RStressThread pinger2(SessionPingerThread,"Pinger");
RunStressThreads(stopper, pinger2);
test.End();
}
test.End();
return(0);
}