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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\euser\cbase\ub_svr.cpp
19 //#define __DEBUG_IMAGE__ 1
20 #if defined(__DEBUG_IMAGE__) && defined (__EPOC32__)
22 #define __IF_DEBUG(t) {RDebug debug;debug.t;}
29 _LIT(KSessionPanicCategory,"CSession");
30 _LIT(KServerPanicCategory,"CServer");
37 This constructor is empty.
39 EXPORT_C CSession2::CSession2()
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.
51 EXPORT_C CSession2::~CSession2()
60 Completes construction of this server-side client session object.
62 The function is called by the server active object, the CServer2 derived
63 class instance, when a client makes a connection request.
65 The connection request results in the creation of this session object,
66 followed by a call to this function.
68 The default implementation is empty.
70 @see CServer2::NewSessionL()
72 EXPORT_C void CSession2::CreateL()
77 Designates the (master or slave) server that is to service this session.
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.
82 It must not be called after CreateL() has finished, as this is the point
83 at which the session binding become irrevocable.
85 @see CServer::DoConnect()
87 EXPORT_C void CSession2::SetServer(const CServer2* aServer)
89 ASSERT(iLink.iNext == NULL);
95 Handles the situation when a call to CSession2::ServiceL(), which services
96 a client request, leaves.
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
104 The default behaviour of this function is to complete the message, using
105 the leave value, if it has not already been completed.
107 Servers can re-implement this as appropriate.
109 @param aMessage The message containing the details of the client request that
111 @param aError The leave code.
114 @see CActive::RunError()
116 EXPORT_C void CSession2::ServiceError(const RMessage2& aMessage,TInt aError)
118 if(!aMessage.IsNull())
119 aMessage.Complete(aError);
125 Called by a server when it receives a disconnect message for the session.
127 This message is sent by the kernel when all client handles to the session have
129 This method deletes the session object and completes the disconnect message.
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
136 @param aMessage The disconnect message.
138 @post 'this' session object has been deleted.
140 EXPORT_C void CSession2::Disconnect(const RMessage2& aMessage)
143 aMessage.Complete(0);
149 Marks the start of resource count checking.
151 It sets up a starting value for resource count checking.
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
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.
162 @see CSession2::CountResources()
163 @see CSession2::ResourceCountMarkEnd()
165 EXPORT_C void CSession2::ResourceCountMarkStart()
167 iResourceCountMark=CountResources();
173 Marks the end of resource count checking.
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)".
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.
184 @param aMessage Represents the details of the client request that is requesting
187 @see CSession2::CountResources()
188 @see CSession2::ResourceCountMarkStart()
190 EXPORT_C void CSession2::ResourceCountMarkEnd(const RMessage2& aMessage)
192 if (iResourceCountMark!=CountResources())
193 aMessage.Panic(KSessionPanicCategory,ESesFoundResCountHeaven);
199 Gets the number of resources currently in use.
201 Derived classes must provide a suitable implementation.
202 The meaning of a resource depends on the design intent of the server.
204 The default implementation panics the calling thread (CSession 1)
205 before returning KErrGeneral.
207 @return The current number of resources in use.
209 @see CSession2::ResourceCountmarkStart()
210 @see CSession2::ResourceCountmarkEnd()
212 EXPORT_C TInt CSession2::CountResources()
214 User::Panic(KSessionPanicCategory,ESesCountResourcesNotImplemented);
225 EXPORT_C TInt CSession2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
227 return CBase::Extension_(aExtensionId, a0, a1);
234 Constructs the server object, specifying the server type and the active
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.
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.
246 EXPORT_C CServer2::CServer2(TInt aPriority, TServerType aType)
247 : CActive(aPriority),
248 iSessionType((TUint8)aType),
249 iSessionQ(_FOFF(CSession2,iLink)),
250 iSessionIter(iSessionQ)
252 ASSERT(iSessionType == aType);
253 __ASSERT_COMPILE(EServerRole_Default == 0);
254 __ASSERT_COMPILE(EServerOpt_PinClientDescriptorsDefault == 0);
260 Frees resources prior to destruction.
262 Specifically, it cancels any outstanding request for messages, and
263 deletes all server-side client session objects.
265 EXPORT_C CServer2::~CServer2()
268 while (!iSessionQ.IsEmpty())
270 CSession2 *pS=iSessionQ.First();
280 Sets whether the kernel will pin descriptors passed to this server in the context of the client
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.
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.
293 This method must be called prior to starting the server by calling the Start() method.
295 @param aPin Set to ETrue for the server to pin its client's descriptors, set to
297 @panic E32USER-CBase 106 When this method is invoked after the server has been started.
298 @see CServer2::Start()
302 EXPORT_C void CServer2::SetPinClientDescriptors(TBool aPin)
304 if (iServer.Handle() != KNullHandle)
305 {// Server already started so too late to make it a pinning one.
306 Panic(ECServer2InvalidSetPin);
308 iServerOpts &= ~EServerOpt_PinClientDescriptorsMask;
310 iServerOpts |= EServerOpt_PinClientDescriptorsEnable;
312 iServerOpts |= EServerOpt_PinClientDescriptorsDisable;
316 Assigns a role (master or slave) for this server.
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.
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.
326 @panic E32USER-CBase-? When this method is invoked after the server has been started.
327 @see CServer2::Start()
331 EXPORT_C void CServer2::SetMaster(const CServer2* aServer)
333 // Roles can only be assigned before the call to Start()
334 ASSERT(Server().Handle() == KNullHandle);
337 iServerRole = EServerRole_Standalone;
338 else if (aServer == this)
339 iServerRole = EServerRole_Master;
341 iServerRole = EServerRole_Slave;
346 Adds the server with the specified name to the active scheduler,
347 and issues the first request for messages.
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.
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.
357 @capability ProtServ if aName starts with a '!' character
359 EXPORT_C TInt CServer2::Start(const TDesC& aName)
361 TInt r = iServer.CreateGlobal(aName, iSessionType, iServerRole, iServerOpts);
364 CActiveScheduler::Add(this);
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.
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.
380 @param aName The name of the server.
381 KNullDesC, to create anonymous servers.
382 @capability ProtServ if aName starts with a '!' character
384 EXPORT_C void CServer2::StartL(const TDesC& aName)
386 User::LeaveIfError(Start(aName));
392 Implements the cancellation of any outstanding request for messages.
394 EXPORT_C void CServer2::DoCancel()
402 void CServer2::Connect(const RMessage2& aMessage)
404 // Handle a connect request. Ptr0()==Version.
405 // NOTE: We don't want this to leave as that may kill the server
409 if (aMessage.Session())
411 aMessage.Panic(KServerPanicCategory,ESessionAlreadyConnected);
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
424 void CServer2::DoConnectL(const RMessage2& aMessage,CSession2* volatile& aSession)
427 *(TInt*)&v = aMessage.Int0();
428 aSession = NewSessionL(v, aMessage);
429 if (!aSession->iServer)
430 aSession->iServer = this;
432 iSessionQ.AddLast(*aSession);
433 Exec::SetSessionPtr(aMessage.Handle(), aSession);
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.
442 @param aMessage The Connect message sent by the client requesting the
443 connection. aMessage.Ptr0() is the required Version.
445 EXPORT_C void CServer2::DoConnect(const RMessage2& aMessage)
447 ASSERT(aMessage.Function() == RMessage2::EConnect);
448 ASSERT(aMessage.Session() == NULL);
449 ASSERT(!aMessage.IsNull());
451 CSession2* newSession = NULL;
452 TRAPD(err, DoConnectL(aMessage, newSession));
457 aMessage.Complete(err);
461 ASSERT(newSession != NULL);
462 CServer2* sessionServer = const_cast<CServer2*>(newSession->Server());
463 ASSERT(sessionServer != NULL);
465 // The return value of Server() will be 'this', unless it was
466 // changed by a call to SetServer().
467 if (sessionServer == this)
469 // no SetServer() call, so just complete the Connect message
470 aMessage.Complete(err);
474 // Transfer the new Csession to the specified slave Cserver
475 newSession->iLink.Deque();
476 sessionServer->iSessionQ.AddLast(*newSession);
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;
483 Exec::TransferSession(msgHandle, sessionServer->Server().Handle());
487 ASSERT(aMessage.IsNull());
493 Handles the situation where a call to CServer2::RunL(), leaves.
495 This is the server active object's implementation of the active object
496 framework's RunError() function.
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.
502 @param aError The leave code.
507 @see CActive::RunError()
508 @see CSession2::ServiceError()
510 EXPORT_C TInt CServer2::RunError(TInt aError)
512 Message().Session()->ServiceError(Message(),aError);
523 The function issues a request for messages.
525 EXPORT_C void CServer2::ReStart()
528 iServer.Receive(iMessage,iStatus);
534 #ifndef __CSERVER_MACHINE_CODED__
536 Handles the receipt of a message.
538 EXPORT_C void CServer2::RunL()
540 TInt fn = Message().Function();
544 // Service the message
545 CSession2* session=Message().Session();
547 session->ServiceL(Message());
549 NotConnected(Message());
551 else if(fn==RMessage2::EConnect)
555 else if(fn==RMessage2::EDisConnect)
557 Disconnect(Message());
561 BadMessage(Message());
563 // Queue reception of next message if it hasn't already been done
572 void CServer2::Disconnect(const RMessage2& aMessage)
574 // Process a disconnect message
577 CSession2* session=Message().Session();
580 // Session not created yet, so just complete message.
581 aMessage.Complete(0);
584 session->Disconnect(aMessage);
589 void CServer2::BadMessage(const RMessage2& aMessage)
591 aMessage.Panic(KServerPanicCategory,EBadMessageNumber);
596 void CServer2::NotConnected(const RMessage2& aMessage)
598 aMessage.Panic(KServerPanicCategory,ESessionNotConnected);
608 EXPORT_C TInt CServer2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
610 return CActive::Extension_(aExtensionId, a0, a1);