Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 34
Текст из файла (страница 34)
To aid migration to the new APIs, all EKA1-based SymbianOS releases from 7.0 s onwards contain both the new Rendezvous()thread/process APIs discussed in Section 3.3.6, and a functioning (but notsecure) implementation of the IPCv2 APIs.ASYNCHRONOUS MESSAGE QUEUES1454.1.6.1 IPCv2 summaryTo summarize, IPCv2 has brought the following benefits and features:• Secure access to the client’s address space based on the permissionsand data types it specifies in messages to the server• The ability to prevent spoofing of server names and to validate asecurity policy against the server when connecting to a session oropening a handle to a shared session• Real-time server performance is possible through the use of asynchronous session connect and disconnect operations• The ability to share server sessions between processes• Asynchronous creation of a connection with a server to prevent amalicious server blocking a client indefinitely.4.2 Asynchronous message queuesA message queue is a mechanism for passing data between threads,which may be in the same process, or in different processes.
The messageitself is usually an instance of a class, and its size must be a multiple of4 bytes.The asynchronous message queue mechanism provides a way to senda message without needing to know the identity of a recipient, or indeed,if anyone is actually listening.You define and fix the size of the queue when you create it, choosingthe maximum number of messages it can contain and the size of thosemessages.
So, you would normally create a new queue to deal with messages of a particular type. There is no fixed maximum to either the messagesize or the queue size – these are only limited by system resources.Many readers and writers may share a single queue. Sending andreceiving messages are real-time operations and operate with realtime guarantees.We represent a message queue by a DMsgQueue kernel-side object,to which the reader and the writer can open a handle. This is a referencecounted object derived from DObject, which means that it is notpersistent; the kernel deletes it when the last handle to it is closed. Thequeue itself is simply a block of memory divided into slots. Here is theDMsgQueue class that manages it:class DMsgQueue : public DObject{public:enum TQueueState {EEmpty, EPartial, EFull};enum {KMaxLength = 256};public:146INTER-THREAD COMMUNICATION∼DMsgQueue();TInt Create(DObject* aOwner, const TDesC* aName,TInt aMsgLength, TInt aSlotCount, TBool aVisible = ETrue);TInt Send(const TAny* aPtr, TInt aLength);TInt Receive(TAny* aPtr, TInt aLength);void NotifySpaceAvailable(TRequestStatus* aStatus);void NotifyDataAvailable(TRequestStatus* aStatus);void CancelSpaceAvailable();void CancelDataAvailable();TInt MessageSize() const;private:void CancelRequest(DThread* aThread, TRequestStatus*& aStatus);void CompleteRequestIfPending(DThread* aThread,TRequestStatus*& aStatus, TInt aCompletionVal);private:TUint8* iMsgPool;TUint8* iFirstFreeSlot;TUint8* iFirstFullSlot;TUint8* iEndOfPool;DThread* iThreadWaitingOnSpaceAvail;DThread* iThreadWaitingOnDataAvail;TRequestStatus* iDataAvailStat;TRequestStatus* iSpaceAvailStat;TUint16 iMaxMsgLength;TUint8 iState;TUint8 iSpare;public:friend class Monitor;};Key member data of DMsgQueueiMsgPoolA pointer to the block of memory used for the message slots.iFirstFreeSlotA pointer to the first free slot in the message pool, unless the pool is full,iState==EFull.iFirstFullSlotA pointer to the first full slot in the message pool, unless the pool isempty, iState==EEmpty.iEndOfPoolA pointer to the byte of memory that is just past the end of the poll ofmessage slots.iStateWhether the pool is empty, full or somewhere in between.You perform actions (such as creation, opening, writing and reading) to amessage queue through a message queue handle, which is an RMsgQueueobject.
This is a templated class, where the template parameter definesthe message type.RMsgQueue is derived from RMsgQueueBase, which together forma thin template class/base class pair. RMsgQueueBase provides theKERNEL-SIDE MESSAGES147implementation, while RMsgQueue provides type safety. An RMsgQueueBase object is a valid message queue handle, but does notoffer the type safety that RMsgQueue does.4.2.1 VisibilityA message queue can be:1. Named and be visible to all processes – a global queue2.
Nameless, but accessible from other processes. A handle may bepassed to another process by a process currently owning a handle tothe queue, using a handle-sharing mechanism – a protected queue3. Nameless and local to the current process, hence not visible to anyother process – a local queue.The choice clearly depends on the use you have in mind for the queue.4.3 Kernel-side messagesKernel-side messages are a means of communication that are used tocommunicate with a Symbian OS thread that is executing kernel-sidecode. Typically, you would use this communication method if you werewriting a device driver – to communicate between your client thread,usually a user-mode thread, and a supervisor-mode thread running theactual device driver code.The mechanism consists of a message containing data, and a queuethat is associated with a DFC.
The DFC runs to process each message.We represent a kernel-side message by a TMessageBase object; thisallows a single 32-bit argument to be passed, and returns a single 32-bitvalue. If you want to pass more arguments, then you must derive a newmessage class from TMessageBase.Every Symbian OS thread has a TThreadMessage object embeddedwithin it. TThreadMessage is derived from TMessageBase, and contains space for 10 extra 32-bit arguments. You can use these objects forcommunication with device driver threads.Both TMessageBase and TThreadMessage are defined in kernel.h.
The following example shows the TMessageBase class:class TMessageBase : public SDblQueLink{public:enum TState {EFree,EDelivered,EAccepted};public:TMessageBase() : iState(EFree), iQueue(NULL) {}IMPORT_C void Send(TMessageQue* aQ);IMPORT_C TInt SendReceive(TMessageQue* aQ);IMPORT_C void Forward(TMessageQue* aQ, TBool aReceiveNext);148INTER-THREAD COMMUNICATIONIMPORT_C void Complete(TInt aResult, TBool aReceiveNext);IMPORT_C void Cancel();IMPORT_C void PanicClient(const TDesC& aCategory, TInt aReason);public:IMPORT_C DThread* Client();public:TUint8 iState;TMessageQue* iQueue;NFastSemaphore iSem;TInt iValue;};Key member data of TMessageBaseiStateIndicates whether message is free, delivered or accepted.iQueueA pointer to the message queue to which the message was delivered.iSemA fast semaphore used to block the sending thread if the message was sentsynchronously.
The iOwningThread field of this semaphore is used asa pointer to the thread that sent the message.iValueUsed to hold a single integer argument when the message is sent; holdscompletion code when message is completed.TMessageQueThe kernel sends kernel-side messages to a message queue, which isrepresented by a TMessageQue object.
This consists of a DFC and adoubly linked list of received messages. The class is shown below:class TMessageQue : private TDfc{public:IMPORT_C TMessageQue(TDfcFn aFunction, TAny* aPtr,TDfcQue* aDfcQ, TInt aPriority);IMPORT_C void Receive();IMPORT_C TMessageBase* Poll();IMPORT_C TMessageBase* Last();IMPORT_C void CompleteAll(TInt aResult);using TDfc::SetDfcQ;public:inline static void Lock() {NKern::FMWait(&MsgLock);}inline static void Unlock() {NKern::FMSignal(&MsgLock);}inline void UnlockAndKick() {Enque(&MsgLock);}public:SDblQue iQ;TBool iReady;TMessageBase* iMessage;static NFastMutex MsgLock;friend class TMessageBase;};KERNEL-SIDE MESSAGES149Key member data of TMessageQueTDfc (the base class)This DFC is attached to the thread receiving the messages. It runswhenever the message queue is ready to receive and a message isavailable.iQA doubly linked list of messages that have been delivered to this queue.iReadyA Boolean flag indicating whether the message queue is ready to receive.If TRUE, the DFC will run as soon as a message is delivered; if FALSEthe message will simply remain on the delivered queue and the DFC willnot run.iMessagePointer to the last message accepted by the receiving thread.Kernel-side messaging in operationWhen a message is sent to the queue, either:• The kernel accepts the message immediately, and the receivingthread’s DFC runs.
This happens if the message queue is ready toreceive, which is the case if the message queue is empty and thereceiving thread has requested the next message.Or• The kernel places the message on the delivered message queue, andthe DFC does not run. This happens if there are other messages queuedahead of this one or if the receiving thread has not (yet) requestedanother message.A kernel-side message may be in one of three states at any time:1. FREE – represented by the TMessageBase::EFree enum value.This indicates that the message is not currently in use2. DELIVERED – represented by the TMessageBase::EDeliveredenum value. This indicates that the message is attached to a messagequeue but is not currently in use by the receiving thread. It may beremoved from the queue and discarded with no ill effects on thereceiving thread3.
ACCEPTED – represented by the TMessageBase::EAcceptedenum value. This indicates that the message is not attached to amessage queue but is currently in use by the receiving thread. Themessage may not be discarded.150INTER-THREAD COMMUNICATIONTransitions between these states, including adding the message to andremoving it from a message queue, occur under the protection of theglobal TMessageQue::MsgLock fast mutex. We need to use a mutexto avoid queue corruption in the case of, for example, multiple threadssending to the same message queue at the same time.