os/kernelhwsrv/kernel/eka/euser/cbase/ub_svr.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\euser\cbase\ub_svr.cpp
    15 // 
    16 //
    17 
    18 #include "ub_std.h"
    19 //#define __DEBUG_IMAGE__ 1
    20 #if defined(__DEBUG_IMAGE__) && defined (__EPOC32__)
    21 #include "e32svr.h" 
    22 #define __IF_DEBUG(t) {RDebug debug;debug.t;}
    23 #else
    24 #define __IF_DEBUG(t)
    25 #endif
    26 
    27 
    28 
    29 _LIT(KSessionPanicCategory,"CSession");
    30 _LIT(KServerPanicCategory,"CServer");
    31 
    32 
    33 
    34 /**
    35 Default constructor.
    36 
    37 This constructor is empty.
    38 */
    39 EXPORT_C CSession2::CSession2()
    40 	{}
    41 
    42 
    43 
    44 /**
    45 Destructor.
    46 
    47 It frees resources prior to destruction of the object.
    48 Specifically, it removes this session object from the server
    49 active object’s list of sessions.
    50 */
    51 EXPORT_C CSession2::~CSession2()
    52 	{
    53 	if (iLink.iNext)
    54 		iLink.Deque();
    55 	}
    56 
    57 
    58 
    59 /**
    60 Completes construction of this server-side client session object.
    61 
    62 The function is called by the server active object, the CServer2 derived
    63 class instance, when a client makes a connection request.
    64 
    65 The connection request results in the creation of this session object,
    66 followed by a call to this function.
    67 
    68 The default implementation is empty.
    69 
    70 @see CServer2::NewSessionL()
    71 */
    72 EXPORT_C void CSession2::CreateL()
    73 	{
    74 	}
    75 
    76 /**
    77 Designates the (master or slave) server that is to service this session.
    78 
    79 This may be called from the NewSessionL() method of the CServer2-derived
    80 class or from the CreateL() method of the CSession2-derived class.
    81 
    82 It must not be called after CreateL() has finished, as this is the point
    83 at which the session binding become irrevocable.
    84 
    85 @see CServer::DoConnect()
    86 */
    87 EXPORT_C void CSession2::SetServer(const CServer2* aServer)
    88 	{
    89 	ASSERT(iLink.iNext == NULL);
    90 	ASSERT(aServer);
    91 	iServer = aServer;
    92 	}
    93 
    94 /**
    95 Handles the situation when a call to CSession2::ServiceL(), which services
    96 a client request, leaves.
    97 
    98 Servers are active objects, and the call to CSession2::ServiceL() to handle
    99 a client request is executed as part of the server's active object RunL()
   100 function. If the RunL() leaves, the active object framework calls the active
   101 object's RunError() function. The server framework implements this as a call
   102 to ServiceError()
   103 
   104 The default behaviour of this function is to complete the message, using
   105 the leave value, if it has not already been completed.
   106 
   107 Servers can re-implement this as appropriate.
   108 
   109 @param aMessage The message containing the details of the client request that
   110                 caused the leave.
   111 @param aError   The leave code.
   112 
   113 @see CActive::RunL()
   114 @see CActive::RunError()
   115 */
   116 EXPORT_C void CSession2::ServiceError(const RMessage2& aMessage,TInt aError)
   117 	{
   118 	if(!aMessage.IsNull())
   119 		aMessage.Complete(aError);
   120 	}
   121 
   122 
   123 
   124 /**
   125 Called by a server when it receives a disconnect message for the session.
   126 	
   127 This message is sent by the kernel when all client handles to the session have
   128 been closed.
   129 This method deletes the session object and completes the disconnect message.
   130 
   131 A derived session implementation may overide this virtual method if it needs to
   132 perform any asynchronous cleanup actions, these actions must end with a call to the
   133 base class implementation of this method, which will delete the session object
   134 and complete the disconnect message
   135 
   136 @param aMessage The disconnect message.
   137 
   138 @post 'this' session object has been deleted.
   139 */
   140 EXPORT_C void CSession2::Disconnect(const RMessage2& aMessage)
   141 	{
   142 	delete this;
   143 	aMessage.Complete(0);
   144 	}
   145 
   146 
   147 
   148 /**
   149 Marks the start of resource count checking.
   150 
   151 It sets up a starting value for resource count checking.
   152 
   153 The function sets up a starting value for resource count checking by using
   154 the value returned by a call to CSession2::CountResources(), and is the value
   155 that will be used for comparison if CSession2::ResourceCountMarkEnd() is called
   156 at some later time.
   157 
   158 The client/server framework does not call this function (nor
   159 does it call CSession2::ResourceCountMarkEnd()), but is available for servers
   160 to use, if appropriate.
   161 
   162 @see CSession2::CountResources()
   163 @see CSession2::ResourceCountMarkEnd()
   164 */
   165 EXPORT_C void CSession2::ResourceCountMarkStart()
   166 	{
   167 	iResourceCountMark=CountResources();
   168 	}
   169 
   170 
   171 
   172 /**
   173 Marks the end of resource count checking.
   174 
   175 The function takes the current resource count by
   176 calling CSession2::CountResources(), and compares it with the resource count
   177 value saved when CSession2::ResourceCountMarkStart() was called.
   178 If the resource counts differ, then the client thread is panicked (CSession 2)".
   179 
   180 The client/server framework does not call this function (nor does it call 
   181 CSession2::ResourceCountMarkStart()), but the function is available for
   182 servers to use, if appropriate.
   183 
   184 @param aMessage Represents the details of the client request that is requesting
   185                 this resource check.
   186 
   187 @see CSession2::CountResources()
   188 @see CSession2::ResourceCountMarkStart()
   189 */
   190 EXPORT_C void CSession2::ResourceCountMarkEnd(const RMessage2& aMessage)
   191 	{
   192 	if (iResourceCountMark!=CountResources())
   193 		aMessage.Panic(KSessionPanicCategory,ESesFoundResCountHeaven);
   194 	}
   195 
   196 
   197 
   198 /**
   199 Gets the number of resources currently in use.
   200 
   201 Derived classes must provide a suitable implementation.
   202 The meaning of a resource depends on the design intent of the server.
   203 
   204 The default implementation panics the calling thread (CSession 1)
   205 before returning KErrGeneral.
   206 
   207 @return The current number of resources in use.
   208 
   209 @see CSession2::ResourceCountmarkStart()
   210 @see CSession2::ResourceCountmarkEnd()
   211 */
   212 EXPORT_C TInt CSession2::CountResources()
   213 	{
   214 	User::Panic(KSessionPanicCategory,ESesCountResourcesNotImplemented);
   215 	return KErrGeneral;
   216 	}
   217 
   218 
   219 
   220 /**
   221 Extension function
   222 
   223 
   224 */
   225 EXPORT_C TInt CSession2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
   226 	{
   227 	return CBase::Extension_(aExtensionId, a0, a1);
   228 	}
   229 
   230 
   231 
   232 
   233 /**
   234 Constructs the server object, specifying the server type and the active
   235 object priority.
   236 
   237 Derived classes must define and implement a constructor through which
   238 the priority can be specified. A typical implementation calls this server
   239 base class constructor through a constructor initialization list.
   240 
   241 @param aPriority The priority of this active object.
   242 @param aType     Indicates the type of session that the server creates.
   243                  If not explicitly stated, then the server creates
   244                  a session that is not sharable with other threads.
   245 */
   246 EXPORT_C CServer2::CServer2(TInt aPriority, TServerType aType)
   247 	:	CActive(aPriority),
   248 		iSessionType((TUint8)aType),
   249 		iSessionQ(_FOFF(CSession2,iLink)),
   250 		iSessionIter(iSessionQ)
   251 	{
   252 	ASSERT(iSessionType == aType);
   253 	__ASSERT_COMPILE(EServerRole_Default == 0);
   254 	__ASSERT_COMPILE(EServerOpt_PinClientDescriptorsDefault == 0);
   255 	}
   256 
   257 
   258 
   259 /**
   260 Frees resources prior to destruction.
   261 
   262 Specifically, it cancels any outstanding request for messages, and 
   263 deletes all server-side client session objects.
   264 */
   265 EXPORT_C CServer2::~CServer2()
   266 	{
   267 	Cancel();
   268 	while (!iSessionQ.IsEmpty())
   269 		{
   270 		CSession2 *pS=iSessionQ.First();
   271 		pS->iLink.Deque();
   272 		pS->iLink.iNext=0;
   273 		delete pS;
   274 		}
   275 	iServer.Close();
   276 	}
   277 
   278 
   279 /**
   280 Sets whether the kernel will pin descriptors passed to this server in the context of the client
   281 thread.
   282 
   283 Setting this is one way of ensuring that the server will not take page faults when accessing client
   284 descriptors, which would otherwise happen if the data was paged out.
   285 
   286 This method overrides the default pinning policy of the server which is for the server 
   287 to pin its client's descriptors if the process creating the server is not data paged.
   288 I.e. if CServer2::SetPinClientDescriptors() is not invoked on the server and 
   289 RProcess::DefaultDataPaged() of the process creating the server returns EFalse, 
   290 the server will pin its client's descriptors, otherwise the server will not pin its
   291 client's descriptors.
   292 
   293 This method must be called prior to starting the server by calling the Start() method.
   294 
   295 @param aPin	Set to ETrue for the server to pin its client's descriptors, set to 
   296 			EFalse otherwise.
   297 @panic E32USER-CBase 106 When this method is invoked after the server has been started.
   298 @see CServer2::Start()
   299 
   300 @prototype
   301 */
   302 EXPORT_C void CServer2::SetPinClientDescriptors(TBool aPin)
   303 	{
   304 	if (iServer.Handle() != KNullHandle)
   305 		{// Server already started so too late to make it a pinning one.
   306 		Panic(ECServer2InvalidSetPin);
   307 		}
   308 	iServerOpts &= ~EServerOpt_PinClientDescriptorsMask;
   309 	if (aPin)
   310 		iServerOpts |= EServerOpt_PinClientDescriptorsEnable;
   311 	else
   312 		iServerOpts |= EServerOpt_PinClientDescriptorsDisable;
   313 	}
   314 
   315 /**
   316 Assigns a role (master or slave) for this server.
   317 
   318 The master server is typically named, and receives all Connect messages
   319 from clients. It can hand off some sessions to be processed by one or
   320 more anonymous slave servers, each running in a separate thread.
   321 
   322 Both master and slave servers must call this function before calling
   323 Start(), in order to define their roles.  Once the server is started,
   324 its role cannot be changed.
   325 
   326 @panic E32USER-CBase-? When this method is invoked after the server has been started.
   327 @see CServer2::Start()
   328 
   329 @prototype
   330 */
   331 EXPORT_C void CServer2::SetMaster(const CServer2* aServer)
   332 	{
   333 	// Roles can only be assigned before the call to Start()
   334 	ASSERT(Server().Handle() == KNullHandle);
   335 
   336 	if (aServer == NULL)
   337 		iServerRole = EServerRole_Standalone;
   338 	else if (aServer == this)
   339 		iServerRole = EServerRole_Master;
   340 	else
   341 		iServerRole = EServerRole_Slave;
   342 	}
   343 
   344 
   345 /**
   346 Adds the server with the specified name to the active scheduler,
   347 and issues the first request for messages.
   348 
   349 If KNullDesC is specified for the name, then an anonymous server will be created.
   350 To create a session to such a server, an overload of RSessionBase::CreateSession()
   351 which takes RServer2 object as a parameter can be used.
   352 
   353 @param aName The name of the server.
   354              KNullDesC, to create anonymous servers.
   355 @return KErrNone, if successful, otherwise one of the other system wide error codes.
   356 
   357 @capability ProtServ if aName starts with a '!' character
   358 */
   359 EXPORT_C TInt CServer2::Start(const TDesC& aName)
   360 	{
   361 	TInt r = iServer.CreateGlobal(aName, iSessionType, iServerRole, iServerOpts);
   362 	if (r == KErrNone)
   363 		{
   364 		CActiveScheduler::Add(this);
   365 		ReStart();
   366 		}
   367 	return r;
   368 	}
   369 
   370 
   371 	
   372 /**
   373 Adds the server with the specified name to the active scheduler,
   374 and issues the first request for messages, and leaves if the operation fails.
   375 
   376 If KNullDesC is specified for the name, then an anonymous server will be created.
   377 To create a session to such a server, the overload of RSessionBase::CreateSession() 
   378 which takes an RServer2 object as a parameter can be used.
   379 
   380 @param aName The name of the server.
   381              KNullDesC, to create anonymous servers.
   382 @capability  ProtServ if aName starts with a '!' character
   383 */
   384 EXPORT_C void CServer2::StartL(const TDesC& aName)
   385 	{
   386 	User::LeaveIfError(Start(aName));
   387 	}
   388 
   389 
   390 
   391 /**
   392 Implements the cancellation of any outstanding request for messages.
   393 */
   394 EXPORT_C void CServer2::DoCancel()
   395 	{
   396 
   397 	iServer.Cancel();
   398 	}
   399 
   400 
   401 
   402 void CServer2::Connect(const RMessage2& aMessage)
   403 //
   404 // Handle a connect request. Ptr0()==Version.
   405 // NOTE: We don't want this to leave as that may kill the server
   406 //
   407 	{
   408 
   409 	if (aMessage.Session())
   410 		{
   411 		aMessage.Panic(KServerPanicCategory,ESessionAlreadyConnected);
   412 		return;
   413 		}
   414 	DoConnect(aMessage);
   415 	}
   416 
   417 
   418 
   419 //
   420 //This is all of the Leaving code for connection creation.
   421 //This is in a seperate function in an effort to force compilers to store aSession
   422 //on the stack which enables cleanup to perform correctly when a Leave occurs
   423 //
   424 void CServer2::DoConnectL(const RMessage2& aMessage,CSession2* volatile& aSession)
   425 	{
   426 	TVersion v;
   427 	*(TInt*)&v = aMessage.Int0();
   428 	aSession = NewSessionL(v, aMessage);
   429 	if (!aSession->iServer)
   430 		aSession->iServer = this;
   431 	aSession->CreateL();
   432 	iSessionQ.AddLast(*aSession);
   433 	Exec::SetSessionPtr(aMessage.Handle(), aSession);
   434 	}
   435 
   436 
   437 
   438 /**
   439 Handles the connect request from the client.  We trap Leaves, to ensure
   440 that existing sessions aren't affected by failure to create a new one.
   441 
   442 @param aMessage The Connect message sent by the client requesting the
   443                 connection. aMessage.Ptr0() is the required Version.
   444 */
   445 EXPORT_C void CServer2::DoConnect(const RMessage2& aMessage)
   446 	{
   447 	ASSERT(aMessage.Function() == RMessage2::EConnect);
   448 	ASSERT(aMessage.Session() == NULL);
   449 	ASSERT(!aMessage.IsNull());
   450 
   451 	CSession2* newSession = NULL;
   452 	TRAPD(err, DoConnectL(aMessage, newSession));
   453 	if (err != KErrNone)
   454 		{
   455 		// Connect failed
   456 		delete newSession;
   457 		aMessage.Complete(err);
   458 		}
   459 	else
   460 		{
   461 		ASSERT(newSession != NULL);
   462 		CServer2* sessionServer = const_cast<CServer2*>(newSession->Server());
   463 		ASSERT(sessionServer != NULL);
   464 
   465 		// The return value of Server() will be 'this', unless it was
   466 		// changed by a call to SetServer().
   467 		if (sessionServer == this)
   468 			{
   469 			// no SetServer() call, so just complete the Connect message
   470 			aMessage.Complete(err);
   471 			}
   472 		else
   473 			{
   474 			// Transfer the new Csession to the specified slave Cserver
   475 			newSession->iLink.Deque();
   476 			sessionServer->iSessionQ.AddLast(*newSession);
   477 
   478 			// Ask the kernel to transfer the DSession to the slave DServer.
   479 			// Note: this Exec call also completes the Connect message.
   480 			TInt msgHandle = aMessage.iHandle;
   481 			const_cast<TInt&>(aMessage.iHandle) = 0;
   482 			ASSERT(msgHandle);
   483 			Exec::TransferSession(msgHandle, sessionServer->Server().Handle());
   484 			}
   485 		}
   486 
   487 	ASSERT(aMessage.IsNull());
   488 	}
   489 
   490 
   491 
   492 /**
   493 Handles the situation where a call to CServer2::RunL(), leaves.
   494 
   495 This is the server active object's implementation of the active object
   496 framework's RunError() function.
   497 
   498 In practice, the leave can only be caused by a session's ServiceL() function,
   499 which is called from this RunL(); this error is reflected back to that session
   500 by calling its ServiceError() function.
   501 
   502 @param aError The leave code.
   503 
   504 @return KErrNone.
   505 
   506 @see CActive::RunL()
   507 @see CActive::RunError()
   508 @see CSession2::ServiceError()
   509 */
   510 EXPORT_C TInt CServer2::RunError(TInt aError)
   511 	{
   512 	Message().Session()->ServiceError(Message(),aError);
   513 	if (!IsActive())
   514 		ReStart();
   515 	return KErrNone;
   516 	}
   517 
   518 
   519 
   520 /**
   521 Restarts the server.
   522 
   523 The function issues a request for messages.
   524 */
   525 EXPORT_C void CServer2::ReStart()
   526 	{
   527 
   528 	iServer.Receive(iMessage,iStatus);
   529 	SetActive();
   530 	}
   531 
   532 
   533 
   534 #ifndef __CSERVER_MACHINE_CODED__
   535 /**
   536 Handles the receipt of a message.
   537 */
   538 EXPORT_C void CServer2::RunL()
   539 	{
   540 	TInt fn = Message().Function();
   541 
   542 	if(fn>=0)
   543 		{
   544 		// Service the message
   545 		CSession2* session=Message().Session();
   546 		if(session)
   547 			session->ServiceL(Message());
   548 		else
   549 			NotConnected(Message());
   550 		}
   551 	else if(fn==RMessage2::EConnect)
   552 		{
   553 		Connect(Message());
   554 		}
   555 	else if(fn==RMessage2::EDisConnect)
   556 		{
   557 		Disconnect(Message());
   558 		}
   559 	else
   560 		{
   561 		BadMessage(Message());
   562 		}
   563 	// Queue reception of next message if it hasn't already been done
   564 	if(!IsActive())
   565 		ReStart();
   566 	}
   567 
   568 #endif
   569 
   570 
   571 
   572 void CServer2::Disconnect(const RMessage2& aMessage)
   573 //
   574 // Process a disconnect message
   575 //
   576 	{
   577 	CSession2* session=Message().Session();
   578 	if(!session)
   579 		{
   580 		// Session not created yet, so just complete message.
   581 		aMessage.Complete(0);
   582 		return;
   583 		}
   584 	session->Disconnect(aMessage);
   585 	}
   586 
   587 
   588 
   589 void CServer2::BadMessage(const RMessage2& aMessage)
   590 	{
   591 	aMessage.Panic(KServerPanicCategory,EBadMessageNumber);
   592 	}
   593 
   594 
   595 
   596 void CServer2::NotConnected(const RMessage2& aMessage)
   597 	{
   598 	aMessage.Panic(KServerPanicCategory,ESessionNotConnected);
   599 	}
   600 
   601 	
   602 
   603 /**
   604 Extension function
   605 
   606 
   607 */
   608 EXPORT_C TInt CServer2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
   609 	{
   610 	return CActive::Extension_(aExtensionId, a0, a1);
   611 	}