This topic explains the operations that can be performed using message queue.
A global queue is created by calling CreateGlobal() on a handle object, while a local queue is created by calling CreateLocal().
A global queue is opened by calling OpenGlobal() on a handle object, passing a queue name.
All the memory used by the queue is allocated when the queue is created, so it is possible for the call that creates a queue to fail with out of memory. The queue is deleted when the last open handle on it is closed.
Creating a global named queue
_LIT(KGLobalName, "GlobalMessageQueue"); const TInt KNumberOfSlots = 5; const TInt KMessageLength = 16; RMsgQueueBase queue; TInt ret = queue.CreateGlobal(KGLobalName, KNumberOfSlots, KMessageLength, EOwnerProcess);
This code fragment creates a global named message queue called GlobalMessageQueue with 5 slots, each capable of holding a message of size 16 bytes. Note that we have explicitly used RMsgQueueBase. In practice, you would use the template class RMsgQueue. For example:
class TMyClass { public: TInt iA; TInt iB; TInt iC; TInt iD; } _LIT(KGLobalName, "GlobalMessageQueue"); const TInt KNumberOfSlots = 5; RMsgQueue<TMyClass> queue; TInt ret = queue.CreateGlobal(KGLobalName, KNumberOfSlots, EOwnerProcess);
The length of the message is the length of the templated class, which in this example is also 16.
Creating a local message queue
const TInt KNumberOfSlots = 2; RMsgQueueBase queue; TInt ret = queue.CreateLocal(KNumberOfSlots, RMsgQueueBase::KMaxLength);
This creates a local queue with 2 message slots that have the maximum possible message size. In practice, you would use the template class RMsgQueue rather than the base class RMsgQueueBase.
Opening a named global queue
_LIT(KGLobalName, "GlobalMessageQueue"); RMsgQueueBase queue; TInt messageSize = 0; TInt ret = queue.OpenGlobal(KGLobalName1); If (ret == KErrNone) { messageSize = queue.MessageSize(); }
This opens the global named message queue called GlobalMessageQueue. The message size used within this queue is queried by calling MessageSize(). If the queue does not exist OpenGlobal() returns KErrNotFound.
Note that using an illegal message size when writing to, or reading from, a queue is a programming error. In practice, you would use the templated class RMsgQueue rather than the base class RMsgQueueBase to avoid this problem.
A message is sent to a message queue by calling Send() or SendBlocking() on the message queue handle. Send() returns the error code KErrOverflow if the queue is full, SendBlocking() waits until there is space in the queue.
The following example creates a global named queue, and sends 2 integer to values to it. The first call to Send() returns an error if the queue is full, the call to SendBlocking() waits until there is space in the queue. Although the example code uses the base class RMsgQueueBase, in practice you would use the templated class RMsgQueue, to avoid the risk of passing an invalid length, message size, or an invalid data pointer.
_LIT(KGLobalName, "GlobalMessageQueue"); RMsgQueueBase mqueue; TInt ret = mqueue.CreateGlobal(KGLobalName1, 1, sizeof (TInt)); if (ret == KErrNone) { TInt src = 45; ret = mqueue.Send(&src, sizeof (TInt)); TBool full = (ret == KErrOverflow); //blocking send src = 32; mqueue.SendBlocking(&src, sizeof(TInt)); mqueue.Close(); }
A message is received from a message queue by calling Receive() or ReceiveBlocking() on the message queue handle. Receive() returns the error code KErrUnderflow if the queue is empty, ReceiveBlocking() waits until there is data in the queue.
The following example opens a global named queue and receives 2 integer values from it. The first call to Receive() returns an error if the queue is empty, the call to ReceiveBlocking() waits until there is data available in the queue. Note also that using the base class RMsgQueueBase rather than the templated class RMsgQueue risks raising panics if the length specified is not the same as the message size specified when the queue was originally created, or if the pointer to the receive buffer is not a valid address.
_LIT(KGLobalName, "GlobalMessageQueue"); RMsgQueueBase mqueue; TInt ret = mqueue.OpenGlobal(KGLobalName1); if (ret == KErrNone) { TInt data; ret = mqueue.Receive(&data, sizeof (TInt)); TBool empty = (ret == KErrUnderflow); //blocking receive mqueue.ReceiveBlocking(&data, sizeof(TInt)); mqueue.Close(); }
It is possible to be notified:
when a queue has messages, by calling NotifyDataAvailable() on the base class RMsgQueueBase
when a queue has space for more messages, by calling NotifySpaceAvailable() on the base class RMsgQueueBase.
Note that the calling NotifyDataAvailable() when such a request is still outstanding or calling NotifySpaceAvailable() when such a request is already outstanding, results in the calling thread being panicked
Notification requests can be cancelled by calling CancelDataAvailable() or CancelDataAvailable() respectively.
TRequestStatus stat; mqueue.NotifyDataAvailable(stat); mqueue.CancelDataAvailable(); User::WaitForRequest(stat);
The size of the message slot can be queried by calling MessageSize() on the handle. This is useful when a queue is opened, as the calling thread is panicked if the size is out of range on a Send() or if the size is not exact on a Receive().
The size of the message is the size of the type, and has the same restrictions as the base class, namely it must be greater than 0, a multiple of 4 bytes and not greater than RMsgQueueBase::KMaxLength.
class TTemplateTestData { public: TTemplateTestData(); TTemplateTestData(TInt a, TUint b, TUint8 c, TBool d, TInt e); public: TInt first; TUint second; TUint8 third; TBool fourth; TInt fifth; }; { .... RMsgQueue<TTemplateTestData> templateQueue; TTemplateTestData ch(1,2,3,ETrue,4); TTemplateTestData ch2; TTemplateTestData ch3; templateQueue.CreateLocal(12); templateQueue.Send(ch); templateQueue.Receive(ch2); .... templateQueue.Close(); ... }
Note, the size of the type (i.e. the size of the message) must be a multiple of 4 bytes.