sl@0: // Copyright (c) 2002-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\mqueue\t_mqueue.cpp sl@0: // Overview: sl@0: // Test message queuing sl@0: // API Information: sl@0: // RMsgQueue, RMsgQueueBase sl@0: // Details: sl@0: // - Create various illegal and legal private message queues and verify sl@0: // results are as expected. Test private message queue functionality in sl@0: // both single threaded tests and multi-threaded tests. sl@0: // - Create various illegal and legal global named message queues and verify sl@0: // results are as expected. Test global named message queue functionality sl@0: // in both single threaded tests and multi-threaded tests. sl@0: // - Test multi-process queues and template based queues, verify results are sl@0: // 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: #include sl@0: #include sl@0: sl@0: LOCAL_D RTest test(_L("t_mqueue")); sl@0: sl@0: //if the test is to run under the debugger, uncomment the following line sl@0: //#define _DEBUGGER_BUILD sl@0: sl@0: const TInt KHeapSize=0x2000; sl@0: const TInt KTestValue = 42; sl@0: _LIT8(KFillPattern, "1234567890"); sl@0: sl@0: _LIT(KGLobalName1, "GlobalMessageQueue1"); sl@0: sl@0: sl@0: LOCAL_C void SingleThreadedTests(RMsgQueueBase& aQueue, TInt aSlots, TInt aSize) sl@0: { sl@0: test.Printf(_L("Single Threaded Tests")); sl@0: sl@0: sl@0: TRequestStatus stat; sl@0: test.Next(_L("test CancelDataAvailable")); sl@0: aQueue.NotifyDataAvailable(stat); sl@0: test (stat == KRequestPending); sl@0: aQueue.CancelDataAvailable(); sl@0: User::WaitForRequest(stat); sl@0: test (stat == KErrCancel); sl@0: sl@0: TUint8 * pSourceData = (TUint8*)User::Alloc(aSize*2); sl@0: test(pSourceData != NULL); sl@0: TPtr8 pS(pSourceData, aSize*2, aSize*2); sl@0: pS.Repeat(KFillPattern); sl@0: sl@0: TUint8 * pDestinationData = (TUint8*)User::Alloc(aSize*2); sl@0: test(pDestinationData != NULL); sl@0: TPtr8 pD(pDestinationData, aSize*2, aSize*2); sl@0: pD.FillZ(); sl@0: sl@0: sl@0: test.Next(_L("test MessageSize")); sl@0: test(aQueue.MessageSize() == aSize); sl@0: sl@0: sl@0: test.Next(_L("Send a legal message through")); sl@0: TInt ret = aQueue.Send(pSourceData, aSize); sl@0: test(ret == KErrNone); sl@0: sl@0: test.Next(_L("Receive legal message")); sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: TPtr8 p(pS); sl@0: p.SetLength(aSize); sl@0: pD.SetLength(aSize); sl@0: test(p == pD); sl@0: pD.FillZ(); sl@0: sl@0: test.Next(_L("Send a short message through")); sl@0: ret = aQueue.Send(pSourceData, aSize/2); sl@0: test(ret == KErrNone); sl@0: sl@0: test.Next(_L("Receive legal message")); sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: p.SetLength(aSize/2); sl@0: pD.SetLength(aSize/2); sl@0: test(p == pD); sl@0: pD.FillZ(); sl@0: sl@0: test.Next(_L("Test Receive with no message")); sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrUnderflow); sl@0: sl@0: if (aSlots >= 2) sl@0: { sl@0: test.Next(_L("Send two legal messages through")); sl@0: pS[0] = 0; sl@0: ret = aQueue.Send(pSourceData, aSize); sl@0: test(ret == KErrNone); sl@0: pS[0] = 1; sl@0: ret = aQueue.Send(pSourceData, aSize); sl@0: test(ret == KErrNone); sl@0: sl@0: test.Next(_L("Receive two legal messages in tx order")); sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: test(pD[0] == 0); sl@0: pD.FillZ(); sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: test(pD[0] == 1); sl@0: pD.FillZ(); sl@0: sl@0: } sl@0: sl@0: test.Next(_L("Test filling the queue to the max")); sl@0: TInt x; sl@0: for (x = 0; x < aSlots; x++) sl@0: { sl@0: pS[0] = (TUint8)x; sl@0: ret = aQueue.Send(pSourceData, aSize); sl@0: test(ret == KErrNone); sl@0: } sl@0: sl@0: test.Next(_L("Test one too many sends")); sl@0: ret = aQueue.Send(pSourceData, aSize); sl@0: test(ret == KErrOverflow); sl@0: sl@0: test.Next(_L("test cancel SpaceAvailable")); sl@0: aQueue.NotifySpaceAvailable(stat); sl@0: test (stat == KRequestPending); sl@0: aQueue.CancelSpaceAvailable(); sl@0: User::WaitForRequest(stat); sl@0: test (stat == KErrCancel); sl@0: sl@0: sl@0: test.Next(_L("Test emptying the queue")); sl@0: sl@0: for (x = 0; x < aSlots; x++) sl@0: { sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: test(pD[0] == (TUint8)x ); sl@0: pD.FillZ(); sl@0: } sl@0: sl@0: test.Next(_L("test cancel DataAvailable")); sl@0: aQueue.NotifyDataAvailable(stat); sl@0: test (stat == KRequestPending); sl@0: aQueue.CancelDataAvailable(); sl@0: User::WaitForRequest(stat); sl@0: test (stat == KErrCancel); sl@0: sl@0: test.Next(_L("Test one too many receives")); sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrUnderflow); sl@0: sl@0: sl@0: test.Next(_L("Test wrap around")); sl@0: test.Printf(_L("fill queue to max\n")); sl@0: for (x = 0; x < aSlots; x++) sl@0: { sl@0: pS[0] = (TUint8)x; sl@0: ret = aQueue.Send(pSourceData, aSize); sl@0: test(ret == KErrNone); sl@0: } sl@0: sl@0: test.Printf(_L("half empty the queue\n")); sl@0: for (x = 0; x < aSlots/2; x++) sl@0: { sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: test(pD[0] == (TUint8)x); sl@0: pD.FillZ(); sl@0: } sl@0: sl@0: test.Printf(_L("fill queue to max\n")); sl@0: for (x = 0; x < aSlots/2; x++) sl@0: { sl@0: pS[0] = (TUint8)x; sl@0: ret = aQueue.Send(pSourceData, aSize); sl@0: test (ret == KErrNone); sl@0: } sl@0: ret = aQueue.Send(pSourceData, aSize); sl@0: test (ret == KErrOverflow); sl@0: sl@0: test.Printf(_L("empty the queue\n")); sl@0: for (x = aSlots/2; x < aSlots; x++) sl@0: { sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: test(pD[0] == (TUint8)x); sl@0: } sl@0: for (x = 0; x < aSlots/2; x++) sl@0: { sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrNone); sl@0: test(pD[0] == (TUint8)x); sl@0: } sl@0: sl@0: test.Next(_L("Test queue is empty")); sl@0: ret = aQueue.Receive(pDestinationData, aSize); sl@0: test(ret == KErrUnderflow); sl@0: sl@0: User::Free(pSourceData); sl@0: User::Free(pDestinationData); sl@0: } sl@0: sl@0: sl@0: _LIT(KThread2Name, "thread2"); sl@0: _LIT(KThread3Name, "thread3"); sl@0: _LIT(KThread4Name, "thread4"); sl@0: sl@0: sl@0: class TData sl@0: { sl@0: public: sl@0: TData(RMsgQueueBase* aQ, TInt aSize, TInt aSlots,TInt aTest=0, TAny* aData=NULL); sl@0: RMsgQueueBase* iQueue; sl@0: TInt iSize; sl@0: TInt iSlots; sl@0: TInt iTest; sl@0: TAny* iData; sl@0: }; sl@0: sl@0: TData::TData(RMsgQueueBase* aQ, TInt aSize, TInt aSlots, TInt aTest, TAny* aData) : iQueue(aQ), iSize(aSize), sl@0: iSlots(aSlots), iTest(aTest), iData(aData) sl@0: { sl@0: //empty sl@0: }; sl@0: sl@0: sl@0: sl@0: LOCAL_C TInt illegalSendEntryPoint(TAny* aData) sl@0: { sl@0: sl@0: TData& data = *(TData *)aData; sl@0: sl@0: switch (data.iTest) sl@0: { sl@0: case 0: sl@0: data.iQueue->Send(data.iData, data.iSize*2); //should panic, message size incorrect sl@0: break; sl@0: sl@0: case 1: sl@0: #ifdef _DEBUGGER_BUILD sl@0: #pragma message ("BUILT FOR DEBUGGER") sl@0: User::Panic(_L("test"),ECausedException); sl@0: #else sl@0: data.iQueue->Send((TAny*)0xfeed, data.iSize); //should panic sl@0: #endif sl@0: break; sl@0: sl@0: case 2: sl@0: #ifdef _DEBUGGER_BUILD sl@0: #pragma message ("BUILT FOR DEBUGGER") sl@0: User::Panic(_L("test"),ECausedException); sl@0: #else sl@0: data.iQueue->Send((TAny*)0xDEDEDEDE, data.iSize); //dodgy address sl@0: #endif sl@0: break; sl@0: } sl@0: sl@0: test(0); //should never get here. This'll make a Kern Exec 0! as tries to use console from different thread sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: LOCAL_C TInt illegalReceiveEntryPoint(TAny* aData) sl@0: { sl@0: sl@0: TData& data = *(TData *)aData; sl@0: TUint8 buf[256]; sl@0: sl@0: switch (data.iTest) sl@0: { sl@0: case 0: sl@0: data.iQueue->Receive(buf, data.iSize*2); //should panic, message size incorrect sl@0: break; sl@0: sl@0: case 1: sl@0: #ifdef _DEBUGGER_BUILD sl@0: #pragma message ("BUILT FOR DEBUGGER") sl@0: User::Panic(_L("test"),ECausedException); sl@0: #else sl@0: data.iQueue->Receive((TAny*)0xfeed, data.iSize); //should panic sl@0: #endif sl@0: break; sl@0: sl@0: case 2: sl@0: #ifdef _DEBUGGER_BUILD sl@0: #pragma message ("BUILT FOR DEBUGGER") sl@0: User::Panic(_L("test"),ECausedException); sl@0: #else sl@0: data.iQueue->Receive((TAny*)0xDEDEDEDE, data.iSize); //dodgy address sl@0: #endif sl@0: break; sl@0: sl@0: } sl@0: sl@0: test(0); //should never get here. This'll make a Kern Exec 0! sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: sl@0: LOCAL_C TInt sendBlockingEntryPoint(TAny* aData) sl@0: { sl@0: TData& data = *(TData *)aData; sl@0: sl@0: TInt d = KTestValue; sl@0: data.iQueue->SendBlocking(&d, 4); sl@0: return KErrNone; sl@0: } sl@0: sl@0: LOCAL_C TInt receiveBlockingEntryPoint(TAny* aData) sl@0: { sl@0: TData& data = *(TData *)aData; sl@0: sl@0: TUint8 pData[256]; sl@0: TPtr8 pD(pData, data.iSize, data.iSize); sl@0: pD.FillZ(); sl@0: data.iQueue->ReceiveBlocking(pData, data.iSize); sl@0: test (*(TInt*)pData == KTestValue); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: LOCAL_C TInt notifyDataAvailableEntryPoint(TAny* aData) sl@0: { sl@0: TData& data = *(TData *)aData; sl@0: sl@0: //check size as well sl@0: test(data.iQueue->MessageSize() == data.iSize); sl@0: sl@0: TRequestStatus stat; sl@0: data.iQueue->NotifyDataAvailable(stat); sl@0: User::WaitForRequest(stat); sl@0: return KErrNone; sl@0: } sl@0: sl@0: LOCAL_C TInt notifySpaceAvailableEntryPoint(TAny* aData) sl@0: { sl@0: TData& data = *(TData *)aData; sl@0: sl@0: TRequestStatus stat; sl@0: data.iQueue->NotifySpaceAvailable(stat); sl@0: User::WaitForRequest(stat); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: sl@0: LOCAL_C void MultiThreadedTests(RMsgQueueBase& aQueue, TInt aSlots, TInt aSize) sl@0: { sl@0: test.Next(_L("multi threaded tests")); sl@0: RThread thread2; sl@0: TInt ret = KErrNone; sl@0: sl@0: TAny* ptr = User::Alloc(aSize); sl@0: sl@0: test.Next(_L("test Send with illegal parameters")); sl@0: TInt testnum; sl@0: TBool jit = User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: for (testnum = 0; testnum < 3; testnum++) //testnum range is determined by the number of tests in illegalSendEntryPoint sl@0: { sl@0: TData data(&aQueue, aSize, aSlots, testnum, ptr); sl@0: ret = thread2.Create(KThread2Name, illegalSendEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: TRequestStatus thread2stat; sl@0: thread2.Logon(thread2stat); sl@0: thread2.Resume(); sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2.ExitType() == EExitPanic); sl@0: switch (testnum) sl@0: { sl@0: case 0: sl@0: test (thread2.ExitReason() == EMsgQueueInvalidLength); sl@0: break; sl@0: case 1: sl@0: test (thread2.ExitReason() == ECausedException); sl@0: break; sl@0: case 2: sl@0: test (thread2.ExitReason() == ECausedException); sl@0: break; sl@0: } sl@0: sl@0: CLOSE_AND_WAIT(thread2); sl@0: } sl@0: sl@0: sl@0: User::SetJustInTime(jit); sl@0: sl@0: sl@0: test.Next(_L("test Receive with illegal parameters")); sl@0: jit = User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: sl@0: sl@0: for (testnum = 0; testnum < 3; testnum++) //testnum range is determined by the number of tests in illegalReceiveEntryPoint sl@0: { sl@0: //put something in the queue sl@0: aQueue.Send(&testnum, 4); sl@0: TData data(&aQueue, aSize, aSlots, testnum, ptr); sl@0: ret = thread2.Create(KThread2Name, illegalReceiveEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: TRequestStatus thread2stat; sl@0: thread2.Logon(thread2stat); sl@0: thread2.Resume(); sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2.ExitType() == EExitPanic); sl@0: sl@0: switch (testnum) sl@0: { sl@0: case 0: sl@0: test (thread2.ExitReason() == EMsgQueueInvalidLength); sl@0: break; sl@0: case 1: sl@0: test (thread2.ExitReason() == ECausedException); sl@0: break; sl@0: case 2: sl@0: test (thread2.ExitReason() == ECausedException); sl@0: break; sl@0: } sl@0: sl@0: CLOSE_AND_WAIT(thread2); sl@0: } sl@0: sl@0: sl@0: User::SetJustInTime(jit); sl@0: sl@0: while(KErrNone == aQueue.Receive(ptr, aSize)) //empty the queue sl@0: { sl@0: //empty, sl@0: } sl@0: sl@0: test.Next(_L("multi threaded NotifySpaceAvailable")); sl@0: sl@0: TInt dummydata = KTestValue; sl@0: //fill the queue sl@0: while (KErrNone == aQueue.Send(&dummydata, sizeof (TInt))) sl@0: { sl@0: //empty sl@0: } sl@0: sl@0: TData data(&aQueue, aSize, aSlots); sl@0: ret = thread2.Create(KThread2Name, notifySpaceAvailableEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: TRequestStatus thread2stat; sl@0: thread2.Logon(thread2stat); sl@0: thread2.Resume(); sl@0: sl@0: //thread2 should be waiting for space available sl@0: test (thread2stat == KRequestPending); sl@0: aQueue.ReceiveBlocking(ptr, aSize); sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2stat == KErrNone); sl@0: test (thread2.ExitType() == EExitKill); sl@0: CLOSE_AND_WAIT(thread2); sl@0: //thread 2 has exited OK sl@0: sl@0: //empty the queue sl@0: while (KErrNone == aQueue.Receive(ptr, aSize)) sl@0: { sl@0: //empty sl@0: } sl@0: sl@0: sl@0: test.Next(_L("multi threaded SendBlocking, ReceiveBlocking")); sl@0: ret = thread2.Create(KThread2Name, receiveBlockingEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: thread2.Logon(thread2stat); sl@0: thread2.Resume(); sl@0: sl@0: aQueue.SendBlocking(&dummydata, sizeof (TInt)); sl@0: sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2.ExitType() == EExitKill); sl@0: CLOSE_AND_WAIT(thread2); sl@0: sl@0: sl@0: test.Next(_L("multiple ReceiveBlocking")); sl@0: ret = thread2.Create(KThread2Name, receiveBlockingEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: sl@0: RThread thread3; sl@0: ret = thread3.Create(KThread3Name, receiveBlockingEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: sl@0: RThread thread4; sl@0: ret = thread4.Create(KThread4Name, receiveBlockingEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: sl@0: thread2.Logon(thread2stat); sl@0: sl@0: TRequestStatus thread3stat; sl@0: thread3.Logon(thread3stat); sl@0: sl@0: TRequestStatus thread4stat; sl@0: thread4.Logon(thread4stat); sl@0: sl@0: thread2.Resume(); sl@0: User::After(500000); sl@0: sl@0: jit = User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: sl@0: thread3.Resume(); sl@0: thread4.Resume(); sl@0: sl@0: sl@0: User::WaitForRequest(thread3stat, thread4stat); sl@0: if (thread3stat != KRequestPending) sl@0: User::WaitForRequest(thread4stat); sl@0: else sl@0: User::WaitForRequest(thread3stat); sl@0: User::SetJustInTime(jit); sl@0: sl@0: //threads 3 and 4 have exited sl@0: test (thread3.ExitType() == EExitPanic); sl@0: test (thread3.ExitReason() == EMsgQueueRequestPending); sl@0: test (thread4.ExitType() == EExitPanic); sl@0: test (thread4.ExitReason() == EMsgQueueRequestPending); sl@0: sl@0: test (thread2stat == KRequestPending); sl@0: aQueue.SendBlocking(&dummydata, sizeof (TInt)); sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2stat == KErrNone); sl@0: test (thread2.ExitType() == EExitKill); sl@0: sl@0: CLOSE_AND_WAIT(thread2); sl@0: CLOSE_AND_WAIT(thread3); sl@0: CLOSE_AND_WAIT(thread4); sl@0: sl@0: sl@0: //fill the queue sl@0: while (KErrNone == aQueue.Send(&dummydata, sizeof (TInt))) sl@0: { sl@0: //empty sl@0: } sl@0: sl@0: test.Next(_L("multiple sendblocking")); sl@0: ret = thread2.Create(KThread2Name, sendBlockingEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: ret = thread3.Create(KThread3Name, sendBlockingEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: ret = thread4.Create(KThread4Name, sendBlockingEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: sl@0: thread2.Logon(thread2stat); sl@0: thread3.Logon(thread3stat); sl@0: thread4.Logon(thread4stat); sl@0: sl@0: thread2.Resume(); sl@0: User::After(500000); sl@0: sl@0: jit = User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: thread3.Resume(); sl@0: thread4.Resume(); sl@0: User::WaitForRequest(thread3stat, thread4stat); sl@0: if (thread3stat != KRequestPending) sl@0: User::WaitForRequest(thread4stat); sl@0: else sl@0: User::WaitForRequest(thread3stat); sl@0: User::SetJustInTime(jit); sl@0: sl@0: //threads 3 and 4 have exited sl@0: test (thread3.ExitType() == EExitPanic); sl@0: test (thread3.ExitReason() == EMsgQueueRequestPending); sl@0: test (thread4.ExitType() == EExitPanic); sl@0: test (thread4.ExitReason() == EMsgQueueRequestPending); sl@0: sl@0: test (thread2stat == KRequestPending); sl@0: sl@0: //consume one to allow the blocking write sl@0: test(KErrNone == aQueue.Receive(ptr, aSize)); sl@0: sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2stat == KErrNone); sl@0: test (thread2.ExitType() == EExitKill); sl@0: sl@0: //consume the rest of the queue sl@0: while (KErrNone == aQueue.Receive(ptr, aSize)) sl@0: { sl@0: // empty sl@0: } sl@0: sl@0: CLOSE_AND_WAIT(thread2); sl@0: CLOSE_AND_WAIT(thread3); sl@0: CLOSE_AND_WAIT(thread4); sl@0: sl@0: sl@0: test.Next(_L("multi threaded NotifyDataAvailable")); sl@0: ret = thread2.Create(KThread2Name, notifyDataAvailableEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: thread2.Logon(thread2stat); sl@0: thread2.Resume(); sl@0: sl@0: //thread2 should be waiting for data available sl@0: test (thread2stat == KRequestPending); sl@0: aQueue.SendBlocking(&dummydata, sizeof (TInt)); sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2stat == KErrNone); sl@0: test (thread2.ExitType() == EExitKill); sl@0: CLOSE_AND_WAIT(thread2); sl@0: //thread 2 has exited OK sl@0: sl@0: //empty the queue sl@0: aQueue.ReceiveBlocking(ptr, aSize); sl@0: test (*(TInt*)ptr == dummydata); sl@0: sl@0: //create thread 2 again sl@0: ret = thread2.Create(KThread2Name, notifyDataAvailableEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: thread2.Logon(thread2stat); sl@0: thread2.Resume(); sl@0: sl@0: //create thread3 sl@0: ret = thread3.Create(KThread3Name, notifyDataAvailableEntryPoint, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: thread3.Logon(thread3stat); sl@0: User::SetJustInTime(EFalse); sl@0: User::After(10000); sl@0: thread3.Resume(); sl@0: sl@0: User::WaitForRequest(thread3stat); sl@0: User::SetJustInTime(jit); sl@0: sl@0: test (thread3.ExitType() == EExitPanic); sl@0: test (thread3.ExitReason() == EMsgQueueRequestPending); sl@0: CLOSE_AND_WAIT(thread3); sl@0: sl@0: aQueue.SendBlocking(&dummydata, sizeof (TInt)); sl@0: User::WaitForRequest(thread2stat); sl@0: test (thread2stat == KErrNone); sl@0: test (thread2.ExitType() == EExitKill); sl@0: CLOSE_AND_WAIT(thread2); sl@0: sl@0: //empty the queue sl@0: aQueue.ReceiveBlocking(ptr, aSize); sl@0: test (*(TInt*)ptr == dummydata); sl@0: sl@0: User::Free(ptr); sl@0: } sl@0: sl@0: sl@0: class TTemplateTestData sl@0: { sl@0: public: sl@0: TTemplateTestData(); sl@0: TTemplateTestData(TInt a, TUint b, TUint8 c, TBool d, TInt e); sl@0: TInt first; sl@0: TUint second; sl@0: TUint8 bob; sl@0: TBool fred; sl@0: TInt chipper; sl@0: }; sl@0: sl@0: TTemplateTestData::TTemplateTestData() : first(0), second(0), bob(0), fred(0), chipper(0) sl@0: { sl@0: } sl@0: sl@0: TTemplateTestData::TTemplateTestData(TInt a, TUint b, TUint8 c, TBool d, TInt e) : first(a), second(b), bob(c), fred(d), chipper(e) sl@0: { sl@0: } sl@0: sl@0: sl@0: enum TQueueType {ECreateLocal, ECreateGlobal}; sl@0: sl@0: LOCAL_C TInt illegalQueueCreation(TAny* aData) sl@0: { sl@0: TData& data = *(TData *)aData; sl@0: switch (data.iTest) sl@0: { sl@0: case ECreateLocal: //CreateLocal sl@0: { sl@0: RMsgQueueBase queue; sl@0: queue.CreateLocal(data.iSlots, data.iSize); sl@0: break; sl@0: } sl@0: case ECreateGlobal: //create global named sl@0: { sl@0: RMsgQueueBase queue; sl@0: queue.CreateGlobal(KGLobalName1, data.iSlots, data.iSize); sl@0: break; sl@0: } sl@0: } sl@0: test(0); //should never get here. This'll make a Kern Exec 0! as tries to use console from different thread sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: LOCAL_C void TestIllegalCreation(TInt aSlots, TInt aSize, TQueueType aQueueType, TInt aExpectedReason) sl@0: { sl@0: RThread thread; sl@0: TData data(NULL, aSize, aSlots, aQueueType, NULL); sl@0: TRequestStatus threadstat; sl@0: TBool jit = User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: TInt ret = thread.Create(KThread2Name, illegalQueueCreation, KDefaultStackSize, KHeapSize, KHeapSize, &data); sl@0: test(KErrNone == ret); sl@0: thread.Logon(threadstat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(threadstat); sl@0: test (thread.ExitType() == EExitPanic); sl@0: test (thread.ExitReason() == aExpectedReason); sl@0: CLOSE_AND_WAIT(thread); sl@0: User::SetJustInTime(jit); sl@0: } sl@0: sl@0: TInt DyingDataAvailableThread( TAny* ) sl@0: { sl@0: RMsgQueue theQ; sl@0: if( KErrNone != theQ.OpenGlobal(_L("TestNotifiedThreadDied")) ) sl@0: User::Panic( _L("TESTTH"), 0 ); sl@0: sl@0: TRequestStatus stat; sl@0: theQ.NotifyDataAvailable( stat ); sl@0: // now just exit sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DyingSpaceAvailableThread( TAny* ) sl@0: { sl@0: RMsgQueue theQ; sl@0: if( KErrNone != theQ.OpenGlobal(_L("TestNotifiedThreadDied")) ) sl@0: User::Panic( _L("TESTTH"), 0 ); sl@0: sl@0: TRequestStatus stat; sl@0: theQ.NotifySpaceAvailable( stat ); sl@0: // now just exit sl@0: return KErrNone; sl@0: } sl@0: sl@0: struct TThreadParams sl@0: { sl@0: TInt imyQHandle; sl@0: TRequestStatus* iRequest; sl@0: }; sl@0: sl@0: TInt DyingRequestDataNotification(TAny* aThreadParams) sl@0: { sl@0: CTrapCleanup* trapHandler = CTrapCleanup::New(); sl@0: if(!trapHandler) sl@0: return KErrNoMemory; sl@0: sl@0: TThreadParams* tp = reinterpret_cast(aThreadParams); sl@0: sl@0: RMsgQueue msgQue2; sl@0: msgQue2.SetHandle(tp->imyQHandle); sl@0: msgQue2.NotifyDataAvailable(*tp->iRequest); sl@0: sl@0: delete trapHandler; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void TestNotifiedThreadDied() sl@0: { sl@0: RThread th; sl@0: TRequestStatus stat; sl@0: RMsgQueue myQ; sl@0: test( KErrNone == myQ.CreateGlobal( _L("TestNotifiedThreadDied"), 1 ) ); sl@0: sl@0: //Test when thread waiting on data available dies sl@0: test( KErrNone == th.Create( _L("DyingDataAvailableThread"), DyingDataAvailableThread, 1024, 1024, 8192, NULL ) ); sl@0: th.Logon( stat ); sl@0: th.Resume(); sl@0: User::WaitForRequest( stat ); sl@0: test(stat.Int()==KErrNone); sl@0: sl@0: User::After( 1000000 ); sl@0: sl@0: myQ.NotifyDataAvailable( stat ); sl@0: myQ.CancelDataAvailable(); sl@0: CLOSE_AND_WAIT(th); sl@0: sl@0: //Test when thread waiting on space available dies sl@0: myQ.Send(0);//This will fill in the whole message queue and block any thread waiting on space available. sl@0: sl@0: test( KErrNone == th.Create( _L("DyingSpaceAvailableThread"), DyingSpaceAvailableThread, 1024, 1024, 8192, NULL ) ); sl@0: th.Logon( stat ); sl@0: th.Resume(); sl@0: User::WaitForRequest( stat ); sl@0: test(stat.Int()==KErrNone); sl@0: sl@0: User::After( 1000000 ); sl@0: sl@0: myQ.NotifySpaceAvailable( stat ); sl@0: myQ.CancelSpaceAvailable(); sl@0: myQ.Close(); sl@0: CLOSE_AND_WAIT(th); sl@0: sl@0: // Calling cancel notification should not crash as the thread that requested notification dies sl@0: test( KErrNone == myQ.CreateLocal(1, EOwnerProcess)); sl@0: sl@0: TThreadParams tp; sl@0: tp.imyQHandle = myQ.Handle(); sl@0: tp.iRequest = &stat; sl@0: sl@0: test( KErrNone == th.Create(_L("DyingRequestDataNotificationThread"), DyingRequestDataNotification, KDefaultStackSize, sl@0: KHeapSize, KHeapSize, reinterpret_cast(&tp))); sl@0: TRequestStatus status; sl@0: th.Logon(status); sl@0: th.Resume(); sl@0: th.Close(); sl@0: sl@0: User::WaitForRequest(status); sl@0: test(status.Int() == KErrNone); sl@0: sl@0: myQ.CancelDataAvailable(); sl@0: myQ.Close(); sl@0: sl@0: } sl@0: sl@0: LOCAL_C void RunTests(void) sl@0: { sl@0: TInt ret = KErrNone; sl@0: test.Start(_L("Testing")); sl@0: sl@0: sl@0: RMsgQueueBase mqueue; sl@0: sl@0: // LOCAL message queues sl@0: sl@0: sl@0: test.Next(_L("Check when thread dies waiting to be notified.")); sl@0: TestNotifiedThreadDied(); sl@0: sl@0: test.Next(_L("Create private message queue with 0 length params")); sl@0: TestIllegalCreation(0,0,ECreateLocal, EMsgQueueInvalidLength); sl@0: sl@0: test.Next(_L("Create private message queue with 0 slots")); sl@0: TestIllegalCreation(0,4,ECreateLocal, EMsgQueueInvalidSlots); sl@0: sl@0: test.Next(_L("Create private message queue with 0 size message")); sl@0: TestIllegalCreation(5, 0, ECreateLocal, EMsgQueueInvalidLength); sl@0: sl@0: test.Next(_L("Create private message queue with none multiple of 4 size message")); sl@0: TestIllegalCreation(5, 9, ECreateLocal, EMsgQueueInvalidLength); sl@0: sl@0: test.Next(_L("Create private message queue with illegal max length ")); sl@0: TestIllegalCreation(8,RMsgQueueBase::KMaxLength+1, ECreateLocal, EMsgQueueInvalidLength); sl@0: sl@0: sl@0: test.Next(_L("Create private message queue, 43 slots, length 8")); sl@0: ret = mqueue.CreateLocal(43,8, EOwnerThread); sl@0: test (KErrNone == ret); sl@0: mqueue.Close(); sl@0: sl@0: test.Next(_L("Create private message queue with max length ")); sl@0: ret = mqueue.CreateLocal(8, RMsgQueueBase::KMaxLength, EOwnerProcess); sl@0: test (KErrNone == ret); sl@0: mqueue.Close(); sl@0: sl@0: test.Next(_L("test private message queue functionality")); sl@0: sl@0: test.Printf(_L("two slots, small queue")); sl@0: ret = mqueue.CreateLocal(2, 4); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 2, 4); sl@0: MultiThreadedTests(mqueue, 2, 4); sl@0: mqueue.Close(); sl@0: sl@0: test.Printf(_L("16 slots, max queue")); sl@0: ret = mqueue.CreateLocal(16, RMsgQueueBase::KMaxLength); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 16, RMsgQueueBase::KMaxLength); sl@0: MultiThreadedTests(mqueue, 16, RMsgQueueBase::KMaxLength); sl@0: mqueue.Close(); sl@0: sl@0: test.Printf(_L("big slots, max queue")); sl@0: ret = mqueue.CreateLocal(KMaxTInt, RMsgQueueBase::KMaxLength); sl@0: test(KErrNoMemory == ret); sl@0: sl@0: sl@0: /**************************************************************************/ sl@0: // GLOBAL Named message queues sl@0: test.Next(_L("Create global named message queue with 0 length params")); sl@0: TestIllegalCreation(0, 0, ECreateGlobal, EMsgQueueInvalidLength); sl@0: sl@0: test.Next(_L("Create global named message queue with 0 slots")); sl@0: TestIllegalCreation(0, 4, ECreateGlobal, EMsgQueueInvalidSlots); sl@0: sl@0: test.Next(_L("Create global message queue with 0 size message")); sl@0: TestIllegalCreation(5, 0, ECreateGlobal, EMsgQueueInvalidLength); sl@0: sl@0: test.Next(_L("Create global message queue with none multiple of 4 size message")); sl@0: TestIllegalCreation(5, 9, ECreateGlobal, EMsgQueueInvalidLength); sl@0: sl@0: test.Next(_L("Create global named message queue with illegal max length ")); sl@0: TestIllegalCreation(8, RMsgQueueBase::KMaxLength+1, ECreateGlobal, EMsgQueueInvalidLength); sl@0: sl@0: test.Next(_L("Create global named message queue")); sl@0: ret = mqueue.CreateGlobal(KGLobalName1, 10,8, EOwnerThread); sl@0: test (KErrNone == ret); sl@0: mqueue.Close(); sl@0: sl@0: test.Next(_L("Create global named message queue with max length ")); sl@0: ret = mqueue.CreateGlobal(KGLobalName1, 8, RMsgQueueBase::KMaxLength, EOwnerProcess); sl@0: test (KErrNone == ret); sl@0: mqueue.Close(); sl@0: sl@0: test.Next(_L("test global named message queue functionality")); sl@0: sl@0: test.Printf(_L("small queue, two slots")); sl@0: ret = mqueue.CreateGlobal(KGLobalName1, 2, 4); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 2, 4); sl@0: MultiThreadedTests(mqueue, 2, 4); sl@0: mqueue.Close(); sl@0: sl@0: test.Printf(_L("max queue, 16 slots")); sl@0: ret = mqueue.CreateGlobal(KGLobalName1, 16, RMsgQueueBase::KMaxLength); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 16, RMsgQueueBase::KMaxLength); sl@0: MultiThreadedTests(mqueue, 16, RMsgQueueBase::KMaxLength); sl@0: mqueue.Close(); sl@0: sl@0: test.Printf(_L("32byte queue, 1000 slots")); sl@0: ret = mqueue.CreateGlobal(KGLobalName1, 1000, 32); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 1000, 32); sl@0: MultiThreadedTests(mqueue, 1000, 32); sl@0: mqueue.Close(); sl@0: sl@0: test.Printf(_L("12 byte queue, 1 slot")); sl@0: ret = mqueue.CreateGlobal(KGLobalName1, 1, 12); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 1, 12); sl@0: MultiThreadedTests(mqueue, 1, 12); sl@0: mqueue.Close(); sl@0: sl@0: sl@0: test.Printf(_L("max queue, maxint! slots")); sl@0: ret = mqueue.CreateGlobal(KGLobalName1, KMaxTInt, RMsgQueueBase::KMaxLength); sl@0: test(KErrNoMemory == ret); sl@0: sl@0: _LIT(KNonQueueName,"non-queue name"); sl@0: test.Printf(_L("open a non-existant queue")); sl@0: ret = mqueue.OpenGlobal(KNonQueueName, EOwnerProcess); sl@0: test(ret == KErrNotFound); sl@0: sl@0: sl@0: ret = mqueue.CreateGlobal(KGLobalName1, 16, 4); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 16, 4); sl@0: MultiThreadedTests(mqueue, 16, 4); sl@0: RMsgQueueBase open; sl@0: sl@0: ret = open.OpenGlobal(KGLobalName1); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(open, 16,4); sl@0: MultiThreadedTests(open, 16, 4); sl@0: sl@0: sl@0: test.Next(_L("Send a legal message through")); sl@0: TInt src = 45; sl@0: TInt dst = 0; sl@0: ret = mqueue.Send(&src, sizeof (TInt)); sl@0: test(ret == KErrNone); sl@0: sl@0: test.Next(_L("Receive legal message")); sl@0: ret = open.Receive(&dst, 4); sl@0: test(ret == KErrNone); sl@0: test (src == dst); sl@0: sl@0: test.Next(_L("Send a legal message through")); sl@0: ret = mqueue.Send(&src, sizeof (TInt)); sl@0: test(ret == KErrNone); sl@0: sl@0: open.Close(); sl@0: mqueue.Close(); sl@0: sl@0: sl@0: ret = mqueue.CreateGlobal(KNullDesC, 5, 4); sl@0: test(KErrNone == ret); sl@0: SingleThreadedTests(mqueue, 5,4); sl@0: MultiThreadedTests(mqueue, 5, 4); sl@0: sl@0: ret = open.OpenGlobal(KNullDesC); sl@0: test(KErrNotFound == ret); sl@0: sl@0: mqueue.Close(); sl@0: sl@0: sl@0: test.Next(_L("Multi Process Queue Tests")); sl@0: sl@0: _LIT(KQueueA, "A"); sl@0: _LIT(KQueueB, "B"); sl@0: _LIT(KProcessName, "T_MQUEUEECHO.EXE"); sl@0: sl@0: RMsgQueueBase inQueue; sl@0: RMsgQueueBase outQueue; sl@0: sl@0: TInt sizes[6] = {4,8,16,32,100,256}; sl@0: sl@0: TInt x; sl@0: for (x = 0; x < 6; x++) sl@0: { sl@0: TUint8* p = (TUint8*)User::Alloc(sizes[x]); sl@0: TRequestStatus stat; sl@0: test (p != NULL); sl@0: ret = inQueue.CreateGlobal(KQueueB, 1, sizes[x]); sl@0: test (KErrNone == ret); sl@0: ret = outQueue.CreateGlobal(KQueueA, 1, sizes[x]); sl@0: test (KErrNone == ret); sl@0: sl@0: //start other process sl@0: RProcess proc; sl@0: ret = proc.Create(KProcessName, KNullDesC); sl@0: test (KErrNone == ret); sl@0: sl@0: //logon to it sl@0: proc.Logon(stat); sl@0: sl@0: proc.Resume(); sl@0: sl@0: TInt y[64] = {1000}; sl@0: sl@0: while (--y[0] >= 0) sl@0: { sl@0: outQueue.SendBlocking(&y,sizes[x]); sl@0: inQueue.ReceiveBlocking(p, sizes[x]); sl@0: test (y[0] == *(TInt*)p); sl@0: } sl@0: sl@0: User::Free(p); sl@0: inQueue.Close(); sl@0: outQueue.Close(); sl@0: sl@0: //wait for the process to terminate sl@0: User::WaitForRequest(stat); sl@0: test(stat == KErrNone); sl@0: CLOSE_AND_WAIT(proc); sl@0: } sl@0: sl@0: test.Next(_L("test templated queue")); sl@0: RMsgQueue templateQueue; sl@0: TTemplateTestData ch(1,2,3,ETrue,4); sl@0: TTemplateTestData ch2; sl@0: TTemplateTestData ch3; sl@0: sl@0: test(KErrNone == templateQueue.CreateLocal(12)); sl@0: sl@0: test (KErrNone == templateQueue.Send(ch)); sl@0: test (ch.first != ch2.first); sl@0: test (ch.chipper != ch2.chipper); sl@0: test (KErrNone == templateQueue.Receive(ch2)); sl@0: test (ch.first == ch2.first); sl@0: test (ch.chipper == ch2.chipper); sl@0: sl@0: templateQueue.SendBlocking(ch); sl@0: test (ch.first != ch3.first); sl@0: test (ch.chipper != ch3.chipper); sl@0: templateQueue.ReceiveBlocking(ch3); sl@0: test (ch.first == ch3.first); sl@0: test (ch.chipper == ch3.chipper); sl@0: sl@0: templateQueue.Close(); sl@0: sl@0: test(KErrNone == templateQueue.CreateGlobal(KNullDesC, 79)); sl@0: templateQueue.Close(); sl@0: sl@0: _LIT(KTestName, "testQueue"); sl@0: sl@0: test(KErrNone == templateQueue.CreateGlobal(KTestName, 986)); sl@0: sl@0: RMsgQueue templateQueue2; sl@0: test(KErrNone == templateQueue2.OpenGlobal(KTestName)); sl@0: templateQueue.Close(); sl@0: templateQueue2.Close(); sl@0: sl@0: sl@0: test.Next(_L("Ending test.\n")); sl@0: test.End(); sl@0: sl@0: test.Close(); sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: // sl@0: // sl@0: { sl@0: test.Title(); sl@0: sl@0: // Turn off evil lazy dll unloading sl@0: RLoader l; sl@0: test(l.Connect()==KErrNone); sl@0: test(l.CancelLazyDllUnload()==KErrNone); sl@0: l.Close(); sl@0: sl@0: RunTests(); sl@0: return KErrNone; sl@0: } sl@0: