Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 35
Текст из файла (страница 35)
By using a fastmutex, we ensure that message-passing operations may only be invokedfrom a thread context.You can send kernel-side messages either synchronously or asynchronously. Each TMessageBase object contains an NFastSemaphoreon which the sending thread will wait after sending a synchronous message. The receiving thread signals the semaphore after the kernel hasprocessed the message and written the completion code. The kernel thenreleases the sending thread, and when it runs, it picks up the return code.The NFastSemaphore also contains a pointer to the sendingNThread; this serves to identify the sending thread and is thereforeset up for both synchronous and asynchronous message send. Wereference count this pointer – incrementing the access count of the originating DThread when the message is sent.
This prevents the sendingDThread object disappearing if the thread terminates unexpectedly.When the kernel completes the message it removes the extra accessasynchronously – the thread completing the message will not need toclose the DThread itself. We do this to avoid unpredictable executiontimes for message completion. Also note that even messages that aresent asynchronously must be completed; this is so that the kernel can setthe message state back to FREE and remove the access count from thesending thread.The kernel always sends the TThreadMessage objects embedded inSymbian OS thread control blocks synchronously – this ensures that onemessage per thread will always suffice. The kernel cancels these messagesif the corresponding thread terminates.
Canceling an ACCEPTED messagehas no effect, but canceling a DELIVERED message means that the kernelwill remove the message from the queue and also remove the access countheld by the message on the sending thread. Because of this, the receivingthread should only use any of the member data of TMessageBase if themessage is in the ACCEPTED state.4.4 Publish and subscribePublish and subscribe, also known as ‘‘properties’’, provides:1.System-wide global variables2.A new IPC mechanism, for asynchronous peer-to-peer communication between threads.An overview is given in Figure 4.6.PUBLISH AND SUBSCRIBE151Propertyidentity:type:security:categorykeysingle word ormultiple bytesreadwritePublisherSubscriberFigure 4.6Publish and subscribe overviewPublish and subscribe can be used by both user and kernel code,through similar APIs, and so this method also allows communicationbetween user and kernel code.From the user side, you would use the RProperty handle, defined ine32property.h:class RProperty : public RHandleBase{public:enum { KMaxPropertySize = 512 };enum { KMaxLargePropertySize = 65535 };enum TType{EInt,EByteArray,EText = EByteArray,ELargeByteArray,ELargeText = ELargeByteArray,ETypeLimit,ETypeMask = 0xff};public:IMPORT_C static TInt Define(TUid aCategory, TUint aKey,TInt aAttr, TInt aPreallocate=0);IMPORT_C static TInt Define(TUid aCategory, TUint aKey,TInt aAttr, const TSecurityPolicy& aReadPolicy,const TSecurityPolicy& aWritePolicy,TInt aPreallocated=0);IMPORT_C static TInt Delete(TUid aCategory, TUint aKey);IMPORT_C static TInt Get(TUid aCategory, TUint aKey, TInt& aValue);IMPORT_C static TInt Get(TUid aCategory, TUint aKey, TDes8& aValue);IMPORT_C static TInt Set(TUid aCategory, TUint aKey, TInt aValue);152INTER-THREAD COMMUNICATIONIMPORT_C static TInt Set(TUid aCategory, TUint aKey,const TDesC8& aValue);IMPORT_C TInt Attach(TUid aCategory, TUint aKey,TOwnerType aType = EOwnerProcess);IMPORT_C void Subscribe(TRequestStatus& aRequest);IMPORT_C void Cancel();IMPORT_C TInt Get(TInt& aValue);IMPORT_C TInt Get(TDes8& aValue);IMPORT_C TInt Set(TInt aValue);IMPORT_C TInt Set(const TDesC8& aValue);};From the kernel side, you use the RPropertyRef and TPropertySubsRequest classes defined in sproperty.h, and the TPropertyInfoclass defined in u32property.h.
Note that TPropertySubsRequestis on a single queue protected by the system lock.class RPropertyRef{public:RPropertyRef() {iProp = NULL;}IMPORT_C TInt Attach(TUid aCategory, TInt aKey);IMPORT_C TInt Open(TUid aCategory, TInt aKey);IMPORT_C void Close();IMPORT_C TInt Define(TInt aAttr, const TSecurityPolicy& aReadPolicy,const TSecurityPolicy& aWritePolicy,TInt aPreallocate=0, DProcess* aProcess = NULL);IMPORT_C TInt Delete(DProcess* aProcess = NULL);IMPORT_C TInt Subscribe(TPropertySubsRequest& aRequest,DProcess* aProcess = NULL);IMPORT_C void Cancel(TPropertySubsRequest& aRequest);IMPORT_C TInt Get(TInt& aValue, DProcess* aProcess = NULL);IMPORT_C TInt Set(TInt aValue, DProcess* aProcess = NULL);IMPORT_C TInt Get(TDes8& aDes, DProcess* aProcess = NULL);IMPORT_C TInt Set(const TDesC8& aDes, DProcess* aProcess = NULL);IMPORT_C TBool GetStatus(TPropertyStatus& aStatus);private:TProperty* iProp;};class TPropertySubsRequest : public SdblQueLink{public:TPropertySubsRequest(TPropertyCompleteFn aCompleteFn, TAny* aPtr){iNext = NULL;iCompleteFn = aCompleteFn;iPtr = aPtr;}TPropertyCompleteFn iCompleteFn;TAny* iPtr;private:friend class TProperty;DProcess* iProcess;};PUBLISH AND SUBSCRIBE153class TPropertyInfo{public:TUintiAttr;TUint16 iSize;RProperty::TType iType;TSecurityPolicy iReadPolicy;TSecurityPolicy iWritePolicy;};4.4.1Key entitiesThere are three key entities in the publish and subscribe system.
I willdescribe them below; you may also want to refer back to the overview inFigure 4.6.PropertiesThis is data: either a single 32-bit data value or a variable-length set ofbytes, identified by a 64-bit integer.PublishersPublishers are threads that define and update a property.SubscribersSubscribers are threads that listen for changes to a property and can getthe current value of a property.Now let’s have a look at properties in a little more detail.4.4.2 PropertiesInternally, the kernel stores a property as an instance of the TPropertyclass, defined in sproperty.cpp. I will give a very cut-down versionhere, as this is a surprisingly large class:class TProperty{public:static TInt Init();static TInt Attach(TUid aCategory, TUint aKey, TProperty** aProp);static TInt Open(TUid aCategory, TUint aKey, TProperty** aProp);void Close();TInt Define(const TPropertyInfo*, DProcess*);TInt Delete(DProcess*);TInt Subscribe(TPropertySubsRequest* aSubs, DProcess*);void Cancel(TPropertySubsRequest* aSubs);TInt GetI(TInt* aValue, DProcess*);TInt GetB(TUint8* aBuf, TInt* aSize, DProcess*, TBool aUser);TInt SetI(TInt aValue, DProcess*);TInt SetB(const TUint8*, TInt aSize, DProcess*, TBool aUser);const TUid iCategory;const TUint iKey;private:enum { KCompletionDfcPriority = 2 };static TDfc CompletionDfc;154INTER-THREAD COMMUNICATIONstatic SDblQue CompletionQue;static DMutex* FeatureLock;static TProperty* Table[KHashTableLimit];TUint8 iType;TUint8 iAttr;TCompiledSecurityPolicy iReadPolicy;TCompiledSecurityPolicy iWritePolicy;TUint32 iOwner;TUint iRefCount;// The property value// Meaningful for defined properties only//(ie.
iType != RProperty::ETypeLimit)union // the value is protected by the system lock{TBuf* iBuf;TInt iValue;};};A property has three key attributes: identity, type and security.The identity and type of a property is the only information that must beshared between a publisher and a subscriber – there is no need to provideinterface classes or functions, though that may often be desirable.IdentityA property is identified by a 64-bit integer made up of two 32-bit parts:the category and the key.A property is said to belong to a category, which is a standard SymbianOS UID.The key is a 32-bit value that identifies a specific property withina category. The meaning applied to the key depends on the kind ofenumeration scheme set up for the category.
At its simplest, a key canbe an index value. It can also be another UID, if you are designing thecategory to be generally extensible.TypeA property can be:1.A single 32-bit value2. A contiguous set of bytes, referred to as a byte-array. The lengthof this can go as high as KMaxLargePropertySize, 65,535 bytes,but real-time guarantees are made only if the length is below RProperty::KMaxPropertySize, 512 bytes. Memory for the smaller bytearrays may be allocated at definition time: if this is done publishing cannotfail with KErrNoMemory, and we can satisfy those real-time guarantees3. Unicode text. This is for properties and accessor functions that acceptUnicode descriptors, and is just a convenience for programmers wishingPUBLISH AND SUBSCRIBE155to store Unicode text properties.
The implementation treats Unicode textas a byte-array; the API hides the detail.SecurityA property has two TCompiledSecurityPolicy members. One ofthese is for read operations – that is, Get() and Subscribe() calls onRProperty – and the other is for write operations – that is Set() callson RProperty.These members are set up when the property is defined, passing intwo TSecurityPolicy parameters to the RProperty::Define()function:IMPORT_C static TInt Define(TUid aCategory, TUint aKey, TInt aAttr,const TSecurityPolicy& aReadPolicy,const TSecurityPolicy& aWritePolicy,TInt aPreallocated=0);You can turn to Chapter 8, Platform Security, for more information.4.4.3 Using publish and subscribeThere are six basic operations that you can perform on a property: define,delete, publish, retrieve, subscribe and unsubscribe.I give an overview of these operations in the table below, and insubsequent sections I will describe some of these functions in more detail.DefineCreate a property variable and define itstype and access controls.DeleteRemove a property from the system.PublishChange the value of a property.RetrieveGet the current value of a property.SubscribeRegister for notification of changes to aproperty.UnsubscribeSay that you no longer want to be notifiedof changes.4.4.4 Defining a propertyAs we saw above, you define a property by using the RProperty::Define() function to specify the attributes of the property.You don’t have to define a property before it is accessed.