diff -r 000000000000 -r a41df078684a kerneltest/e32test/thread/t_killer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/thread/t_killer.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,672 @@ +// 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 +#include +#include +#include +#include + +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); + } +