diff -r 000000000000 -r a41df078684a kerneltest/e32test/active/t_messge.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/active/t_messge.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,686 @@ +// Copyright (c) 1995-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\active\t_messge.cpp +// Overview: +// Test the RMessage2 and RMessagePtr2 classes. +// API Information: +// RMessage2, RMessagePtr2, RSessionBase, CSession2, CServer2 +// Details: +// - Verify copy constructor and assignment operator of Rmessage2 is implemented correctly. +// - Verify default constructor, copy constructor and assignment operator of RMessagePtr2 +// is implemented correctly, construct RMessagePtr2 from pointer to RMessage2 and verify +// that it is constructed successfully. +// - Create client and server threads, open a session with specified number of message slots +// - Send integer message arguments from client and test that the server receives the +// same integers. +// - Send pointers as message arguments from client and test that the server receives the +// same pointers. +// - Test Client() method of RMessage2 and verify it opened a handle to the client thread +// - Complete several messages using RMessage2::Complete and verify the client gets the +// error codes back correctly. +// - Complete several messages using RMessagePtr2::Complete and verify the client gets the +// error codes back correctly. +// - Check RMessage construction from RMessagePtr2 is successful. +// - Check creation of other sessions to the same server is successful. +// - Check the server return KErrServerBusy when client has more outstanding requests than +// available message slots. +// - Send stop signal and check that the server has stopped as expected. +// - Check the client and server have exited as expected. +// - Create client and server threads, open a connection to the server and verify that +// - Server is panicked when completing a message twice. +// Platforms/Drives/Compatibility: +// All. +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// Base Port information: +// +// + +#include +#include +#include +#include + +const TInt KHeapMinSize=0x1000; +const TInt KHeapMaxSize=0x1000; + +_LIT(KServerName,"CTestServer"); + +class CTestServer : public CServer2 + { +public: + IMPORT_C CTestServer(TInt aPriority); + enum TPanicType{ + EInt0Error=1, EInt1Error, EInt2Error, EInt3Error, + EPtr0Error, EPtr1Error, EPtr2Error, EPtr3Error, + ECreateNameError, ENewSessionError, + EClientError + }; + static void Panic(TPanicType aReason); +protected: + //override the pure virtual functions: + IMPORT_C virtual CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const; + }; + + +class CTestSession : public CSession2 + { +public: + enum {EStop,ETestInt,ETestPtr,ETestClient,ETestComplete,ETestPtrComplete,ETestCompletePanic,ETestOtherSession,ETestCompleteAfter,ETestMessageConstruction, ETestRMessagePtr2LeavingInterface}; +//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 TestMessageConstruction(const RMessage2& aMessage); + TInt TestRMessagePtr2LeavingInterface(const RMessage2& aMessage); + // + 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 &aPtr) + { + return (SendReceive(aFunction, aPtr)); + } + void PublicSendReceive(TInt aFunction, const TIpcArgs &aPtr, TRequestStatus& aStatus) + { + SendReceive(aFunction, aPtr, 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& /*aMessage*/) 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; + +void CTestServer::Panic(TPanicType aReason) //static function + { + clientThread.Kill(KErrNone); + User::Panic(_L("CTestServer"),aReason); + } + +RSession session, otherSession; +RSemaphore sem; + +const TInt KTestInt[] = {-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}; + +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); + } + +void CTestSession::TestClient(const RMessage2& aMessage) +// +// Tests Client() +// + { + + TFullName n=RProcess().Name(); + n+=_L("::Client Thread"); + RThread t; + TInt r=aMessage.Client(t); + if (r!=KErrNone) + User::Invariant(); + if (t.FullName().CompareF(n)!=0) + { + clientThread.Kill(0); + CTestServer::Panic(CTestServer::EClientError); + } + t.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; + __ASSERT_ALWAYS(!messagePtrs[count2].IsNull(), User::Invariant()); + if (++count2==5) + for(count2=4; count2>=0; count2--) + { + messagePtrs[count2].Complete(10-count2*2); + __ASSERT_ALWAYS(messagePtrs[count2].IsNull(), User::Invariant()); + } + } + + + +TInt CTestSession::TestMessageConstruction(const RMessage2& aMessage) + { + RMessage2 m2((RMessagePtr2&)aMessage); + if(m2!=aMessage) + return KErrGeneral; + return KErrNone; + } + +TInt CTestSession::TestRMessagePtr2LeavingInterface(const RMessage2& aMessage) + { + RThread thread1, thread2; + TProcessPriority priority = EPriorityForeground; + + //Check that both Client and ClientL methods return the same thread and error code. + if (aMessage.Client(thread1)) + return KErrGeneral; + + TRAPD(r1, aMessage.ClientL(thread2)) + if (KErrNone != r1) + { + thread1.Close(); + return r1; + } + if (thread1.Id() != thread2.Id()) + { + thread1.Close(); + thread2.Close(); + return KErrBadHandle; + } + + //Check that both SetPriority & SetPriorityL methods return the same error code + r1 = aMessage.SetProcessPriority(priority); + TRAPD(r2, aMessage.SetProcessPriorityL(priority)) + + thread1.Close(); + thread2.Close(); + if (r1 != r2) + return KErrGeneral; + + return KErrNone; + } + +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; + case ETestMessageConstruction: + r=TestMessageConstruction(aMessage); + break; + case ETestRMessagePtr2LeavingInterface: + r=TestRMessagePtr2LeavingInterface(aMessage); + break; + default: + r=KErrNotSupported; + + } + aMessage.Complete(r); + + } + +// CTestSession funtions + +void CMyActiveScheduler::Error(TInt anError) const +// +// Virtual error handler +// + { + User::Panic(_L("CMyActiveScheduer::Error"), anError); + } + +#include + +TInt ClientThread(TAny*) +// +// Passed as the first client thread - signals the server to do several tests +// + { + RTest test(_L("T_MESSGE...client")); + + test.Title(); + test.Start(_L("Wait for server to start")); + sem.Wait(); + + test.Next(_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,TIpcArgs(-3866,30566,0,200) ); + test(r==KErrNone); + + test.Next(_L("Signal to test Ptr0/1/2/3()")); + + r=session.PublicSendReceive(CTestSession::ETestPtr, TIpcArgs(&clientThread, &serverThread, &session, &sem)); + 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("Test RMessage contruction from Ptr")); + if(UserSvr::IpcV1Available()) + { + r=session.PublicSendReceive(CTestSession::ETestMessageConstruction, TIpcArgs(111,222,333,444)); + test(r==KErrNone); + } + else + { + test.Printf(_L("NOT TESTED - IPC V1 is not supported by system")); + } + + test.Next(_L("Test RMessagePtr leaving interface")); + r=session.PublicSendReceive(CTestSession::ETestRMessagePtr2LeavingInterface, TIpcArgs()); + test(r==KErrNone); + + 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("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.Next(_L("Signal to stop ActiveScheduler")); + session.PublicSendReceive(CTestSession::EStop, TIpcArgs()); + session.Close(); + otherSession.PublicSendReceive(CTestSession::EStop, TIpcArgs()); + otherSession.Close(); + test.Close(); + + return (KErrNone); + } + +TInt ServerThread(TAny*) +// +// Passed as the server thread in 2 tests - sets up and runs CTestServer +// + { + RTest test(_L("T_MESSGE...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(KServerName);//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_MESSGE 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()); + + test.Next(_L("Assignment operator")); + RMessage2 message3; + Mem::Fill(&message3,sizeof(message3),0xb9); // first fill message 3 with rubbish + 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()); + + test.End(); + } + +void SimpleRMessagePtr() +// +// Simple RMessagePtr2 tests - constructors and assignment +// + { + test.Start(_L("Default constructor")); + RMessagePtr2 messagePtr1; + test(messagePtr1.IsNull()); + + test.Next(_L("Copy constructor")); + RMessagePtr2 messagePtr2(messagePtr1); + test(messagePtr2.IsNull()); + + test.Next(_L("Constructor from pointer to RMessage2")); + RMessage2 message; + messagePtr1= message; + + test.Next(_L("Assignment operator")); + messagePtr1=messagePtr2; + + test.End(); + } + + +GLDEF_C TInt E32Main() + { + test.Title(); + + test.Start(_L("Simple RMessage2 tests")); + SimpleRMessage(); + + test.Next(_L("Simple RMessagePtr2 tests")); + SimpleRMessagePtr(); + + test.Next(_L("Sending messages between two threads")); + test.Start(_L("Create client and server threads")); + clientThread.Create(_L("Client Thread"),ClientThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,NULL); + serverThread.Create(_L("Server Thread"),ServerThread,KDefaultStackSize,KHeapMinSize,KHeapMaxSize,NULL); + + test.Next(_L("Logon to the threads")); + TRequestStatus clientStat,serverStat; + 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")); + if(clientStat==KRequestPending) + User::WaitForRequest(clientStat); + if(serverStat==KRequestPending) + User::WaitForRequest(serverStat); + switch (clientThread.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.Panic(_L("!!Client thread panicked:")); + test.Panic(clientThread.ExitCategory(), clientThread.ExitReason()); + default: + test.Panic(_L("!!Client thread did something bizarre"), clientThread.ExitReason()); + } + switch (serverThread.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()); + } + + test.Next(_L("Close the threads")); + CLOSE_AND_WAIT(serverThread); + CLOSE_AND_WAIT(clientThread); + test.End(); + + TBool justInTime=User::JustInTime(); + + 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 Thread1"),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); + User::SetJustInTime(EFalse); + clientThread.Resume(); + serverThread.Resume(); + + test.Next(_L("Wait for the threads to stop")); + User::WaitForRequest(clientStat); // + User::WaitForRequest(serverStat); + User::SetJustInTime(justInTime); + 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); + + test.Next(_L("Close the threads")); + CLOSE_AND_WAIT(serverThread); + CLOSE_AND_WAIT(clientThread); + test.End(); + + test.End(); + + return (KErrNone); + } + +