sl@0: // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\system\t_trap.cpp sl@0: // Overview: sl@0: // Test TRAP, Leave and Assert sl@0: // API Information: sl@0: // TRAP, User::Leave, __ASSERT_DEBUG_NO_LEAVE, __ASSERT_ALWAYS_NO_LEAVE sl@0: // Details: sl@0: // - Test TRAP macro works as expected. sl@0: // - Test User::Leave works as expected including leave from sl@0: // within nested calls. sl@0: // - Verify that a leave without a TRAP causes the thread to panic. sl@0: // - Create a thread that asserts and verify the exit type and other sl@0: // results are as expected. sl@0: // Platforms/Drives/Compatibility: sl@0: // All. sl@0: // Assumptions/Requirement/Pre-requisites: sl@0: // Failures and causes: sl@0: // Base Port information: sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: sl@0: const TInt KLeaveVal=1111; sl@0: const TInt KUnLeaveVal=2222; sl@0: const TInt KRecursiveUnLeaveVal=3333; sl@0: const TInt KRecursiveSingleLeaveVal=4444; sl@0: const TInt KMaxDepth=20; sl@0: sl@0: //#define __TEST_BREAKPOINT_IN_TRAP__ sl@0: sl@0: LOCAL_D RTest test(_L("T_TRAP")); sl@0: sl@0: sl@0: LOCAL_C TInt UnLeaveFunction(void) sl@0: { sl@0: sl@0: return(KUnLeaveVal); sl@0: } sl@0: sl@0: LOCAL_C TInt LeaveFunction(void) sl@0: { sl@0: sl@0: User::Leave(KLeaveVal); sl@0: return(0); sl@0: } sl@0: sl@0: LOCAL_C TInt RecursiveUnLeave(TInt level) sl@0: { sl@0: sl@0: if (level==0) sl@0: return(KRecursiveUnLeaveVal); sl@0: else sl@0: return(RecursiveUnLeave(--level)); sl@0: } sl@0: sl@0: LOCAL_C TInt RecursiveSingleLeave(TInt level) sl@0: { sl@0: sl@0: if (level==0) sl@0: User::Leave(KRecursiveSingleLeaveVal); sl@0: else sl@0: RecursiveSingleLeave(--level); sl@0: return(0); sl@0: } sl@0: sl@0: LOCAL_C TInt RecursiveMultiLeave1(TInt level) sl@0: { sl@0: sl@0: TInt ret=0; sl@0: TRAP(ret,{if (level==0) User::Leave(level); else ret=RecursiveMultiLeave1(level-1); test(EFalse);}) sl@0: test(ret==level); sl@0: User::Leave(level+1); sl@0: return(0); sl@0: } sl@0: sl@0: LOCAL_C TInt RecursiveMultiLeave2(TInt level) sl@0: { sl@0: sl@0: if (level==0) sl@0: return(1); sl@0: TInt ret=0; sl@0: TRAP(ret,ret=RecursiveMultiLeave2(level-1)) sl@0: test(ret==level); sl@0: User::Leave(level+1); sl@0: return(0); sl@0: } sl@0: sl@0: LOCAL_C TInt doTrap(TInt aVal) sl@0: // sl@0: // Nest trap function. sl@0: // sl@0: { sl@0: sl@0: if (aVal) sl@0: { sl@0: TInt j=(-1); sl@0: TRAP(j,j=doTrap(aVal-1)) sl@0: test(j==aVal); sl@0: } sl@0: return(aVal+1); sl@0: } sl@0: sl@0: #ifdef __TEST_BREAKPOINT_IN_TRAP__ sl@0: void bkpt() sl@0: { sl@0: __BREAKPOINT(); sl@0: } sl@0: #endif sl@0: sl@0: LOCAL_C void doLeave(TInt aLevel,TInt aVal) sl@0: // sl@0: // Nest trap with leave function. sl@0: // sl@0: { sl@0: sl@0: if (aLevel) sl@0: doLeave(aLevel-1,aVal); sl@0: else sl@0: User::Leave(aVal); sl@0: } sl@0: sl@0: LOCAL_C void testTrap() sl@0: // sl@0: // Test trap functions O.K. sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Trap level 1")); sl@0: // sl@0: TInt i=2; sl@0: TRAP(i,i=1); sl@0: test(i==1); sl@0: #ifdef __TEST_BREAKPOINT_IN_TRAP__ sl@0: TRAP(i,bkpt()); sl@0: TRAP(i,TRAP(i,bkpt())); sl@0: #endif sl@0: // sl@0: test.Next(_L("Trap level n")); sl@0: for (i=1;i sl@0: #include sl@0: sl@0: #include "../mmu/mmudetect.h" sl@0: sl@0: const TInt KHeapSize=0x2000; sl@0: sl@0: _LIT(KServerName,"Display"); sl@0: sl@0: class CMySession : public CSession2 sl@0: { sl@0: public: sl@0: CMySession(); sl@0: virtual void ServiceL(const RMessage2& aMessage); sl@0: }; sl@0: sl@0: class CMyServer : public CServer2 sl@0: { sl@0: public: sl@0: enum {ERead,EStop}; sl@0: public: sl@0: CMyServer(TInt aPriority); sl@0: static CMyServer* New(TInt aPriority); sl@0: virtual CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const;//Overloading sl@0: }; sl@0: sl@0: class RDisplay : public RSessionBase sl@0: { sl@0: public: sl@0: TInt Open(); sl@0: void Read(TRequestStatus& aStatus); sl@0: TInt Stop(); sl@0: }; sl@0: sl@0: LOCAL_D RTest testSvr(_L("T_TRAP Server")); sl@0: LOCAL_D RSemaphore client; sl@0: LOCAL_D RSemaphore server; sl@0: LOCAL_D RDisplay display; sl@0: LOCAL_D const RMessage2* message; sl@0: sl@0: // Constructor sl@0: // sl@0: // sl@0: CMySession::CMySession() sl@0: {} sl@0: sl@0: CMyServer* CMyServer::New(TInt aPriority) sl@0: // sl@0: // Create a new CMyServer. sl@0: // sl@0: { sl@0: return new CMyServer(aPriority); sl@0: } sl@0: sl@0: CMyServer::CMyServer(TInt aPriority) sl@0: // sl@0: // Constructor. sl@0: // sl@0: : CServer2(aPriority) sl@0: {} sl@0: sl@0: CSession2* CMyServer::NewSessionL(const TVersion& /*aVersion*/, const RMessage2&) const sl@0: // sl@0: // Create a new client for this server. sl@0: // sl@0: { sl@0: return(new(ELeave) CMySession()); sl@0: } sl@0: sl@0: void CMySession::ServiceL(const RMessage2& aMessage) sl@0: // sl@0: // Handle messages for this server. sl@0: // sl@0: { sl@0: TInt r=KErrNone; sl@0: switch (aMessage.Function()) sl@0: { sl@0: case CMyServer::ERead: sl@0: testSvr.Printf(_L("read message received\n")); sl@0: if (HaveVirtMem()) sl@0: { sl@0: message = &aMessage; sl@0: } sl@0: client.Signal(); sl@0: server.Wait(); sl@0: break; sl@0: case CMyServer::EStop: sl@0: testSvr.Printf(_L("stop message received\n")); sl@0: CActiveScheduler::Stop(); sl@0: break; sl@0: default: sl@0: r=KErrNotSupported; sl@0: } sl@0: aMessage.Complete(r); sl@0: } sl@0: sl@0: TInt RDisplay::Open() sl@0: // sl@0: // Open the server. sl@0: // sl@0: { sl@0: return(CreateSession(KServerName,TVersion(),1)); sl@0: } sl@0: sl@0: void RDisplay::Read(TRequestStatus& aStatus) sl@0: // sl@0: // Get session to test CSession2::ReadL. sl@0: // sl@0: { sl@0: TBuf<0x10>* bad = (TBuf<0x10> *)(0x30000000); sl@0: SendReceive(CMyServer::ERead, TIpcArgs(bad), aStatus); sl@0: } sl@0: sl@0: TInt RDisplay::Stop() sl@0: // sl@0: // Stop the server. sl@0: // sl@0: { sl@0: return SendReceive(CMyServer::EStop, TIpcArgs()); sl@0: } sl@0: sl@0: LOCAL_C TInt serverThreadEntryPoint(TAny*) sl@0: // sl@0: // The entry point for the server thread. sl@0: // sl@0: { sl@0: testSvr.Title(); sl@0: testSvr.Start(_L("Create CActiveScheduler")); sl@0: CActiveScheduler* pR=new CActiveScheduler; sl@0: testSvr(pR!=NULL); sl@0: CActiveScheduler::Install(pR); sl@0: // sl@0: testSvr.Next(_L("Create CMyServer")); sl@0: CMyServer* pS=CMyServer::New(0); sl@0: testSvr(pS!=NULL); sl@0: // sl@0: testSvr.Next(_L("Start CMyServer")); sl@0: TInt r=pS->Start(KServerName); sl@0: testSvr(r==KErrNone); sl@0: // sl@0: testSvr.Next(_L("Signal to client that we have started")); sl@0: client.Signal(); sl@0: // sl@0: testSvr.Next(_L("Start CActiveScheduler")); sl@0: CActiveScheduler::Start(); sl@0: // sl@0: testSvr.Next(_L("Exit server")); sl@0: delete pS; sl@0: testSvr.Close(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: void CreateServer() sl@0: { sl@0: test.Next(_L("Creating client semaphore")); sl@0: TInt r=client.CreateLocal(0); sl@0: test(r==KErrNone); sl@0: // sl@0: test.Next(_L("Creating server semaphore")); sl@0: r=server.CreateLocal(0); sl@0: test(r==KErrNone); sl@0: // sl@0: test.Next(_L("Creating server thread")); sl@0: RThread server; sl@0: r=server.Create(_L("Server"),serverThreadEntryPoint,KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: server.SetPriority(EPriorityMore); sl@0: // sl@0: test.Next(_L("Resume server thread")); sl@0: server.Resume(); sl@0: test(ETrue); sl@0: // sl@0: test.Next(_L("Wait for server to start")); sl@0: client.Wait(); sl@0: // sl@0: test.Next(_L("Connect to server")); sl@0: r=display.Open(); sl@0: test(r==KErrNone); sl@0: } sl@0: sl@0: void StopServer() sl@0: { sl@0: test.Next(_L("Stop server")); sl@0: TInt r=display.Stop(); sl@0: test(r==KErrNone); sl@0: // sl@0: test.Next(_L("Close connection")); sl@0: display.Close(); sl@0: // sl@0: test.Next(_L("Close all")); sl@0: server.Close(); sl@0: client.Close(); sl@0: } sl@0: sl@0: /*============== end of server for testing exceptions in TRAP implementation ====================*/ sl@0: sl@0: #undef TRAP_INSTRUMENTATION_START sl@0: #undef TRAP_INSTRUMENTATION_NOLEAVE sl@0: #undef TRAP_INSTRUMENTATION_LEAVE sl@0: #define TRAP_INSTRUMENTATION_START ++TrapStart; sl@0: #define TRAP_INSTRUMENTATION_NOLEAVE ++TrapNoLeave; TestExcInInstrumentation(); sl@0: #define TRAP_INSTRUMENTATION_LEAVE(aReason) TrapLeave=aReason; sl@0: sl@0: TInt TrapStart = 0; sl@0: TInt TrapNoLeave = 0; sl@0: TInt TrapLeave = 123; sl@0: sl@0: // sl@0: // This is mostly for the benefit of WINS, where Win32 exceptions sl@0: // have a nasty habit of interacting badly with C++ exceptions sl@0: // sl@0: sl@0: void TestExcInInstrumentation() sl@0: { sl@0: TRequestStatus status; sl@0: display.Read(status); sl@0: test(status.Int() == KRequestPending); sl@0: sl@0: client.Wait(); sl@0: sl@0: TBuf<0x100> buf; sl@0: if (message) sl@0: test(message->Read(0,buf) == KErrBadDescriptor); sl@0: sl@0: server.Signal(); sl@0: sl@0: User::WaitForRequest(status); sl@0: test(status.Int() == KErrNone); sl@0: } sl@0: sl@0: void TestTrapInstrumentation() sl@0: { sl@0: CreateServer(); sl@0: sl@0: test.Start(_L("TRAPD No Leave")); sl@0: TRAPD(r,User::LeaveIfError(0)); sl@0: test(TrapStart==1); sl@0: test(TrapLeave==123); sl@0: test(r==0); sl@0: test(TrapNoLeave==1); sl@0: sl@0: test.Next(_L("TRAP No Leave")); sl@0: TRAP(r,User::LeaveIfError(0)); sl@0: test(TrapStart==2); sl@0: test(TrapLeave==123); sl@0: test(r==0); sl@0: test(TrapNoLeave==2); sl@0: sl@0: test.Next(_L("TRAP_IGNORE No Leave")); sl@0: TRAP_IGNORE(User::LeaveIfError(0)); sl@0: test(TrapStart==3); sl@0: test(TrapLeave==123); sl@0: test(TrapNoLeave==3); sl@0: sl@0: test.Next(_L("TRAPD Leave")); sl@0: TRAPD(r2,User::LeaveIfError(-999)); sl@0: test(TrapStart==4); sl@0: test(TrapLeave==-999); sl@0: test(r2==TrapLeave); sl@0: test(TrapNoLeave==3); sl@0: sl@0: test.Next(_L("TRAP Leave")); sl@0: TRAP(r2,User::LeaveIfError(-666)); sl@0: test(TrapStart==5); sl@0: test(TrapLeave==-666); sl@0: test(r2==TrapLeave); sl@0: test(TrapNoLeave==3); sl@0: sl@0: test.Next(_L("TRAP_IGNORE Leave")); sl@0: TRAP_IGNORE(User::LeaveIfError(-333)); sl@0: test(TrapStart==6); sl@0: test(TrapLeave==-333); sl@0: test(TrapNoLeave==3); sl@0: sl@0: test.Next(_L("Leave")); sl@0: test.End(); sl@0: sl@0: StopServer(); sl@0: } sl@0: sl@0: #undef TRAP_INSTRUMENTATION_START sl@0: #undef TRAP_INSTRUMENTATION_NOLEAVE sl@0: #undef TRAP_INSTRUMENTATION_LEAVE sl@0: #define TRAP_INSTRUMENTATION_START sl@0: #define TRAP_INSTRUMENTATION_NOLEAVE sl@0: #define TRAP_INSTRUMENTATION_LEAVE(aReason) sl@0: sl@0: #ifdef __WINS__ sl@0: TUint32* Stack; sl@0: volatile TInt* volatile Q; sl@0: const TInt A[] = {17,19,23,29,31,37,41,43,47,53}; sl@0: sl@0: void ExceptionHandler(TExcType) sl@0: { sl@0: TUint32* sp = Stack; sl@0: for (; *sp!=0xfacefeed; --sp) {} sl@0: *sp = (TUint32)(Q++); sl@0: } sl@0: sl@0: __NAKED__ TInt GetNext() sl@0: { sl@0: _asm mov Stack, esp sl@0: _asm mov eax, 0facefeedh sl@0: _asm mov eax, [eax] sl@0: _asm ret sl@0: } sl@0: sl@0: void testExceptionsInTrap() sl@0: { sl@0: TInt ix = 0; sl@0: TInt r; sl@0: User::SetExceptionHandler(&ExceptionHandler, 0xffffffff); sl@0: Q = (volatile TInt* volatile)A; sl@0: r = GetNext(); sl@0: test(r==A[ix++]); sl@0: TInt i; sl@0: TRAP(i,r=GetNext()); sl@0: test(i==0); sl@0: test(r==A[ix++]); sl@0: TRAP(i,TRAP(i,r=GetNext())); sl@0: test(i==0); sl@0: test(r==A[ix++]); sl@0: TRAP(i, TRAP(i,User::Leave(271));r=GetNext(); ); sl@0: test(i==271); sl@0: test(r==A[ix++]); sl@0: TRAP(i, TRAP(i, TRAP(i,User::Leave(487));r=GetNext(); ); ); sl@0: test(i==487); sl@0: test(r==A[ix++]); sl@0: TInt s=-1; sl@0: TRAP(i, TRAP(i, TRAP(i, TRAP(i,User::Leave(999));r=GetNext(); ); s=GetNext(); ); ); sl@0: test(i==999); sl@0: test(r==A[ix++]); sl@0: test(s==A[ix++]); sl@0: TInt j=-1, k=-1, l=-1; sl@0: TRAP(l, \ sl@0: TRAP(k, \ sl@0: TRAP(j, \ sl@0: TRAP(i,User::Leave(9991)); \ sl@0: r=GetNext(); \ sl@0: ); \ sl@0: User::Leave(9992); \ sl@0: ); \ sl@0: s=GetNext(); \ sl@0: ); sl@0: test(i==9991); sl@0: test(j==0); sl@0: test(k==9992); sl@0: test(l==0); sl@0: test(r==A[ix++]); sl@0: test(s==A[ix++]); sl@0: } sl@0: #endif sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: test.Title(); sl@0: // sl@0: test.Start(_L("Trap")); sl@0: testTrap(); sl@0: // sl@0: test.Next(_L("Leave")); sl@0: testLeave(); sl@0: // sl@0: test.Next(_L("Assorted")); sl@0: testMH(); sl@0: // sl@0: test.Next(_L("Leave without Trap")); sl@0: TestLeaveNoTrap(); sl@0: // sl@0: test.Next(_L("Assertions")); sl@0: TestAssert(0); sl@0: TestAssert(EAssertTest_Debug); sl@0: TestAssert(EAssertTest_Leave); sl@0: TestAssert(EAssertTest_Leave | EAssertTest_Debug); sl@0: sl@0: #ifdef __LEAVE_EQUALS_THROW__ sl@0: test.Next(_L("Trap instrumentation")); sl@0: TestTrapInstrumentation(); sl@0: #endif sl@0: sl@0: #ifdef __WINS__ sl@0: testExceptionsInTrap(); sl@0: #endif sl@0: sl@0: test.End(); sl@0: return(0); sl@0: }