1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/euser/cbase/ub_svr.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,611 @@
1.4 +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\euser\cbase\ub_svr.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include "ub_std.h"
1.22 +//#define __DEBUG_IMAGE__ 1
1.23 +#if defined(__DEBUG_IMAGE__) && defined (__EPOC32__)
1.24 +#include "e32svr.h"
1.25 +#define __IF_DEBUG(t) {RDebug debug;debug.t;}
1.26 +#else
1.27 +#define __IF_DEBUG(t)
1.28 +#endif
1.29 +
1.30 +
1.31 +
1.32 +_LIT(KSessionPanicCategory,"CSession");
1.33 +_LIT(KServerPanicCategory,"CServer");
1.34 +
1.35 +
1.36 +
1.37 +/**
1.38 +Default constructor.
1.39 +
1.40 +This constructor is empty.
1.41 +*/
1.42 +EXPORT_C CSession2::CSession2()
1.43 + {}
1.44 +
1.45 +
1.46 +
1.47 +/**
1.48 +Destructor.
1.49 +
1.50 +It frees resources prior to destruction of the object.
1.51 +Specifically, it removes this session object from the server
1.52 +active object’s list of sessions.
1.53 +*/
1.54 +EXPORT_C CSession2::~CSession2()
1.55 + {
1.56 + if (iLink.iNext)
1.57 + iLink.Deque();
1.58 + }
1.59 +
1.60 +
1.61 +
1.62 +/**
1.63 +Completes construction of this server-side client session object.
1.64 +
1.65 +The function is called by the server active object, the CServer2 derived
1.66 +class instance, when a client makes a connection request.
1.67 +
1.68 +The connection request results in the creation of this session object,
1.69 +followed by a call to this function.
1.70 +
1.71 +The default implementation is empty.
1.72 +
1.73 +@see CServer2::NewSessionL()
1.74 +*/
1.75 +EXPORT_C void CSession2::CreateL()
1.76 + {
1.77 + }
1.78 +
1.79 +/**
1.80 +Designates the (master or slave) server that is to service this session.
1.81 +
1.82 +This may be called from the NewSessionL() method of the CServer2-derived
1.83 +class or from the CreateL() method of the CSession2-derived class.
1.84 +
1.85 +It must not be called after CreateL() has finished, as this is the point
1.86 +at which the session binding become irrevocable.
1.87 +
1.88 +@see CServer::DoConnect()
1.89 +*/
1.90 +EXPORT_C void CSession2::SetServer(const CServer2* aServer)
1.91 + {
1.92 + ASSERT(iLink.iNext == NULL);
1.93 + ASSERT(aServer);
1.94 + iServer = aServer;
1.95 + }
1.96 +
1.97 +/**
1.98 +Handles the situation when a call to CSession2::ServiceL(), which services
1.99 +a client request, leaves.
1.100 +
1.101 +Servers are active objects, and the call to CSession2::ServiceL() to handle
1.102 +a client request is executed as part of the server's active object RunL()
1.103 +function. If the RunL() leaves, the active object framework calls the active
1.104 +object's RunError() function. The server framework implements this as a call
1.105 +to ServiceError()
1.106 +
1.107 +The default behaviour of this function is to complete the message, using
1.108 +the leave value, if it has not already been completed.
1.109 +
1.110 +Servers can re-implement this as appropriate.
1.111 +
1.112 +@param aMessage The message containing the details of the client request that
1.113 + caused the leave.
1.114 +@param aError The leave code.
1.115 +
1.116 +@see CActive::RunL()
1.117 +@see CActive::RunError()
1.118 +*/
1.119 +EXPORT_C void CSession2::ServiceError(const RMessage2& aMessage,TInt aError)
1.120 + {
1.121 + if(!aMessage.IsNull())
1.122 + aMessage.Complete(aError);
1.123 + }
1.124 +
1.125 +
1.126 +
1.127 +/**
1.128 +Called by a server when it receives a disconnect message for the session.
1.129 +
1.130 +This message is sent by the kernel when all client handles to the session have
1.131 +been closed.
1.132 +This method deletes the session object and completes the disconnect message.
1.133 +
1.134 +A derived session implementation may overide this virtual method if it needs to
1.135 +perform any asynchronous cleanup actions, these actions must end with a call to the
1.136 +base class implementation of this method, which will delete the session object
1.137 +and complete the disconnect message
1.138 +
1.139 +@param aMessage The disconnect message.
1.140 +
1.141 +@post 'this' session object has been deleted.
1.142 +*/
1.143 +EXPORT_C void CSession2::Disconnect(const RMessage2& aMessage)
1.144 + {
1.145 + delete this;
1.146 + aMessage.Complete(0);
1.147 + }
1.148 +
1.149 +
1.150 +
1.151 +/**
1.152 +Marks the start of resource count checking.
1.153 +
1.154 +It sets up a starting value for resource count checking.
1.155 +
1.156 +The function sets up a starting value for resource count checking by using
1.157 +the value returned by a call to CSession2::CountResources(), and is the value
1.158 +that will be used for comparison if CSession2::ResourceCountMarkEnd() is called
1.159 +at some later time.
1.160 +
1.161 +The client/server framework does not call this function (nor
1.162 +does it call CSession2::ResourceCountMarkEnd()), but is available for servers
1.163 +to use, if appropriate.
1.164 +
1.165 +@see CSession2::CountResources()
1.166 +@see CSession2::ResourceCountMarkEnd()
1.167 +*/
1.168 +EXPORT_C void CSession2::ResourceCountMarkStart()
1.169 + {
1.170 + iResourceCountMark=CountResources();
1.171 + }
1.172 +
1.173 +
1.174 +
1.175 +/**
1.176 +Marks the end of resource count checking.
1.177 +
1.178 +The function takes the current resource count by
1.179 +calling CSession2::CountResources(), and compares it with the resource count
1.180 +value saved when CSession2::ResourceCountMarkStart() was called.
1.181 +If the resource counts differ, then the client thread is panicked (CSession 2)".
1.182 +
1.183 +The client/server framework does not call this function (nor does it call
1.184 +CSession2::ResourceCountMarkStart()), but the function is available for
1.185 +servers to use, if appropriate.
1.186 +
1.187 +@param aMessage Represents the details of the client request that is requesting
1.188 + this resource check.
1.189 +
1.190 +@see CSession2::CountResources()
1.191 +@see CSession2::ResourceCountMarkStart()
1.192 +*/
1.193 +EXPORT_C void CSession2::ResourceCountMarkEnd(const RMessage2& aMessage)
1.194 + {
1.195 + if (iResourceCountMark!=CountResources())
1.196 + aMessage.Panic(KSessionPanicCategory,ESesFoundResCountHeaven);
1.197 + }
1.198 +
1.199 +
1.200 +
1.201 +/**
1.202 +Gets the number of resources currently in use.
1.203 +
1.204 +Derived classes must provide a suitable implementation.
1.205 +The meaning of a resource depends on the design intent of the server.
1.206 +
1.207 +The default implementation panics the calling thread (CSession 1)
1.208 +before returning KErrGeneral.
1.209 +
1.210 +@return The current number of resources in use.
1.211 +
1.212 +@see CSession2::ResourceCountmarkStart()
1.213 +@see CSession2::ResourceCountmarkEnd()
1.214 +*/
1.215 +EXPORT_C TInt CSession2::CountResources()
1.216 + {
1.217 + User::Panic(KSessionPanicCategory,ESesCountResourcesNotImplemented);
1.218 + return KErrGeneral;
1.219 + }
1.220 +
1.221 +
1.222 +
1.223 +/**
1.224 +Extension function
1.225 +
1.226 +
1.227 +*/
1.228 +EXPORT_C TInt CSession2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
1.229 + {
1.230 + return CBase::Extension_(aExtensionId, a0, a1);
1.231 + }
1.232 +
1.233 +
1.234 +
1.235 +
1.236 +/**
1.237 +Constructs the server object, specifying the server type and the active
1.238 +object priority.
1.239 +
1.240 +Derived classes must define and implement a constructor through which
1.241 +the priority can be specified. A typical implementation calls this server
1.242 +base class constructor through a constructor initialization list.
1.243 +
1.244 +@param aPriority The priority of this active object.
1.245 +@param aType Indicates the type of session that the server creates.
1.246 + If not explicitly stated, then the server creates
1.247 + a session that is not sharable with other threads.
1.248 +*/
1.249 +EXPORT_C CServer2::CServer2(TInt aPriority, TServerType aType)
1.250 + : CActive(aPriority),
1.251 + iSessionType((TUint8)aType),
1.252 + iSessionQ(_FOFF(CSession2,iLink)),
1.253 + iSessionIter(iSessionQ)
1.254 + {
1.255 + ASSERT(iSessionType == aType);
1.256 + __ASSERT_COMPILE(EServerRole_Default == 0);
1.257 + __ASSERT_COMPILE(EServerOpt_PinClientDescriptorsDefault == 0);
1.258 + }
1.259 +
1.260 +
1.261 +
1.262 +/**
1.263 +Frees resources prior to destruction.
1.264 +
1.265 +Specifically, it cancels any outstanding request for messages, and
1.266 +deletes all server-side client session objects.
1.267 +*/
1.268 +EXPORT_C CServer2::~CServer2()
1.269 + {
1.270 + Cancel();
1.271 + while (!iSessionQ.IsEmpty())
1.272 + {
1.273 + CSession2 *pS=iSessionQ.First();
1.274 + pS->iLink.Deque();
1.275 + pS->iLink.iNext=0;
1.276 + delete pS;
1.277 + }
1.278 + iServer.Close();
1.279 + }
1.280 +
1.281 +
1.282 +/**
1.283 +Sets whether the kernel will pin descriptors passed to this server in the context of the client
1.284 +thread.
1.285 +
1.286 +Setting this is one way of ensuring that the server will not take page faults when accessing client
1.287 +descriptors, which would otherwise happen if the data was paged out.
1.288 +
1.289 +This method overrides the default pinning policy of the server which is for the server
1.290 +to pin its client's descriptors if the process creating the server is not data paged.
1.291 +I.e. if CServer2::SetPinClientDescriptors() is not invoked on the server and
1.292 +RProcess::DefaultDataPaged() of the process creating the server returns EFalse,
1.293 +the server will pin its client's descriptors, otherwise the server will not pin its
1.294 +client's descriptors.
1.295 +
1.296 +This method must be called prior to starting the server by calling the Start() method.
1.297 +
1.298 +@param aPin Set to ETrue for the server to pin its client's descriptors, set to
1.299 + EFalse otherwise.
1.300 +@panic E32USER-CBase 106 When this method is invoked after the server has been started.
1.301 +@see CServer2::Start()
1.302 +
1.303 +@prototype
1.304 +*/
1.305 +EXPORT_C void CServer2::SetPinClientDescriptors(TBool aPin)
1.306 + {
1.307 + if (iServer.Handle() != KNullHandle)
1.308 + {// Server already started so too late to make it a pinning one.
1.309 + Panic(ECServer2InvalidSetPin);
1.310 + }
1.311 + iServerOpts &= ~EServerOpt_PinClientDescriptorsMask;
1.312 + if (aPin)
1.313 + iServerOpts |= EServerOpt_PinClientDescriptorsEnable;
1.314 + else
1.315 + iServerOpts |= EServerOpt_PinClientDescriptorsDisable;
1.316 + }
1.317 +
1.318 +/**
1.319 +Assigns a role (master or slave) for this server.
1.320 +
1.321 +The master server is typically named, and receives all Connect messages
1.322 +from clients. It can hand off some sessions to be processed by one or
1.323 +more anonymous slave servers, each running in a separate thread.
1.324 +
1.325 +Both master and slave servers must call this function before calling
1.326 +Start(), in order to define their roles. Once the server is started,
1.327 +its role cannot be changed.
1.328 +
1.329 +@panic E32USER-CBase-? When this method is invoked after the server has been started.
1.330 +@see CServer2::Start()
1.331 +
1.332 +@prototype
1.333 +*/
1.334 +EXPORT_C void CServer2::SetMaster(const CServer2* aServer)
1.335 + {
1.336 + // Roles can only be assigned before the call to Start()
1.337 + ASSERT(Server().Handle() == KNullHandle);
1.338 +
1.339 + if (aServer == NULL)
1.340 + iServerRole = EServerRole_Standalone;
1.341 + else if (aServer == this)
1.342 + iServerRole = EServerRole_Master;
1.343 + else
1.344 + iServerRole = EServerRole_Slave;
1.345 + }
1.346 +
1.347 +
1.348 +/**
1.349 +Adds the server with the specified name to the active scheduler,
1.350 +and issues the first request for messages.
1.351 +
1.352 +If KNullDesC is specified for the name, then an anonymous server will be created.
1.353 +To create a session to such a server, an overload of RSessionBase::CreateSession()
1.354 +which takes RServer2 object as a parameter can be used.
1.355 +
1.356 +@param aName The name of the server.
1.357 + KNullDesC, to create anonymous servers.
1.358 +@return KErrNone, if successful, otherwise one of the other system wide error codes.
1.359 +
1.360 +@capability ProtServ if aName starts with a '!' character
1.361 +*/
1.362 +EXPORT_C TInt CServer2::Start(const TDesC& aName)
1.363 + {
1.364 + TInt r = iServer.CreateGlobal(aName, iSessionType, iServerRole, iServerOpts);
1.365 + if (r == KErrNone)
1.366 + {
1.367 + CActiveScheduler::Add(this);
1.368 + ReStart();
1.369 + }
1.370 + return r;
1.371 + }
1.372 +
1.373 +
1.374 +
1.375 +/**
1.376 +Adds the server with the specified name to the active scheduler,
1.377 +and issues the first request for messages, and leaves if the operation fails.
1.378 +
1.379 +If KNullDesC is specified for the name, then an anonymous server will be created.
1.380 +To create a session to such a server, the overload of RSessionBase::CreateSession()
1.381 +which takes an RServer2 object as a parameter can be used.
1.382 +
1.383 +@param aName The name of the server.
1.384 + KNullDesC, to create anonymous servers.
1.385 +@capability ProtServ if aName starts with a '!' character
1.386 +*/
1.387 +EXPORT_C void CServer2::StartL(const TDesC& aName)
1.388 + {
1.389 + User::LeaveIfError(Start(aName));
1.390 + }
1.391 +
1.392 +
1.393 +
1.394 +/**
1.395 +Implements the cancellation of any outstanding request for messages.
1.396 +*/
1.397 +EXPORT_C void CServer2::DoCancel()
1.398 + {
1.399 +
1.400 + iServer.Cancel();
1.401 + }
1.402 +
1.403 +
1.404 +
1.405 +void CServer2::Connect(const RMessage2& aMessage)
1.406 +//
1.407 +// Handle a connect request. Ptr0()==Version.
1.408 +// NOTE: We don't want this to leave as that may kill the server
1.409 +//
1.410 + {
1.411 +
1.412 + if (aMessage.Session())
1.413 + {
1.414 + aMessage.Panic(KServerPanicCategory,ESessionAlreadyConnected);
1.415 + return;
1.416 + }
1.417 + DoConnect(aMessage);
1.418 + }
1.419 +
1.420 +
1.421 +
1.422 +//
1.423 +//This is all of the Leaving code for connection creation.
1.424 +//This is in a seperate function in an effort to force compilers to store aSession
1.425 +//on the stack which enables cleanup to perform correctly when a Leave occurs
1.426 +//
1.427 +void CServer2::DoConnectL(const RMessage2& aMessage,CSession2* volatile& aSession)
1.428 + {
1.429 + TVersion v;
1.430 + *(TInt*)&v = aMessage.Int0();
1.431 + aSession = NewSessionL(v, aMessage);
1.432 + if (!aSession->iServer)
1.433 + aSession->iServer = this;
1.434 + aSession->CreateL();
1.435 + iSessionQ.AddLast(*aSession);
1.436 + Exec::SetSessionPtr(aMessage.Handle(), aSession);
1.437 + }
1.438 +
1.439 +
1.440 +
1.441 +/**
1.442 +Handles the connect request from the client. We trap Leaves, to ensure
1.443 +that existing sessions aren't affected by failure to create a new one.
1.444 +
1.445 +@param aMessage The Connect message sent by the client requesting the
1.446 + connection. aMessage.Ptr0() is the required Version.
1.447 +*/
1.448 +EXPORT_C void CServer2::DoConnect(const RMessage2& aMessage)
1.449 + {
1.450 + ASSERT(aMessage.Function() == RMessage2::EConnect);
1.451 + ASSERT(aMessage.Session() == NULL);
1.452 + ASSERT(!aMessage.IsNull());
1.453 +
1.454 + CSession2* newSession = NULL;
1.455 + TRAPD(err, DoConnectL(aMessage, newSession));
1.456 + if (err != KErrNone)
1.457 + {
1.458 + // Connect failed
1.459 + delete newSession;
1.460 + aMessage.Complete(err);
1.461 + }
1.462 + else
1.463 + {
1.464 + ASSERT(newSession != NULL);
1.465 + CServer2* sessionServer = const_cast<CServer2*>(newSession->Server());
1.466 + ASSERT(sessionServer != NULL);
1.467 +
1.468 + // The return value of Server() will be 'this', unless it was
1.469 + // changed by a call to SetServer().
1.470 + if (sessionServer == this)
1.471 + {
1.472 + // no SetServer() call, so just complete the Connect message
1.473 + aMessage.Complete(err);
1.474 + }
1.475 + else
1.476 + {
1.477 + // Transfer the new Csession to the specified slave Cserver
1.478 + newSession->iLink.Deque();
1.479 + sessionServer->iSessionQ.AddLast(*newSession);
1.480 +
1.481 + // Ask the kernel to transfer the DSession to the slave DServer.
1.482 + // Note: this Exec call also completes the Connect message.
1.483 + TInt msgHandle = aMessage.iHandle;
1.484 + const_cast<TInt&>(aMessage.iHandle) = 0;
1.485 + ASSERT(msgHandle);
1.486 + Exec::TransferSession(msgHandle, sessionServer->Server().Handle());
1.487 + }
1.488 + }
1.489 +
1.490 + ASSERT(aMessage.IsNull());
1.491 + }
1.492 +
1.493 +
1.494 +
1.495 +/**
1.496 +Handles the situation where a call to CServer2::RunL(), leaves.
1.497 +
1.498 +This is the server active object's implementation of the active object
1.499 +framework's RunError() function.
1.500 +
1.501 +In practice, the leave can only be caused by a session's ServiceL() function,
1.502 +which is called from this RunL(); this error is reflected back to that session
1.503 +by calling its ServiceError() function.
1.504 +
1.505 +@param aError The leave code.
1.506 +
1.507 +@return KErrNone.
1.508 +
1.509 +@see CActive::RunL()
1.510 +@see CActive::RunError()
1.511 +@see CSession2::ServiceError()
1.512 +*/
1.513 +EXPORT_C TInt CServer2::RunError(TInt aError)
1.514 + {
1.515 + Message().Session()->ServiceError(Message(),aError);
1.516 + if (!IsActive())
1.517 + ReStart();
1.518 + return KErrNone;
1.519 + }
1.520 +
1.521 +
1.522 +
1.523 +/**
1.524 +Restarts the server.
1.525 +
1.526 +The function issues a request for messages.
1.527 +*/
1.528 +EXPORT_C void CServer2::ReStart()
1.529 + {
1.530 +
1.531 + iServer.Receive(iMessage,iStatus);
1.532 + SetActive();
1.533 + }
1.534 +
1.535 +
1.536 +
1.537 +#ifndef __CSERVER_MACHINE_CODED__
1.538 +/**
1.539 +Handles the receipt of a message.
1.540 +*/
1.541 +EXPORT_C void CServer2::RunL()
1.542 + {
1.543 + TInt fn = Message().Function();
1.544 +
1.545 + if(fn>=0)
1.546 + {
1.547 + // Service the message
1.548 + CSession2* session=Message().Session();
1.549 + if(session)
1.550 + session->ServiceL(Message());
1.551 + else
1.552 + NotConnected(Message());
1.553 + }
1.554 + else if(fn==RMessage2::EConnect)
1.555 + {
1.556 + Connect(Message());
1.557 + }
1.558 + else if(fn==RMessage2::EDisConnect)
1.559 + {
1.560 + Disconnect(Message());
1.561 + }
1.562 + else
1.563 + {
1.564 + BadMessage(Message());
1.565 + }
1.566 + // Queue reception of next message if it hasn't already been done
1.567 + if(!IsActive())
1.568 + ReStart();
1.569 + }
1.570 +
1.571 +#endif
1.572 +
1.573 +
1.574 +
1.575 +void CServer2::Disconnect(const RMessage2& aMessage)
1.576 +//
1.577 +// Process a disconnect message
1.578 +//
1.579 + {
1.580 + CSession2* session=Message().Session();
1.581 + if(!session)
1.582 + {
1.583 + // Session not created yet, so just complete message.
1.584 + aMessage.Complete(0);
1.585 + return;
1.586 + }
1.587 + session->Disconnect(aMessage);
1.588 + }
1.589 +
1.590 +
1.591 +
1.592 +void CServer2::BadMessage(const RMessage2& aMessage)
1.593 + {
1.594 + aMessage.Panic(KServerPanicCategory,EBadMessageNumber);
1.595 + }
1.596 +
1.597 +
1.598 +
1.599 +void CServer2::NotConnected(const RMessage2& aMessage)
1.600 + {
1.601 + aMessage.Panic(KServerPanicCategory,ESessionNotConnected);
1.602 + }
1.603 +
1.604 +
1.605 +
1.606 +/**
1.607 +Extension function
1.608 +
1.609 +
1.610 +*/
1.611 +EXPORT_C TInt CServer2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
1.612 + {
1.613 + return CActive::Extension_(aExtensionId, a0, a1);
1.614 + }