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