--- /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 <e32test.h>
+#include <e32svr.h>
+#include <e32msgqueue.h>
+#include <f32file.h>
+
+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<TInt> 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<TInt> 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<TThreadParams*>(aThreadParams);
+
+ RMsgQueue<TInt> msgQue2;
+ msgQue2.SetHandle(tp->imyQHandle);
+ msgQue2.NotifyDataAvailable(*tp->iRequest);
+
+ delete trapHandler;
+ return KErrNone;
+ }
+
+void TestNotifiedThreadDied()
+{
+ RThread th;
+ TRequestStatus stat;
+ RMsgQueue<TInt> 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<TAny*>(&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<TTemplateTestData> 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<TTemplateTestData> 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;
+ }
+