Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 30
Текст из файла (страница 30)
Thesession class is RSessionBase, as follows:CLIENT-SERVER ITC127class RSessionBase : public RHandleBase{friend class RSubSessionBase;public:enum TAttachMode{EExplicitAttach,EAutoAttach};public:inline TInt ShareAuto(){ return DoShare(EAutoAttach); }inline TInt ShareProtected(){ return DoShare(EAutoAttach|KCreateProtectedObject); }IMPORT_C TInt Open(RMessagePtr2 aMessage,TInt aParam,TOwnerType aType=EOwnerProcess);IMPORT_C TInt Open(RMessagePtr2 aMessage,TInt aParam,const TSecurityPolicy& aServerPolicy, TOwnerType aType=EOwnerProcess);IMPORT_C TInt Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess);protected:IMPORT_C TInt Open(TInt aArgumentIndex,const TSecurityPolicy& aServerPolicy, TOwnerType aType=EOwnerProcess);inline TInt CreateSession(const TDesC& aServer,const TVersion& aVersion);IMPORT_C TInt CreateSession(const TDesC& aServer,const TVersion& aVersion,TInt aAsyncMessageSlots);IMPORT_C TInt CreateSession(const TDesC& aServer,const TVersion& aVersion,TInt aAsyncMessageSlots,TIpcSessionType aType,const TSecurityPolicy* aPolicy=0,TRequestStatus* aStatus=0);inline TInt CreateSession(RServer2 aServer,const TVersion& aVersion);IMPORT_C TInt CreateSession(RServer2 aServer,const TVersion& aVersion,TInt aAsyncMessageSlots);IMPORT_C TInt CreateSession(RServer2 aServer,const TVersion& aVersion,TInt aAsyncMessageSlots,TIpcSessionType aType,const TSecurityPolicy* aPolicy=0, TRequestStatus* aStatus=0);inline TInt Send(TInt aFunction,const TIpcArgs& aArgs) const;inline void SendReceive(TInt aFunction,const TIpcArgs& aArgs,TRequestStatus& aStatus) const;inline TInt SendReceive(TInt aFunction,const TIpcArgs& aArgs) const;inline TInt Send(TInt aFunction) const;inline void SendReceive(TInt aFunction,TRequestStatus& aStatus) const;inline TInt SendReceive(TInt aFunction) const;private:TInt SendAsync(TInt aFunction,const TIpcArgs* aArgs,TRequestStatus* aStatus) const;TInt SendSync(TInt aFunction,const TIpcArgs* aArgs) const;IMPORT_C TInt DoShare(TInt aAttachMode);TInt DoConnect(const TVersion &aVersion,TRequestStatus* aStatus);};Sub-sessions are simply a lightweight wrapper over the functionality ofsession objects, as already described above.
They are useful because itis often the case that clients wish to use multiple instances of an API thatwould otherwise be associated with the session, for example a client mightwish to have multiple instances of the file API from the file server. Sessionsare relatively heavyweight in terms of the kernel overhead associated with128INTER-THREAD COMMUNICATIONthem, so rather than insist that a new session be created to support suchparadigms, we provide a simple mechanism for multiplexing multiple‘‘sub-sessions’’ over a single session in the RSubSessionBase class.You enable sub-session creation by specifying a specific function thatthe server will use to create resources required to manage the sub-session.As well as this, the sub-session creation function generates a ‘‘sub-sessioncookie’’ that RSubSessionBase then stores, which is automaticallypassed as the fourth argument of any future messages to that session.(This leaves only three parameters for use by the sub-session requests.)When a session object receives a request that it recognizes as being fora sub-session, it uses the cookie in the fourth argument to identify thesub-session and then processes the message accordingly.
You should notethat the sub-session cookie is only shared by the client and server and isopaque to the kernel, which sees it as any other message parameter. Forexample, requests to the RFile API appear to the kernel as identical torequests to the file server session API, RFs, of which it is a sub-session.From the following declaration of RSubSessionBase, it can be seenthat it is simply a wrapper around the RSessionBase API implementedusing a private RSessionBase member and a copy of the sub-sessioncookie used to identify the sub-session to the server:class RSubSessionBase{public:inline TInt SubSessionHandle() const;protected:inline RSubSessionBase();IMPORT_C const RSessionBase Session() const;inline TInt CreateSubSession(const RSessionBase& aSession,TInt aFunction,const TIpcArgs& aArgs);inline TInt CreateSubSession(const RSessionBase& aSession,TInt aFunction);IMPORT_C TInt CreateAutoCloseSubSession(RSessionBase& aSession,TInt aFunction,const TIpcArgs& aArgs);IMPORT_C void CloseSubSession(TInt aFunction);inline TInt Send(TInt aFunction,const TIpcArgs& aArgs) const;inline void SendReceive(TInt aFunction,const TIpcArgs& aArgs,TRequestStatus& aStatus) const;inline TInt SendReceive(TInt aFunction,const TIpcArgs& aArgs) const;inline TInt Send(TInt aFunction) const;inline void SendReceive(TInt aFunction,TRequestStatus& aStatus) const;inline TInt SendReceive(TInt aFunction) const;private:RSessionBase iSession;TInt iSubSessionHandle;};Note that because a thread blocks on the synchronous API, only onesynchronous server message may be sent by a thread at a time.
Thisallows a significant optimization in the allocation of kernel-side memoryused to hold messages.CLIENT-SERVER ITC129The session and sub-session creation functions have new overloads inIPCv2 that allow the session to be created asynchronously, so the servercannot maliciously block the client whilst connecting to it.The other methods of note in RSessionBase are the ShareXxx()methods. Previously, in EKA1, a session could only be created in a nonshared state. If sharing was required, then the client had to explicitly callShare() (not present in IPCv2) or ShareAuto() to create a processrelative session handle.
A similar method has been added in EKA2 toexplicitly create a process-relative handle that is also ‘‘protected’’ and maybe passed to another process – ShareProtected().However, creating a duplicate handle is an expensive operation, sowe have now provided a new overload of RSessionBase::CreateSession() which allows the sharability of the session to be determinedfrom the creation of the session, thereby avoiding the need to performthe expensive handle duplication operation.
This then is the preferredand recommended way of creating a shared session on EKA2. Before aclient in a separate thread or process can use a given session, the sessionmust either be created with the required level of sharability or a call to aShareXxx() method must be made before the separate thread or processsends any messages to the session, or a panic will occur in the client.If the return value from a client call to RSessionBase::CreateSession() indicates that the server is not running, then the client DLLmay wish to launch the server process itself and then make anotherattempt to create a session with the server. When doing this, the clientcode needs to be able to detect whether and when the server has startedup successfully. To do this in the past, the client had to pass a structurecontaining its thread ID and a pointer to a request status object in itsaddress space to the server via the server’s command line.
The serverwould then use this structure to signal successful startup to the clientusing RThread::RequestComplete(). The introduction of threadand process rendezvous, as described in Section 3.3.6, removes the needfor this mechanism and simplifies server startup code considerably.4.1.5 Kernel-side architecture4.1.5.1 Server – queue managementThe kernel-side architecture reflects the structure of the user-side clientserver architecture it is designed to support. The first kernel-side object I’lldiscuss is the server object, corresponding to the RServer2 handle heldby the server process. The kernel-side server object has two purposes:• To ensure the uniqueness of the user-mode server within the system• To provide a FIFO queue of messages to be delivered to the serverthread. A client may deliver messages to the server at any time, butthe server thread only receives the messages one at a time as itsequentially requests them from the kernel.130INTER-THREAD COMMUNICATIONThe first requirement is easy to achieve: during server creation the kerneladds the server object being added to a global object container forservers.
As I will show in the next chapter, object containers mandate theuniqueness of names within them. Also, another check is performed atserver creation: the server may only specify a name beginning with ‘‘!’’ ifthe server has the ProtServ capability. This allows the client to be certainthat servers with names beginning with ‘‘!’’ have not been spoofed bysome other malicious code.To fulfill the second requirement, server objects use the state machineshown in Figure 4.3 to manage their FIFO queue of messages.~DServer()DServer()1., 2.3.AWAITINGMESSAGEIDLE4., 5.4., 5.2.,3.1.2.3.5.5.SESSIONATTACHEDMESSAGEPENDING3.1., 2.1., 2., 3., 5.Figure 4.3 Server object state machineThe labeled state transitions listed below are executed under theprotection of the system lock, to maintain state integrity.
Each of thesetransitions is designed to hold the system lock for constant executiontime. This maintains the real-time characteristics of the kernel as therewill always be a maximum, constant time for which the system lock willbe held before being released:1.DSession::Add()2.DSession::Detach()CLIENT-SERVER ITC1313. DServer::Receive()4. DServer::Cancel(),DServer::Close() [when closing last reference]5.
DServer::Deliver()The states in the above transition diagram are defined as follows:Session queueMessage queue[User] Serverrequest statusIDLEEmptyEmptyNULLSESSIONATTACHEDNon-emptyEmptyNULLAWAITINGMESSAGEDon’t careEmptyNon-NULLMESSAGEPENDINGDon’t careNon-emptyNULLThe implementation of this state machine can be seen in the methodsand members of the DServer class:class DServer : public DObject{public:DServer();virtual ∼DServer();virtual TInt Close(TAny*);virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType);// aMessage bit 0 = 0 -> RMessage, bit 0 = 1 -> RMessage2void Receive(TRequestStatus& aStatus, TAny* aMessage);void Cancel();void Accept(RMessageK* aMsg);void Deliver(RMessageK* aMsg);public:inline TBool IsClosing();public:DThread* iOwningThread; // thread which receives messagesTAny* iMsgDest; // where to deliver messagesTRequestStatus* iStatus; // completed to signal message arrivalSDblQue iSessionQ; // list of sessionsSDblQue iDeliveredQ; // messages delivered but not yet acceptedTUint8 iSessionType; // TIpcSessionType};The server object itself is created by ExecHandler::ServerCreate(),called (indirectly via RServer2) from CServer2::Start().