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) 1997-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\thread\t_killer.cpp
// Derived from T_MESSGE, tests threads killing each other, not cleaning up etc.
//
//
#include <e32std.h>
#include <e32std_private.h>
#include <e32math.h>
#include <e32test.h>
#include <e32ver.h>
#include <e32panic.h>
const TInt KHeapMinSize=0x1000;
const TInt KHeapMaxSize=0x1000;
class CTestServer : public CServer2
{
public:
IMPORT_C CTestServer(TInt aPriority);
enum TPanicType{
EInt0Error=1, EInt1Error, EInt2Error, EInt3Error,
EPtr0Error, EPtr1Error, EPtr2Error, EPtr3Error,
ECreateNameError, ENewSessionError,
EClientError, EWatcherError, EKilled
};
static void Panic(TPanicType aReason);
protected:
//override the pure virtual functions:
IMPORT_C virtual CSession2* NewSessionL(const TVersion& aVersion, const RMessage2 &) const;
};
class CTestSession : public CSession2
{
public:
enum {EStop,ETestInt,ETestPtr,ETestClient,ETestComplete,ETestPtrComplete,ETestCompletePanic,ETestOtherSession,ETestCompleteAfter};
//Override pure virtual
IMPORT_C virtual void ServiceL(const RMessage2& aMessage);
private:
void TestInt(const RMessage2& aMessage);
void TestPtr(const RMessage2& aMessage);
void TestClient(const RMessage2& aMessage);
void TestComplete(const RMessage2& aMessage);
void TestPtrComplete(const RMessage2& aMessage);
void TestCompletePanic();
//
TInt count1;//initially ==0
RMessage2 messages[5];//Used in TestComplete()
//
TInt count2;//initially ==0
RMessagePtr2 messagePtrs[5];//User in TestPtrComplete()
};
class CMyActiveScheduler : public CActiveScheduler
{
public:
virtual void Error(TInt anError) const; //override pure virtual error function
};
class RSession : public RSessionBase
{
public:
TInt PublicSendReceive(TInt aFunction, const TIpcArgs& aArgs)
{
return (SendReceive(aFunction, aArgs));
}
void PublicSendReceive(TInt aFunction, const TIpcArgs& aArgs, TRequestStatus& aStatus)
{
SendReceive(aFunction, aArgs, aStatus);
}
TInt PublicCreateSession(const TDesC& aServer,TInt aMessageSlots)
{
return (CreateSession(aServer,User::Version(),aMessageSlots));
}
};
//=========================================================================
// CTestServer functions
CTestServer::CTestServer(TInt aPriority)
//
// Constructor - sets name
//
: CServer2(aPriority)
{}
CSession2* CTestServer::NewSessionL(const TVersion& aVersion, const RMessage2 &) const
//
// Virtual fn - checks version supported and creates a CTestSession
//
{
TVersion version(KE32MajorVersionNumber,KE32MinorVersionNumber,KE32BuildVersionNumber);
if (User::QueryVersionSupported(version,aVersion)==EFalse)
User::Leave(KErrNotSupported);
CTestSession* newCTestSession = new CTestSession;
if (newCTestSession==NULL)
Panic(ENewSessionError);
return(newCTestSession);
}
RThread clientThread, serverThread, killerThread;
void CTestServer::Panic(TPanicType aReason) //static function
{
clientThread.Kill(KErrNone);
User::Panic(_L("CTestServer"),aReason);
}
// CTestSession funtions
RSession session, otherSession;
RSemaphore sem;
const TInt KTestInt[] = {-3866,30566,0,200};
const TIpcArgs KIpcArgInt(-3866,30566,0,200);
void CTestSession::TestInt(const RMessage2& aMessage)
//
// Tests to see that the correct Int0/1/2/3 have been received
//
{
if (aMessage.Int0()!=KTestInt[0])
CTestServer::Panic(CTestServer::EInt0Error);
if (aMessage.Int1()!=KTestInt[1])
CTestServer::Panic(CTestServer::EInt1Error);
if (aMessage.Int2()!=KTestInt[2])
CTestServer::Panic(CTestServer::EInt2Error);
if (aMessage.Int3()!=KTestInt[3])
CTestServer::Panic(CTestServer::EInt3Error);
}
const TAny* KTestPtr[]={&clientThread, &serverThread, &session, &sem};
const TIpcArgs KIpcArgPtr(&clientThread, &serverThread, &session, &sem);
void CTestSession::TestPtr(const RMessage2& aMessage)
//
// Tests to see that the correct Ptr0/1/2/3 have been received
//
{
if (aMessage.Ptr0()!=KTestPtr[0])
CTestServer::Panic(CTestServer::EPtr0Error);
if (aMessage.Ptr1()!=KTestPtr[1])
CTestServer::Panic(CTestServer::EPtr1Error);
if (aMessage.Ptr2()!=KTestPtr[2])
CTestServer::Panic(CTestServer::EPtr2Error);
if (aMessage.Ptr3()!=KTestPtr[3])
CTestServer::Panic(CTestServer::EPtr3Error);
}
TFullName clientName;
TInt clientNumber;
void CTestSession::TestClient(const RMessage2& aMessage)
//
// Tests Client()
//
{
// Under WINS, thread names are not prefixed with the process name
TFullName n=RProcess().Name();
n+=_L("::");
n+=clientName;
RThread client;
TInt r = aMessage.Client(client);
if (r != KErrNone || client.FullName().CompareF(n)!=0)
{
client.Close();
clientThread.Kill(0);
CTestServer::Panic(CTestServer::EClientError);
}
client.Close();
}
void CTestSession::TestComplete(const RMessage2& aMessage)
//
// Stores messages up then Completes in reverse order
//
{
messages[count1] = aMessage;
if (++count1==5)
for(count1=4; count1>=0; count1--)
messages[count1].Complete(5-count1); //Complete with different 'error messages'
}
void CTestSession::TestPtrComplete(const RMessage2& aMessage)
//
// Stores messages up as RMessagePtrs then Completes in reverse order
// Also tests RMessage2::MessagePtr()
//
{
messagePtrs[count2] = aMessage;
if (++count2==5)
for(count2=4; count2>=0; count2--)
messagePtrs[count2].Complete(10-count2*2);
}
void CTestSession::ServiceL(const RMessage2& aMessage)
//
// Virtual message-handler
//
{
TInt r=KErrNone;
switch (aMessage.Function())
{
case EStop:
CActiveScheduler::Stop();
break;
case ETestInt:
TestInt(aMessage);
break;
case ETestPtr:
TestPtr(aMessage);
break;
case ETestClient:
TestClient(aMessage);
break;
case ETestComplete:
TestComplete(aMessage);
return;
case ETestPtrComplete:
TestPtrComplete(aMessage);
return;
case ETestCompletePanic:
aMessage.Complete(KErrNone);
break;
case ETestOtherSession:
break;
case ETestCompleteAfter:
User::After(7000000);
break;
default:
r=KErrNotSupported;
}
aMessage.Complete(r);
}
void CMyActiveScheduler::Error(TInt anError) const
//
// Virtual error handler
//
{
User::Panic(_L("CMyActiveScheduer::Error"), anError);
}
LOCAL_D TInt64 TheSeed;
GLDEF_C TInt Random(TInt aRange)
{
return (Math::Rand(TheSeed)>>11)%aRange;
}
TInt KillerThread(TAny*)
//
// Wait a random time and then kill the client thread
//
{
RTest test(_L("T_KILLER...Killer"));
TRequestStatus clientStatus;
TInt delay=0;
test.Title();
test.Start(_L("Logon to client"));
clientThread.Logon(clientStatus);
test.Next(_L("Delay...."));
for (;;)
{
User::After(1000);
delay++;
if (clientStatus!=KRequestPending)
return KErrNone; // client has already finished
if (Random(1000)<1)
break; // Time to die!
}
test.Printf(_L("Kill client after %d ms\n"), delay);
clientThread.Kill(CTestServer::EKilled);
test.Close(); // close console immediately
// test.End(); // "Press ENTER to exit"
return KErrNone;
}
TInt ClientThread(TAny* aPtr)
//
// Passed as the first client thread - signals the server to do several tests
//
{
RTest test(_L("T_KILLER...client"));
TInt repeat = (TInt)aPtr;
test.Title();
test.Start(_L("Client thread"));
do
{
test.Next(_L("Client loop"));
test.Start(_L("Create Session"));
TInt r=session.PublicCreateSession(_L("CTestServer"),5);
if (r!=KErrNone)
User::Panic(_L("CreateSessn failure"),r);
test.Next(_L("Signal to test Int0/1/2/3()"));
r=session.PublicSendReceive(CTestSession::ETestInt, KIpcArgInt);
test(r==KErrNone);
test.Next(_L("Signal to test Ptr0/1/2/3()"));
r=session.PublicSendReceive(CTestSession::ETestPtr, KIpcArgPtr);
test(r==KErrNone);
test.Next(_L("Signal to test Client()"));
r=session.PublicSendReceive(CTestSession::ETestClient, TIpcArgs());
test(r==KErrNone);
test.Next(_L("Test RMessage2::Complete()"));
TRequestStatus stat[7];
for (r=0;r<4;r++)
{
session.PublicSendReceive(CTestSession::ETestComplete, TIpcArgs(), stat[r]);
test(stat[r]==KRequestPending);
}
session.PublicSendReceive(CTestSession::ETestComplete, TIpcArgs(), stat[4]);
User::WaitForRequest(stat[0]);
for (r=0;r<5;r++)
test(stat[r]==5-r); //Test the 'error messages' set by Complete()
test.Next(_L("Test RMessagePtr2::Complete()"));
for (r=0;r<4;r++)
{
session.PublicSendReceive(CTestSession::ETestPtrComplete, TIpcArgs(), stat[r]);
test(stat[r]==KRequestPending);
}
session.PublicSendReceive(CTestSession::ETestPtrComplete, TIpcArgs(), stat[4]);
User::WaitForRequest(stat[0]);
for (r=0;r<5;r++)
test(stat[r]==10-r*2);
test.Next(_L("Try another session"));
r=otherSession.PublicCreateSession(_L("CTestServer"),5);
test(r==KErrNone);
r=otherSession.PublicSendReceive(CTestSession::ETestOtherSession, TIpcArgs());
test(r==KErrNone);
// test.Next(_L("Try to disconnect"));
// r=session.PublicSendReceive(RMessage2::EDisConnect,NULL);//Panics user
// test(r==KErrNone);
test.Next(_L("Saturate server"));
for(r=0;r<7;r++)
{
test.Printf(_L("Send %d\r"),r);
session.PublicSendReceive(CTestSession::ETestCompleteAfter,TIpcArgs(),stat[r]);
if (r<5)
test(stat[r]==KRequestPending);
else
test(stat[r]==KErrServerBusy);
}
test.Printf(_L("\n"));
for(r=0;r<5;r++)
{
test.Printf(_L("Wait %d\r"),r);
User::WaitForRequest(stat[r]);
test(stat[r]==KErrNone);
}
test.Printf(_L("\n"));
test.End();
}
while (--repeat > 0);
test.Start(_L("Signal to stop ActiveScheduler"));
session.PublicSendReceive(CTestSession::EStop, TIpcArgs());
test.Close();
return (KErrNone);
}
TInt ServerThread(TAny*)
//
// Passed as the server thread in 2 tests - sets up and runs CTestServer
//
{
RTest test(_L("T_KILLER...server"));
test.Title();
test.Start(_L("Create and install ActiveScheduler"));
CMyActiveScheduler* pScheduler = new CMyActiveScheduler;
if (pScheduler==NULL)
{
clientThread.Kill(0);
User::Panic(_L("CreateSched failure"),KErrNoMemory);
}
CActiveScheduler::Install(pScheduler);
test.Next(_L("Creating and starting Server"));
CTestServer* pServer = new CTestServer(0);
if (pServer==NULL)
{
clientThread.Kill(0);
User::Panic(_L("CreateServr failure"),KErrNoMemory);
}
TInt r=pServer->Start(_L("CTestServer"));//Starting a CServer2 also Adds it to the ActiveScheduler
if (r!=KErrNone)
{
clientThread.Kill(0);
User::Panic(_L("StartServr failure"),r);
}
test.Next(_L("Start ActiveScheduler and signal to client"));
test.Printf(_L(" There might be something going on beneath this window"));
sem.Signal();
CActiveScheduler::Start();
test.Next(_L("Destroy ActiveScheduler"));
delete pScheduler;
delete pServer;
test.Close();
return (KErrNone);
}
const TInt KTestPanic = 14849;
TInt PanicTestThread (TAny*)
//
// Passed as a thread entry - just calls RMessage2::Panic()
//
{
RMessage2 message;
message.Panic(_L("Testing Panic"),KTestPanic);
return(KErrNone);
}
RTest test(_L("Main T_KILLER test"));
TInt CompletePanicClientThread (TAny*)
//
// Passed as the second client thread entry - signals to server to call Complete() twice
//
{
sem.Wait();
TInt r=session.PublicCreateSession(_L("CTestServer"),1);
test(r==KErrNone);
r=session.PublicSendReceive(CTestSession::ETestCompletePanic, TIpcArgs());
test(r==KErrNone);
session.PublicSendReceive(CTestSession::EStop, TIpcArgs());//panic should occur before this is serviced
return(KErrNone);
}
void SimpleRMessage()
//
// Simple RMessage2 Tests - constructors and assignment
//
{
test.Start(_L("Default constructor"));
RMessage2 message1;
test.Next(_L("Copy constructor"));
RMessage2 message2(message1);
test(message1.Function()==message2.Function());
test(message1.Int0()==message2.Int0());
test(message1.Int1()==message2.Int1());
test(message1.Int2()==message2.Int2());
test(message1.Int3()==message2.Int3());
RThread client1;
test(message1.Client(client1) == KErrNone);
RThread client2;
test(message2.Client(client2) == KErrNone);
test(client1.Handle()==client2.Handle());
client2.Close();
test.Next(_L("Assignment operator"));
RMessage2 message3(*(RMessage2*) SimpleRMessage);// Pass some rubbish so message3 is definitely != message1
message3=message1;
test(message1.Function()==message3.Function());
test(message1.Int0()==message3.Int0());
test(message1.Int1()==message3.Int1());
test(message1.Int2()==message3.Int2());
test(message1.Int3()==message3.Int3());
RThread client3;
test(message3.Client(client3) == KErrNone);
test(client1.Handle()==client3.Handle());
client3.Close();
client1.Close();
test.End();
}
GLDEF_C TInt E32Main()
{
TInt err;
#ifdef __WINS__
User::SetDebugMask(0xa04); // KSERVER+KTHREAD+KLOGON
#endif
test.Title();
test.Next(_L("Sending messages between two threads"));
TRequestStatus clientStat,killerStat,serverStat;
TInt exitType;
test.Start(_L("Create and start the server"));
sem.CreateLocal(0);
serverThread.Create(_L("Server Thread"),ServerThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,NULL);
serverThread.Logon(serverStat);
serverThread.Resume();
sem.Wait();
for (TInt i=0; serverStat==KRequestPending && i<100; i++)
{
test.Next(_L("Run and kill a client"));
clientName.Format(_L("Client Thread %d"),++clientNumber);
test.Start(_L("Create client and killer threads"));
err=clientThread.Create(clientName,ClientThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,(TAny *)3);
if (err)
test.Panic(_L("!!clientThread .Create failed"), err);
err=killerThread.Create(_L("Killer Thread"),KillerThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,NULL);
if (err)
test.Panic(_L("!!killerThread .Create failed"), err);
test.Next(_L("Logon to the threads"));
clientThread.Logon(clientStat);
killerThread.Logon(killerStat);
test.Next(_L("Start the threads"));
clientThread.Resume();
killerThread.Resume();
test.Next(_L("Wait for the client to stop"));
User::WaitForRequest(clientStat);
test.Next(_L("Wait for the killer to stop"));
User::WaitForRequest(killerStat);
exitType=clientThread.ExitType();
switch (exitType)
{
case EExitKill:
test.Printf(_L(" Client thread killed\n"));
break;
case EExitTerminate:
test.Printf(_L("!!Client thread terminated:"));
test.Panic(clientThread.ExitCategory(), clientThread.ExitReason());
case EExitPanic:
test.Printf(_L("!!Client thread panicked:"));
test.Panic(clientThread.ExitCategory(), clientThread.ExitReason());
default:
test.Panic(_L("!!Client thread did something bizarre"), clientThread.ExitReason());
}
exitType=killerThread.ExitType();
switch (exitType)
{
case EExitKill:
test.Printf(_L(" Killer thread killed\n"));
break;
case EExitTerminate:
test.Printf(_L("!!Killer thread terminated:"));
test.Panic(killerThread.ExitCategory(), killerThread.ExitReason());
case EExitPanic:
test.Printf(_L("!!Killer thread panicked:"));
test.Panic(killerThread.ExitCategory(), killerThread.ExitReason());
//
// To catch a panic put a breakpoint in User::Panic() (in UCDT\UC_UNC.CPP).
//
default:
test.Panic(_L("!!Killer thread did something bizarre"), killerThread.ExitReason());
}
test.Next(_L("Close the threads"));
clientThread.Close();
killerThread.Close();
// test.Next(_L("Pause for 1 second"));
// User::After(1000000);
test.End();
}
test.Next(_L("Close the server thread"));
serverThread.Kill(0); // in case we got through the 100 iterations without killing it
User::WaitForRequest(serverStat);
exitType=serverThread.ExitType();
switch (exitType)
{
case EExitKill:
test.Printf(_L(" Server thread killed\n"));
break;
case EExitTerminate:
test.Printf(_L("!!Server thread terminated:"));
test.Panic(serverThread.ExitCategory(), serverThread.ExitReason());
case EExitPanic:
test.Printf(_L("!!Server thread panicked:"));
test.Panic(serverThread.ExitCategory(), serverThread.ExitReason());
//
// To catch a panic put a breakpoint in User::Panic() (in UCDT\UC_UNC.CPP).
//
default:
test.Panic(_L("!!Server thread did something bizarre"), serverThread.ExitReason());
}
serverThread.Close();
test.End();
test.Next(_L("The Panic() function"));
RThread panicThread;
panicThread.Create(_L("Panic Test Thread"),PanicTestThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,NULL);
TRequestStatus stat;
panicThread.Logon(stat);
// don't want just in time debugging as we trap panics
TBool justInTime=User::JustInTime();
User::SetJustInTime(EFalse);
panicThread.Resume();
User::WaitForRequest(stat);
test(panicThread.ExitType()==EExitPanic);
test(panicThread.ExitCategory().Compare(_L("Testing Panic"))==0);
test(panicThread.ExitReason()==KTestPanic);
panicThread.Close(); //If this Close() is missed out Wins build 48 throws a wobbler when we next connect a server
test.Next(_L("Check it Panics if you try to Complete a message twice"));
test.Start(_L("Create client and server threads"));
clientThread.Create(_L("Client Thread"),CompletePanicClientThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,NULL);
serverThread.Create(_L("Server Thread"),ServerThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,NULL);
test.Next(_L("Logon to the threads"));
clientThread.Logon(clientStat);
serverThread.Logon(serverStat);
test.Next(_L("Start the threads"));
sem.CreateLocal(0);
clientThread.Resume();
serverThread.Resume();
test.Next(_L("Wait for the threads to stop"));
User::WaitForRequest(clientStat);
User::WaitForRequest(serverStat);
test.Next(_L("Check the exit categories"));
test(clientThread.ExitType()==EExitKill);
test(clientThread.ExitCategory().Compare(_L("Kill"))==0);
test(clientThread.ExitReason()==KErrNone);
test(serverThread.ExitType()==EExitPanic);
test(serverThread.ExitCategory().Compare(_L("USER"))==0);
test(serverThread.ExitReason()==ETMesCompletion);
User::SetJustInTime(justInTime);
test.Next(_L("Close the threads"));
clientThread.Close();
serverThread.Close();
test.End();
test.End();
return (KErrNone);
}