Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 40
Текст из файла (страница 40)
When therequest has been handled, the server calls RMessage::Complete()to notify the client thread of request completion. The example code inChapter 12 illustrates this.You’ll notice a set of resource-counting functions, ResourceCountMarkStart(), ResourceCountMarkEnd() and CountResources(), which have a default, ”do nothing” implementation in theCSharableSession base class but which may be overridden by derivedclasses for customized resource checking at server startup and shutdown,usually used only in debug builds. ResourceCountMarkStart() initializes server resource counting while ResourceCountMarkEnd()checks that the current number of server resources (e.g. subsessions) inuse is equivalent to that when resource counting started.
If the valuesare not equal, the function panics the client thread associated with themost recent message. CountResources() returns the number of serverresources currently in use.Prior to Symbian OS v6.0, class CSession represented a session onthe server side. The CSession class was thread-specific and accessibleonly by a single thread on the client side. Symbian OS v6.0 introducedthe concept of sharable client–server sessions.
From v6.0, a client sessionmay potentially be shared between multiple threads in the same clientprocess, although a server implementation is not required to supportsharable sessions. To support this modification, Symbian OS v6.0 introduced CSharableSession as the base class for a server-side session.CSession still exists, deriving from CSharableSession, as an abstractclass which provides a set of thread-specific functions to transfer databetween client and server.178THE CLIENT–SERVER FRAMEWORK IN THEORYCServerThe fundamental server-side base class is CServer, which itself derivesfrom CActive.
Here’s the definition of CServer from e32base.h,with the less relevant details omitted for clarity:class CServer : public CActive{public:IMPORT_C ∼CServer()=0;IMPORT_C TInt Start(const TDesC& aName);IMPORT_C void StartL(const TDesC& aName);IMPORT_C void ReStart();inline const RMessage& Message() const;protected:IMPORT_C CServer(TInt aPriority,TServerType aType=EUnsharableSessions);IMPORT_C void DoCancel();IMPORT_C void RunL();private:virtual CSharableSession* NewSessionL(const TVersion& aVersion)const=0;void Connect();private:const TServerType iSessionType;RServer iServer;TDblQue<CSharableSession> iSessionQ;protected:// to iterate the list of connected sessionsTDblQueIter<CSharableSession> iSessionIter;};The system ensures that there is only one CServer-derived activeobject created for each uniquely-named server.
This object receivesrequests from all clients of the server as events, receiving notification ofeach incoming request from the kernel. By inspecting the RMessage associated with the request, the event handler method, CServer::RunL(),determines whether the CServer-derived object handles the requestsitself or directs them to be handled by the appropriate server-side session class.If the request is to connect a new session, CServer::RunL() callsthe NewSessionL() method of the derived class, which creates a newserver-side session object. If it is a request from a client-side sessionto disconnect, the associated server-side session object is destroyedin CServer::RunL().
For other client requests, CServer::RunL()calls the ServiceL() method of the associated CSharableSessionderived object to service the request. Having serviced each request,CServer::RunL() resubmits a ”message receive” request and awaitsfurther client requests.When you are implementing a server, you must create an active scheduler as part of server startup (as I described in Chapter 8, which coversHOW IS A SERVER STARTED?179the basics of active objects). I’ll illustrate how to do this in the examplecode for a typical server in the next chapter. CServer::StartL()adds the server to the active scheduler and initiates the first messagereceive request.For each CServer object created in the system, a correspondingDServer object is created in the kernel.
Each DServer object holdsa doubly-linked queue of all DSessions, representing all the currentlyopen sessions for that server. It also owns a kernel object, DThread,which represents the server thread.When implementing a server, you must create an active schedulerduring server startup.11.5 How Do Synchronous and AsynchronousRequests Differ?A client can request synchronous or asynchronous services8 from a server.Asynchronous requests take a TRequestStatus reference parameter,which is passed to RSessionBase::SendReceive(). This parameteris filled with a completion result by the server, via the kernel, when therequest is completed by a call to RThread::RequestComplete(),which also signals the request semaphore of the client thread to notify itof request completion.In fact, synchronous requests to the server are actually ”pseudosynchronous”.
The synchronous overload of RSessionBase::SendReceive() declares a TRequestStatus object locally, passes thisto the asynchronous overload of SendReceive() and then blocks theclient thread until the request completes. In effect, the client thread issuspended and notified only when a server has completed its action,rather than continuing to poll the server for the status of a request. This isimportant on Symbian OS, to minimize power consumption.11.6 How Is a Server Started?There are several ways in which a server can be started and stopped:• System servers, e.g. the file server, are started by Symbian OS as partof OS startup because they are essential to the operating system.8For each asynchronous request function a server API provides, it must also provide acancellation method.180THE CLIENT–SERVER FRAMEWORK IN THEORY• Application servers, which are only needed when certain applicationsare running, are started when clients need to connect to them.
Ifan application attempts to start a server that is already running, saybecause it has been started by another application, no error resultsand only a single instance of the server runs. When the server hasno outstanding clients, that is, when the last client session closes,it should terminate to save system resources. This type of server isknown as a transient server. I’ll illustrate startup and shutdown for thiskind of server in the next chapter.• Other servers, e.g.
the POSIX server, are required by only a singleapplication and are started with that application and closed whenit terminates.11.7How Many Connections Can a Client Have?A client can have multiple ”connections” to a server through one or moresessions as follows:• Each connection can use a separate client–server session opened bya call to RSessionBase::CreateSession(). The sessions areindependent of any other within the client thread, and each maintainsits own context.
That is, each client session has a correspondingCSharableSession object in the server and DSession object inthe kernel. Use of multiple client sessions where they are not strictlynecessary should be limited to reduce the number of kernel and serverresources consumed – I’ll discuss this further later in this chapter.• The client may create a number of subsessions within a single session(the use of subsessions is described in Section 11.14).
Client–servercommunication occurs via the owning session, using a unique handleto identify each individual subsession. The use of separate subsessionsis more lightweight than separate sessions because it uses fewerkernel resources. However, they are more complex to implementserver-side.• The server may support sharable sessions. Up to 255 threads in aclient process may share a single session.11.8What Happens When a Client Disconnects?Typically, a class used to access a server has a termination method,which is usually called Close(). Internally, this method will callRHandleBase::Close(), which sends a disconnection message tothe server and sets the session handle to zero. On receipt of this message,HOW DOES CLIENT–SERVER COMMUNICATION USE THREADS?181the server ends its session with the client by destroying the associatedCSharableSession-derived object (in addition, the kernel will destroythe DSession object which represents the session).
If the client has anyoutstanding requests when Close() is called, they are not guaranteedto be completed.11.9 What Happens If a Client Dies?For a non-sharable session, if the client dies without calling Close(),the kernel sends a disconnection message to the server to allow it tocleanup sessions associated with that client thread. The kernel performsits thread-death cleanup by walking the queue of DSession objects anddestroying any associated with the dead client thread.If the session is sharable, the death of a single client thread does notclose the session – the session is effectively process-relative by virtue ofbeing sharable. To destroy the session, either the client process mustterminate or the session must be closed explicitly on the client-side by acall to Close() on an RSessionBase handle.11.10What Happens If a Server Dies?If a server dies, the kernel will complete any waiting client requestswith the error code KErrServerTerminated.
This gives the clientan opportunity to handle request failure and cleanup, destroying anyRSessionBase objects open on the server. Even if the server is restarted,previous client sessions cannot be reused without first being reconnectedto it, so the only valid operation is to call Close().11.11How Does Client–Server CommunicationUse Threads?A session between a client and a server is between one or more clientthreads and a separate server thread. Client code runs in user-modethreads. It submits requests to server code which also runs in user mode.The channel of communication between client and server is mediated bythe kernel.The Symbian OS server model is thread-based, allowing a server torun either in a separate process to the client, for greater isolation betweenclient and server, or in the same process, to avoid the overhead ofinter-process client–server communication.18211.12THE CLIENT–SERVER FRAMEWORK IN THEORYWhat Are the Implications of Server-SideActive Objects?The responsiveness of a server can be defined as the maximum timerequired to process a client message or the maximum time required torespond to an event on some device that it controls.