--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/euser/cbase/ub_svr.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,611 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\euser\cbase\ub_svr.cpp
+//
+//
+
+#include "ub_std.h"
+//#define __DEBUG_IMAGE__ 1
+#if defined(__DEBUG_IMAGE__) && defined (__EPOC32__)
+#include "e32svr.h"
+#define __IF_DEBUG(t) {RDebug debug;debug.t;}
+#else
+#define __IF_DEBUG(t)
+#endif
+
+
+
+_LIT(KSessionPanicCategory,"CSession");
+_LIT(KServerPanicCategory,"CServer");
+
+
+
+/**
+Default constructor.
+
+This constructor is empty.
+*/
+EXPORT_C CSession2::CSession2()
+ {}
+
+
+
+/**
+Destructor.
+
+It frees resources prior to destruction of the object.
+Specifically, it removes this session object from the server
+active object’s list of sessions.
+*/
+EXPORT_C CSession2::~CSession2()
+ {
+ if (iLink.iNext)
+ iLink.Deque();
+ }
+
+
+
+/**
+Completes construction of this server-side client session object.
+
+The function is called by the server active object, the CServer2 derived
+class instance, when a client makes a connection request.
+
+The connection request results in the creation of this session object,
+followed by a call to this function.
+
+The default implementation is empty.
+
+@see CServer2::NewSessionL()
+*/
+EXPORT_C void CSession2::CreateL()
+ {
+ }
+
+/**
+Designates the (master or slave) server that is to service this session.
+
+This may be called from the NewSessionL() method of the CServer2-derived
+class or from the CreateL() method of the CSession2-derived class.
+
+It must not be called after CreateL() has finished, as this is the point
+at which the session binding become irrevocable.
+
+@see CServer::DoConnect()
+*/
+EXPORT_C void CSession2::SetServer(const CServer2* aServer)
+ {
+ ASSERT(iLink.iNext == NULL);
+ ASSERT(aServer);
+ iServer = aServer;
+ }
+
+/**
+Handles the situation when a call to CSession2::ServiceL(), which services
+a client request, leaves.
+
+Servers are active objects, and the call to CSession2::ServiceL() to handle
+a client request is executed as part of the server's active object RunL()
+function. If the RunL() leaves, the active object framework calls the active
+object's RunError() function. The server framework implements this as a call
+to ServiceError()
+
+The default behaviour of this function is to complete the message, using
+the leave value, if it has not already been completed.
+
+Servers can re-implement this as appropriate.
+
+@param aMessage The message containing the details of the client request that
+ caused the leave.
+@param aError The leave code.
+
+@see CActive::RunL()
+@see CActive::RunError()
+*/
+EXPORT_C void CSession2::ServiceError(const RMessage2& aMessage,TInt aError)
+ {
+ if(!aMessage.IsNull())
+ aMessage.Complete(aError);
+ }
+
+
+
+/**
+Called by a server when it receives a disconnect message for the session.
+
+This message is sent by the kernel when all client handles to the session have
+been closed.
+This method deletes the session object and completes the disconnect message.
+
+A derived session implementation may overide this virtual method if it needs to
+perform any asynchronous cleanup actions, these actions must end with a call to the
+base class implementation of this method, which will delete the session object
+and complete the disconnect message
+
+@param aMessage The disconnect message.
+
+@post 'this' session object has been deleted.
+*/
+EXPORT_C void CSession2::Disconnect(const RMessage2& aMessage)
+ {
+ delete this;
+ aMessage.Complete(0);
+ }
+
+
+
+/**
+Marks the start of resource count checking.
+
+It sets up a starting value for resource count checking.
+
+The function sets up a starting value for resource count checking by using
+the value returned by a call to CSession2::CountResources(), and is the value
+that will be used for comparison if CSession2::ResourceCountMarkEnd() is called
+at some later time.
+
+The client/server framework does not call this function (nor
+does it call CSession2::ResourceCountMarkEnd()), but is available for servers
+to use, if appropriate.
+
+@see CSession2::CountResources()
+@see CSession2::ResourceCountMarkEnd()
+*/
+EXPORT_C void CSession2::ResourceCountMarkStart()
+ {
+ iResourceCountMark=CountResources();
+ }
+
+
+
+/**
+Marks the end of resource count checking.
+
+The function takes the current resource count by
+calling CSession2::CountResources(), and compares it with the resource count
+value saved when CSession2::ResourceCountMarkStart() was called.
+If the resource counts differ, then the client thread is panicked (CSession 2)".
+
+The client/server framework does not call this function (nor does it call
+CSession2::ResourceCountMarkStart()), but the function is available for
+servers to use, if appropriate.
+
+@param aMessage Represents the details of the client request that is requesting
+ this resource check.
+
+@see CSession2::CountResources()
+@see CSession2::ResourceCountMarkStart()
+*/
+EXPORT_C void CSession2::ResourceCountMarkEnd(const RMessage2& aMessage)
+ {
+ if (iResourceCountMark!=CountResources())
+ aMessage.Panic(KSessionPanicCategory,ESesFoundResCountHeaven);
+ }
+
+
+
+/**
+Gets the number of resources currently in use.
+
+Derived classes must provide a suitable implementation.
+The meaning of a resource depends on the design intent of the server.
+
+The default implementation panics the calling thread (CSession 1)
+before returning KErrGeneral.
+
+@return The current number of resources in use.
+
+@see CSession2::ResourceCountmarkStart()
+@see CSession2::ResourceCountmarkEnd()
+*/
+EXPORT_C TInt CSession2::CountResources()
+ {
+ User::Panic(KSessionPanicCategory,ESesCountResourcesNotImplemented);
+ return KErrGeneral;
+ }
+
+
+
+/**
+Extension function
+
+
+*/
+EXPORT_C TInt CSession2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+ {
+ return CBase::Extension_(aExtensionId, a0, a1);
+ }
+
+
+
+
+/**
+Constructs the server object, specifying the server type and the active
+object priority.
+
+Derived classes must define and implement a constructor through which
+the priority can be specified. A typical implementation calls this server
+base class constructor through a constructor initialization list.
+
+@param aPriority The priority of this active object.
+@param aType Indicates the type of session that the server creates.
+ If not explicitly stated, then the server creates
+ a session that is not sharable with other threads.
+*/
+EXPORT_C CServer2::CServer2(TInt aPriority, TServerType aType)
+ : CActive(aPriority),
+ iSessionType((TUint8)aType),
+ iSessionQ(_FOFF(CSession2,iLink)),
+ iSessionIter(iSessionQ)
+ {
+ ASSERT(iSessionType == aType);
+ __ASSERT_COMPILE(EServerRole_Default == 0);
+ __ASSERT_COMPILE(EServerOpt_PinClientDescriptorsDefault == 0);
+ }
+
+
+
+/**
+Frees resources prior to destruction.
+
+Specifically, it cancels any outstanding request for messages, and
+deletes all server-side client session objects.
+*/
+EXPORT_C CServer2::~CServer2()
+ {
+ Cancel();
+ while (!iSessionQ.IsEmpty())
+ {
+ CSession2 *pS=iSessionQ.First();
+ pS->iLink.Deque();
+ pS->iLink.iNext=0;
+ delete pS;
+ }
+ iServer.Close();
+ }
+
+
+/**
+Sets whether the kernel will pin descriptors passed to this server in the context of the client
+thread.
+
+Setting this is one way of ensuring that the server will not take page faults when accessing client
+descriptors, which would otherwise happen if the data was paged out.
+
+This method overrides the default pinning policy of the server which is for the server
+to pin its client's descriptors if the process creating the server is not data paged.
+I.e. if CServer2::SetPinClientDescriptors() is not invoked on the server and
+RProcess::DefaultDataPaged() of the process creating the server returns EFalse,
+the server will pin its client's descriptors, otherwise the server will not pin its
+client's descriptors.
+
+This method must be called prior to starting the server by calling the Start() method.
+
+@param aPin Set to ETrue for the server to pin its client's descriptors, set to
+ EFalse otherwise.
+@panic E32USER-CBase 106 When this method is invoked after the server has been started.
+@see CServer2::Start()
+
+@prototype
+*/
+EXPORT_C void CServer2::SetPinClientDescriptors(TBool aPin)
+ {
+ if (iServer.Handle() != KNullHandle)
+ {// Server already started so too late to make it a pinning one.
+ Panic(ECServer2InvalidSetPin);
+ }
+ iServerOpts &= ~EServerOpt_PinClientDescriptorsMask;
+ if (aPin)
+ iServerOpts |= EServerOpt_PinClientDescriptorsEnable;
+ else
+ iServerOpts |= EServerOpt_PinClientDescriptorsDisable;
+ }
+
+/**
+Assigns a role (master or slave) for this server.
+
+The master server is typically named, and receives all Connect messages
+from clients. It can hand off some sessions to be processed by one or
+more anonymous slave servers, each running in a separate thread.
+
+Both master and slave servers must call this function before calling
+Start(), in order to define their roles. Once the server is started,
+its role cannot be changed.
+
+@panic E32USER-CBase-? When this method is invoked after the server has been started.
+@see CServer2::Start()
+
+@prototype
+*/
+EXPORT_C void CServer2::SetMaster(const CServer2* aServer)
+ {
+ // Roles can only be assigned before the call to Start()
+ ASSERT(Server().Handle() == KNullHandle);
+
+ if (aServer == NULL)
+ iServerRole = EServerRole_Standalone;
+ else if (aServer == this)
+ iServerRole = EServerRole_Master;
+ else
+ iServerRole = EServerRole_Slave;
+ }
+
+
+/**
+Adds the server with the specified name to the active scheduler,
+and issues the first request for messages.
+
+If KNullDesC is specified for the name, then an anonymous server will be created.
+To create a session to such a server, an overload of RSessionBase::CreateSession()
+which takes RServer2 object as a parameter can be used.
+
+@param aName The name of the server.
+ KNullDesC, to create anonymous servers.
+@return KErrNone, if successful, otherwise one of the other system wide error codes.
+
+@capability ProtServ if aName starts with a '!' character
+*/
+EXPORT_C TInt CServer2::Start(const TDesC& aName)
+ {
+ TInt r = iServer.CreateGlobal(aName, iSessionType, iServerRole, iServerOpts);
+ if (r == KErrNone)
+ {
+ CActiveScheduler::Add(this);
+ ReStart();
+ }
+ return r;
+ }
+
+
+
+/**
+Adds the server with the specified name to the active scheduler,
+and issues the first request for messages, and leaves if the operation fails.
+
+If KNullDesC is specified for the name, then an anonymous server will be created.
+To create a session to such a server, the overload of RSessionBase::CreateSession()
+which takes an RServer2 object as a parameter can be used.
+
+@param aName The name of the server.
+ KNullDesC, to create anonymous servers.
+@capability ProtServ if aName starts with a '!' character
+*/
+EXPORT_C void CServer2::StartL(const TDesC& aName)
+ {
+ User::LeaveIfError(Start(aName));
+ }
+
+
+
+/**
+Implements the cancellation of any outstanding request for messages.
+*/
+EXPORT_C void CServer2::DoCancel()
+ {
+
+ iServer.Cancel();
+ }
+
+
+
+void CServer2::Connect(const RMessage2& aMessage)
+//
+// Handle a connect request. Ptr0()==Version.
+// NOTE: We don't want this to leave as that may kill the server
+//
+ {
+
+ if (aMessage.Session())
+ {
+ aMessage.Panic(KServerPanicCategory,ESessionAlreadyConnected);
+ return;
+ }
+ DoConnect(aMessage);
+ }
+
+
+
+//
+//This is all of the Leaving code for connection creation.
+//This is in a seperate function in an effort to force compilers to store aSession
+//on the stack which enables cleanup to perform correctly when a Leave occurs
+//
+void CServer2::DoConnectL(const RMessage2& aMessage,CSession2* volatile& aSession)
+ {
+ TVersion v;
+ *(TInt*)&v = aMessage.Int0();
+ aSession = NewSessionL(v, aMessage);
+ if (!aSession->iServer)
+ aSession->iServer = this;
+ aSession->CreateL();
+ iSessionQ.AddLast(*aSession);
+ Exec::SetSessionPtr(aMessage.Handle(), aSession);
+ }
+
+
+
+/**
+Handles the connect request from the client. We trap Leaves, to ensure
+that existing sessions aren't affected by failure to create a new one.
+
+@param aMessage The Connect message sent by the client requesting the
+ connection. aMessage.Ptr0() is the required Version.
+*/
+EXPORT_C void CServer2::DoConnect(const RMessage2& aMessage)
+ {
+ ASSERT(aMessage.Function() == RMessage2::EConnect);
+ ASSERT(aMessage.Session() == NULL);
+ ASSERT(!aMessage.IsNull());
+
+ CSession2* newSession = NULL;
+ TRAPD(err, DoConnectL(aMessage, newSession));
+ if (err != KErrNone)
+ {
+ // Connect failed
+ delete newSession;
+ aMessage.Complete(err);
+ }
+ else
+ {
+ ASSERT(newSession != NULL);
+ CServer2* sessionServer = const_cast<CServer2*>(newSession->Server());
+ ASSERT(sessionServer != NULL);
+
+ // The return value of Server() will be 'this', unless it was
+ // changed by a call to SetServer().
+ if (sessionServer == this)
+ {
+ // no SetServer() call, so just complete the Connect message
+ aMessage.Complete(err);
+ }
+ else
+ {
+ // Transfer the new Csession to the specified slave Cserver
+ newSession->iLink.Deque();
+ sessionServer->iSessionQ.AddLast(*newSession);
+
+ // Ask the kernel to transfer the DSession to the slave DServer.
+ // Note: this Exec call also completes the Connect message.
+ TInt msgHandle = aMessage.iHandle;
+ const_cast<TInt&>(aMessage.iHandle) = 0;
+ ASSERT(msgHandle);
+ Exec::TransferSession(msgHandle, sessionServer->Server().Handle());
+ }
+ }
+
+ ASSERT(aMessage.IsNull());
+ }
+
+
+
+/**
+Handles the situation where a call to CServer2::RunL(), leaves.
+
+This is the server active object's implementation of the active object
+framework's RunError() function.
+
+In practice, the leave can only be caused by a session's ServiceL() function,
+which is called from this RunL(); this error is reflected back to that session
+by calling its ServiceError() function.
+
+@param aError The leave code.
+
+@return KErrNone.
+
+@see CActive::RunL()
+@see CActive::RunError()
+@see CSession2::ServiceError()
+*/
+EXPORT_C TInt CServer2::RunError(TInt aError)
+ {
+ Message().Session()->ServiceError(Message(),aError);
+ if (!IsActive())
+ ReStart();
+ return KErrNone;
+ }
+
+
+
+/**
+Restarts the server.
+
+The function issues a request for messages.
+*/
+EXPORT_C void CServer2::ReStart()
+ {
+
+ iServer.Receive(iMessage,iStatus);
+ SetActive();
+ }
+
+
+
+#ifndef __CSERVER_MACHINE_CODED__
+/**
+Handles the receipt of a message.
+*/
+EXPORT_C void CServer2::RunL()
+ {
+ TInt fn = Message().Function();
+
+ if(fn>=0)
+ {
+ // Service the message
+ CSession2* session=Message().Session();
+ if(session)
+ session->ServiceL(Message());
+ else
+ NotConnected(Message());
+ }
+ else if(fn==RMessage2::EConnect)
+ {
+ Connect(Message());
+ }
+ else if(fn==RMessage2::EDisConnect)
+ {
+ Disconnect(Message());
+ }
+ else
+ {
+ BadMessage(Message());
+ }
+ // Queue reception of next message if it hasn't already been done
+ if(!IsActive())
+ ReStart();
+ }
+
+#endif
+
+
+
+void CServer2::Disconnect(const RMessage2& aMessage)
+//
+// Process a disconnect message
+//
+ {
+ CSession2* session=Message().Session();
+ if(!session)
+ {
+ // Session not created yet, so just complete message.
+ aMessage.Complete(0);
+ return;
+ }
+ session->Disconnect(aMessage);
+ }
+
+
+
+void CServer2::BadMessage(const RMessage2& aMessage)
+ {
+ aMessage.Panic(KServerPanicCategory,EBadMessageNumber);
+ }
+
+
+
+void CServer2::NotConnected(const RMessage2& aMessage)
+ {
+ aMessage.Panic(KServerPanicCategory,ESessionNotConnected);
+ }
+
+
+
+/**
+Extension function
+
+
+*/
+EXPORT_C TInt CServer2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+ {
+ return CActive::Extension_(aExtensionId, a0, a1);
+ }