Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 39
Текст из файла (страница 39)
SendReceive() has overloads to handle both synchronous and asynchronousrequests. The asynchronous request method takes a TRequestStatus¶meter, while the synchronous version returns the result in the TIntreturn value. RSessionBase::Send() sends a message to the serverbut does not receive a reply (and in practice, this function is rarely used).The Send() and SendReceive() methods take a 32-bit argument (aFunction) that identifies the client request (typically definedin an enumeration shared between the client and server – see theTHerculeanLabors enumeration in the sample code of Chapter 124A TVersion object contains three integers representing the major, minor and buildversion numbers.5A session can only ever have one outstanding synchronous request with a server.WHAT CLASSES DOES THE CLIENT–SERVER FRAMEWORK USE?173for an example). The methods also take a TAny* argument which isa pointer to an array of four 32-bit values.
This array constitutes the”payload” for the request; it can be empty or it may contain up to fourinteger values or pointers to descriptors in the client’s address space. Thelayout of the array is determined in advance for each request betweenclient and server and is a private protocol.
The calling client does notneed to have any knowledge of how data is transferred.If a server supports session sharing, a client session may be shared by allthe threads in a client process (Symbian OS v8.0 is the first release whichalso allows a session to be shared between processes). However, someservers restrict the session to the thread which connected to the serveralone (this was always the case until sharable sessions were introducedin Symbian OS v6.0). I’ll discuss sharable sessions in more detail later inthis chapter.On the client side, if a session can be shared, the first connection tothe server should be made as normal using RSessionBase::CreateSession(). Once the session is opened, RSessionBase::Share()should be called on it to make it sharable.6 Until Share() is called, thesession is specific to the connecting client thread.
If the TAttachModeparameter passed to Share() is EExplicitAttach, other threadswishing to share the session should call RSessionBase::Attach()on the session. However, if EAutoAttach is passed to Share(), thenall threads are attached to the session automatically. If the session is notattached before a message is sent, or the session is not sharable, a panicoccurs (KERN-SVR 0).Client requests are identified using an enumeration shared betweenthe client and server.
Requests are submitted with a payload arraywhich can contain up to four 32-bit values (integer values orpointers to descriptors in the client’s address space).RMessageAn RMessage object is a server-side representation of a client request,and each client request to the server is represented by a separateRMessage object. Here is the definition from e32std.h, where again,I’ve shown only the most relevant methods:class RMessage{public:IMPORT_C RMessage();6A server must support sharable sessions, otherwise a call to RSessionBase::Share() raises a panic (KERN-SVR 23).174THE CLIENT–SERVER FRAMEWORK IN THEORYIMPORT_C void Complete(TInt aReason) const;IMPORT_C void ReadL(const TAny* aPtr,TDes8& aDes) const;IMPORT_C void ReadL(const TAny* aPtr,TDes8& aDes,TInt anOffset) const;IMPORT_C void ReadL(const TAny* aPtr,TDes16& aDes) const;IMPORT_C void ReadL(const TAny* aPtr,TDes16& aDes,TInt anOffset) const;IMPORT_C void WriteL(const TAny* aPtr,const TDesC8& aDes) const;IMPORT_C void WriteL(const TAny* aPtr,const TDesC8& aDes,TInt anOffset) const;IMPORT_C void WriteL(const TAny* aPtr,const TDesC16& aDes) const;IMPORT_C void WriteL(const TAny* aPtr,const TDesC16& aDes,TInt anOffset) const;IMPORT_C void Panic(const TDesC& aCategory,TInt aReason) const;IMPORT_C void Kill(TInt aReason) const;IMPORT_C void Terminate(TInt aReason) const;inline TInt Function() const;inline const RThread& Client() const;inline TInt Int0() const;inline TInt Int1() const;inline TInt Int2() const;inline TInt Int3() const;inline const TAny* Ptr0() const;inline const TAny* Ptr1() const;inline const TAny* Ptr2() const;inline const TAny* Ptr3() const;inline const RMessagePtr MessagePtr() const;protected:TInt iFunction;TInt iArgs[KMaxMessageArguments];RThread iClient;const TAny* iSessionPtr;TInt iHandle;};The RMessage object stores the 32-bit request identifier (also knownas an ”opcode”), which can be retrieved by calling Function().
Italso holds the array of request payload data, a handle to the clientthread, accessible through Client(), and the client’s RHandleBaseidentification handle.As I described above, the layout of the request parameters in therequest data array is pre-determined for each client request. For requestswhere the server expects parameters from the client, it can retrieve thedata from an RMessage object using Int0() to return a 32-bit valuefrom the first element of the request array, Int1() to return the secondelement, and so on.
In a similar manner, Ptr0() returns the contents ofthe first element in the request array as a TAny* pointer, Ptr1() for thesecond element, and so on to the fourth element of the array.The pointers returned from Ptr0() to Ptr3() cannot be useddirectly by the server code if they refer to the address space of aclient running in a different process. The server must instead passWHAT CLASSES DOES THE CLIENT–SERVER FRAMEWORK USE?175these pointers to the overloaded ReadL() and WriteL() methods7of RMessage, which use kernel-mediated inter-process communicationto transfer the data.When the server has serviced a client request, it calls Complete()on the RMessage to notify the client.
This method wraps a call toRThread::Complete() on the client’s thread handle. The integervalue passed to Complete() is written into the client’s TRequestStatus value and the request semaphore for the client thread is signaled.If you’re wondering about synchronous SendReceive() requests fromthe client, which don’t take a TRequestStatus parameter, take a lookat Section 11.5. The Panic(), Terminate() and Kill() methodsof RMessage are wrappers over the RThread methods of the samename and may be used by the server to stop the client thread undercertain circumstances, such as client misbehavior due to a programming error.The client and server run in separate threads which also typicallyrun in different processes.
The address spaces of Symbian OSprocesses are protected and kernel-mediated data transfer must beused between the client and server.DSessionDSession is a kernel class; the ”D” prefix means that it is a CBasederived kernel-side class.On Symbian OS, each process is memory-mapped into a differentaddress space, so it is protected from other processes. One processcannot overwrite the memory of another. The only process that can ”see”all the physical memory in the system is the kernel process. When a clientcalls RSessionBase::CreateSession(), the kernel establishes theconnection between the client and the server and creates a DSessionobject to represent the session.
Each DSession object has a pointer to akernel object representing the client thread (DThread) and a pointer tothe kernel server object (DServer), as shown in Figure 11.2.CSharableSessionCSharableSession is an abstract base class that represents a sessionwithin the server. For each RSessionBase-derived object on the clientside, there is an associated CSharableSession-derived object on theserver side.7These methods are simply wrappers over the ReadL() and WriteL() methods ofRThread, as described in Chapter 10.176THE CLIENT–SERVER FRAMEWORK IN THEORYUSER SIDERSessionBaseKERNEL SIDEDSessionDThread(Client)CLIENT PROCESSSERVER PROCESSRThread(Client)CSessionDServer holds a doubly linkedlist of DSession objectsDServerCSharableSessionCServer holds adoubly linked list ofCSharableSessionobjectsDThread(Server)CServerRServerFigure 11.2Symbian OS client- and server-side base classesclass CSharableSession : public CBase{friend class CServer;public:IMPORT_C ∼CSharableSession()=0;IMPORT_C virtual void CreateL(const CServer& aServer);inline const CServer* Server() const;inline const RMessage& Message() const;IMPORT_C void ResourceCountMarkStart();IMPORT_C void ResourceCountMarkEnd();IMPORT_C virtual TInt CountResources();virtual void ServiceL(const RMessage& aMessage)=0;protected:IMPORT_C CSharableSession();...private:TInt iResourceCountMark;TDblQueLink iLink;const CServer* iServer;};WHAT CLASSES DOES THE CLIENT–SERVER FRAMEWORK USE?177CSharableSession provides methods to access the CServerderived object, Server(), which I’ll discuss shortly.
Message() canbe used to access the next client request to process, if there anyare outstanding. If the server makes an asynchronous call to servicethe request and does not complete the request before returning fromServiceL(), the RMessage object must be stored so it can be completed at a later stage. If it was not stored, when it came to complete therequest, Message() would return a different message if other requestshad been submitted to the server while the asynchronous request wasbeing processed.Classes derived from CSharableSession handle incoming clientrequests through their implementation of the pure virtual ServiceL()method. Typically, this method should check the incoming message tosee which request the client has submitted, then handle it by unpackingthe message and using the incoming parameters accordingly.