commsfwsupport/commselements/serverden/src/sd_player.cpp
changeset 0 dfb7c4ff071f
child 9 77effd21b2c9
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 2008-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 "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 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <e32base.h>
       
    22 #include <cfshared.h>
       
    23 #include "sd_log.h"
       
    24 #include "sd_roles.h"
       
    25 #include "sd_msgs.h"
       
    26 #include "sd_std.h"
       
    27 #include "sd_errors.h"
       
    28 
       
    29 
       
    30 #ifdef _DEBUG
       
    31 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
       
    32 // (if it could happen through user error then you should give it an explicit, documented, category + code)
       
    33 _LIT(KSpecAssert_ElemSvrDenPlayrC, "ElemSvrDenPlayrC");
       
    34 #endif
       
    35 
       
    36 using namespace Den;
       
    37 using namespace CommsFW;
       
    38 
       
    39 //
       
    40 // CSockSessionProxy
       
    41 //
       
    42 EXPORT_C CCommonSessionProxy::CCommonSessionProxy(CWorkerSession* aSession, CCommonPlayer& aPlayer)
       
    43 :	iSession(aSession),
       
    44 	iPlayer(aPlayer),
       
    45 	iNumSubSessClosing(ELivingSession)
       
    46 	{
       
    47 	//COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CSockSessionProxy %08x:\tCSockSessionProxy(), iSockSession %08x"), this, iSession) );
       
    48 	}
       
    49 
       
    50 EXPORT_C CCommonSessionProxy::~CCommonSessionProxy()
       
    51 	{
       
    52 	//LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\t~CSockSessionProxy(), iSockSession %08x"), this, iSockSession) );
       
    53 	if(iLink.iNext)
       
    54 		{
       
    55 		iLink.Deque();
       
    56 		}
       
    57 	}
       
    58 
       
    59 void CCommonSessionProxy::BeginSessionClose()
       
    60 	{
       
    61 	//COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CSockSessionProxy %08x:\tBeginSessionClose(), iSockSession %08x"), this, iSession) );
       
    62 	/* Only do something if the message is within the deadline and we're sure
       
    63 	   the session pointer is safe to use */
       
    64 	CCommonWorkerThread& worker = iPlayer.WorkerThread();
       
    65 	worker.IncProlongBindingLife();
       
    66 	__ASSERT_DEBUG(!IsClosing(), User::Panic(KSpecAssert_ElemSvrDenPlayrC, 1));
       
    67 	iNumSubSessClosing = 1;	// dummy subsession to prevent premature suicide during this close loop
       
    68 
       
    69 	// The object container is stored as a packed array, so working backwards through it avoids invalidating
       
    70 	// the iterator when removing entries (and as a bonus is more efficient)
       
    71 	CCommonPlayer::TSubSessionContainer& subSessions(iPlayer.SubSessions());
       
    72 	for(TInt i = subSessions.Count() - 1; i >= 0; --i)
       
    73 		{
       
    74 		CWorkerSubSession* subSession = subSessions[i];
       
    75 		if(subSession->Session() == iSession)
       
    76 			{
       
    77 			++iNumSubSessClosing;
       
    78 			if(!subSession->IsClosing())
       
    79 				{
       
    80 				subSession->DeleteMe();
       
    81 				}
       
    82 			}
       
    83 		}
       
    84 
       
    85 	NotifySubSessionDestroyed();	// remove the dummy subsession
       
    86 	}
       
    87 
       
    88 EXPORT_C void CCommonSessionProxy::NotifySubSessionDestroyed()
       
    89 	{
       
    90 	//COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CSockSessionProxy %08x:\tNotifySubSessionDestroyed(), iSockSession %08x"), this, iSession) );
       
    91 	if(IsClosing() && --iNumSubSessClosing <= 0)
       
    92 		{
       
    93 		__ASSERT_DEBUG(iNumSubSessClosing == 0, User::Panic(KSpecAssert_ElemSvrDenPlayrC, 2));
       
    94 		CCommonWorkerThread& worker = iPlayer.WorkerThread();
       
    95 		worker.CompleteSessionClose(iSession);
       
    96 		delete this;
       
    97 		}
       
    98 	}
       
    99 
       
   100 
       
   101 //
       
   102 // CCommonPlayer
       
   103 //
       
   104 
       
   105 /**
       
   106 The Player destructor doesn't have much to do as a lot of the cleanup is done during the
       
   107 normal shutdown routines. Here the Player merely deletes all sub-sessions it owns.
       
   108 */
       
   109 EXPORT_C CCommonPlayer::~CCommonPlayer()
       
   110 	{
       
   111 	// The object container is stored as a packed array, so working backwards through it avoids invalidating
       
   112 	// the iterator when removing entries (and as a bonus is more efficient)
       
   113 	COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CCommonPlayer::~CCommonPlayer()")));
       
   114 
       
   115 	for(TInt i = iSubSessions.Count() - 1; i >= 0; --i)
       
   116 		{
       
   117 		CWorkerSubSession* subSession = iSubSessions[i];
       
   118 		COMMONLOG((WorkerId(),KECommonBootingTag, _L8("-- destroying %08x"), subSession));
       
   119 		subSession->DeleteMe();
       
   120 		}
       
   121 
       
   122 	// Subsessions belong to sessions and get removed when those close. The only time a Player should be going down
       
   123 	// with leftover subsessions is an immediate shutdown, else either a session wasn't destroyed properly or a subsession
       
   124 	// got leaked off it. We do this after the cleanup loop above so the ptrs are helpfully listed
       
   125 	__ASSERT_DEBUG((iSubSessions.Count() == 0 || PitBoss().TestImmediateShutdownPresent()), User::Panic(KSpecAssert_ElemSvrDenPlayrC, 3));
       
   126 
       
   127 	iSubSessions.ResetAndDestroy();
       
   128 	}
       
   129 
       
   130 EXPORT_C CCommonPlayer::CCommonPlayer(CCommonWorkerThread* aOwnerThread, TPlayerRole aPlayerRole)
       
   131 :	iOwnerThread(aOwnerThread),
       
   132 	iPlayerRole(aPlayerRole)
       
   133 	{
       
   134 	COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CCommonPlayer::CCommonPlayer()")));
       
   135 	iSessionProxies.SetOffset(CCommonSessionProxy::GetLinkOffset());
       
   136 	}
       
   137 
       
   138 /**
       
   139 MultiTool function to return the current session proxy for a session, but also to create it
       
   140 if it doesn't exist. This avoids having the same pattern in multiple places where we first check
       
   141 to see if it exists then creates it if not.
       
   142 */
       
   143 EXPORT_C CCommonSessionProxy* CCommonPlayer::CurrentSessionProxyL()
       
   144 	{
       
   145 	if(!iCurrentSessionProxy)
       
   146 		{
       
   147 		iCurrentSessionProxy = FindOrCreateSessionProxyL(Session());
       
   148 		}
       
   149 	return iCurrentSessionProxy;
       
   150 	}
       
   151 
       
   152 CCommonSessionProxy* CCommonPlayer::FindOrCreateSessionProxyL(CWorkerSession* aSession)
       
   153 	{
       
   154 	CCommonSessionProxy* proxy = FindSessionProxy(aSession);
       
   155 	if(proxy==NULL)
       
   156 		{
       
   157 		// No existing proxy; create a new one and append to list
       
   158 		proxy = DoCreateSessionProxyL(aSession);
       
   159 		iSessionProxies.AddLast(*proxy);
       
   160 		}
       
   161 	return proxy;
       
   162 	}
       
   163 
       
   164 CCommonSessionProxy* CCommonPlayer::FindSessionProxy(CWorkerSession* aSession)
       
   165 	{
       
   166 	TDblQueIter<CCommonSessionProxy> iter(iSessionProxies);
       
   167 	CCommonSessionProxy* proxy;
       
   168 	while((proxy = iter++) != NULL)
       
   169 		{
       
   170 		if(proxy->Session() == aSession)
       
   171 			{
       
   172 			break;
       
   173 			}
       
   174 		}
       
   175 	return proxy;
       
   176 	}
       
   177 
       
   178 /**
       
   179 The Player can unbind from another worker thread if it doesn't have any sub-sessions
       
   180 belonging to a session in the peer's Dealer and there are no interface cookies left registered
       
   181 at all
       
   182 */
       
   183 TBool CCommonPlayer::CanUnbindFromWorker(TWorkerId aWorker)
       
   184 	{
       
   185 	COMMONLOG((WorkerId(), KECommonBootingTag, _L8("CCommonPlayer::CanUnbindFromWorker(%d): %d subsess"), aWorker, iSubSessions.Count()));
       
   186 
       
   187 	TInt regItfCount = WorkerThread().Transport()->RegisteredCount();
       
   188 	TInt persistentItfCount = Messages::TlsGlobals::Get().PersistentItfCount();
       
   189 	if(regItfCount > persistentItfCount)
       
   190 		{
       
   191 		COMMONLOG((WorkerId(), KECommonBootingTag, _L8("-- can't; %d interfaces still registered (%d transient)"), regItfCount, regItfCount - persistentItfCount) );
       
   192 		return EFalse;
       
   193 		}
       
   194 
       
   195 	for(TInt idx = iSubSessions.Count() - 1; idx >= 0; --idx)
       
   196 		{
       
   197 		const CWorkerSubSession* ss = iSubSessions[idx];
       
   198 		COMMONLOG((WorkerId(),KECommonBootingTag, _L8("-- subsess %08x worker=%d"), ss, ss->Session()->WorkerId()));
       
   199 		if(ss->Session()->WorkerId() == aWorker)
       
   200 			{
       
   201 			COMMONLOG((WorkerId(),KECommonBootingTag, _L8("-- can't; subsess %08x belongs to this peer"), ss) );
       
   202 			return EFalse;
       
   203 			}
       
   204 		}
       
   205 	return ETrue;
       
   206 	}
       
   207 
       
   208 EXPORT_C void CCommonPlayer::MaybeSetPlayerShutdownComplete(TBool aForceShutdownNow)
       
   209 	{
       
   210 	//A forced shutdown trumps all other considerations
       
   211 	TBool shutdownComplete = aForceShutdownNow || (SubSessions().Count() == 0 && IsPlayerShutdownComplete());
       
   212 
       
   213 	COMMONLOG((WorkerId(), KECommonBootingTag, _L8("CPlayer::MaybeSetPlayerShutdownComplete(), shutdownComplete = %d [forced=%d, #subSess=%d]"),
       
   214 		shutdownComplete, aForceShutdownNow, SubSessions().Count()));
       
   215 
       
   216 	WorkerThread().SetPlayerShutdownComplete(shutdownComplete);
       
   217 	}
       
   218 
       
   219 EXPORT_C CWorkerSubSession* CCommonPlayer::SubSession(const TSubSessionUniqueId& aSubSessionUniqueId) const
       
   220 	{
       
   221 	__ASSERT_DEBUG(aSubSessionUniqueId!=0, User::Panic(KDenFaultPanic, ECommonBadSubSessionUniqueId));
       
   222 	CWorkerSubSession* ss = NULL;
       
   223 	for (TInt i = iSubSessions.Count() - 1; i>=0 && ss==NULL ; i--)
       
   224 		{
       
   225 		if (iSubSessions[i]->UniqueId()==aSubSessionUniqueId)
       
   226 			{
       
   227 			ss = iSubSessions[i];
       
   228 			}
       
   229 		}
       
   230 	return ss;
       
   231 	}
       
   232 
       
   233 EXPORT_C void CCommonPlayer::ProcessMessageL(const RSafeMessage& aMessage, CWorkerSubSession* aSubSession)
       
   234 	{
       
   235 	SetSession(static_cast<CWorkerSession*>(aMessage.Session()));
       
   236 	iCurrentSessionProxy = NULL;
       
   237 	Reset();
       
   238 	iCurrentMessage = &aMessage;
       
   239 
       
   240 	DoProcessMessageL(aMessage,aSubSession);
       
   241 	}
       
   242 
       
   243 /**
       
   244 Panic the client in response to an operation on an existing subsession, after
       
   245 which the request mustn't be completed
       
   246 */
       
   247 void CCommonPlayer::PanicClient(CWorkerSubSession& /*aSubSession*/, TInt aPanic)
       
   248 	{
       
   249 	SafeMessage().PanicClient(KDenFaultPanic, aPanic);
       
   250 	DontCompleteCurrentRequest();
       
   251 	}
       
   252 
       
   253 /**
       
   254 Panic the client in response to an operation on an existing subsession, after
       
   255 which the request mustn't be completed
       
   256 
       
   257 This version allows panic categories to be passed in to support expected legacy
       
   258 behaviour.
       
   259 */
       
   260 void CCommonPlayer::PanicClient(CWorkerSubSession& /*aSubSession*/, const TDesC &aCategory, TInt aPanic)
       
   261 	{
       
   262 	SafeMessage().PanicClient(aCategory, aPanic);
       
   263 	DontCompleteCurrentRequest();
       
   264 	}
       
   265 
       
   266 EXPORT_C void CCommonPlayer::PanicClient(TInt aPanic)
       
   267 	{
       
   268 	SafeMessage().PanicClient(KDenFaultPanic, aPanic);
       
   269 	DontCompleteCurrentRequest();
       
   270 	}
       
   271 
       
   272 EXPORT_C void CCommonPlayer::PanicClient(const TDesC& aCategory, TInt aPanic)
       
   273 	{
       
   274 	SafeMessage().PanicClient(aCategory, aPanic);
       
   275 	DontCompleteCurrentRequest();
       
   276 	}
       
   277 
       
   278 EXPORT_C void CCommonPlayer::DontCompleteCurrentRequest()
       
   279 	{
       
   280 	iComplete=EFalse;
       
   281 	}
       
   282 
       
   283 EXPORT_C TBool CCommonPlayer::ShouldCompleteCurrentRequest() const
       
   284 	{
       
   285 	return iComplete;
       
   286 	}
       
   287 
       
   288 EXPORT_C void CCommonPlayer::SetReturn(TInt aReturn/*, TInt anError, TUid anOwner*/)
       
   289 	{
       
   290 	iReturn=aReturn;
       
   291 
       
   292 	}
       
   293 
       
   294 /**
       
   295 Remove all subsessions belonging to sessions of the nominated worker. No locks required; only the
       
   296 Player accesses the object container.
       
   297 @see TWorkerMsg::ECleanupDeadPeer
       
   298 */
       
   299 EXPORT_C void CCommonPlayer::CleanupDeadWorker(TWorkerId aWorkerId)
       
   300 	{
       
   301 	(void)aWorkerId;
       
   302 	//TBDAA - it's in ss_glob.h ASSERT_HOME_THREAD;
       
   303 
       
   304 	// The object container is stored as a packed array, so working backwards through it avoids invalidating
       
   305 	// the iterator when removing entries (and as a bonus is more efficient)
       
   306 	for(TInt i = iSubSessions.Count() - 1; i >= 0; --i)
       
   307 		{
       
   308 		iSubSessions[i]->CleanupDeadWorker(aWorkerId);
       
   309 		}
       
   310 	}
       
   311 /**
       
   312 If an incoming shutdown request is of type EImmediate, informs the
       
   313 Worker Thread that Player shutdown is complete, otherwise do nothing here.
       
   314 */
       
   315 void CCommonPlayer::ProcessShutdownRequest(TCFShutdownType aType)
       
   316 	{
       
   317 	COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CPlayer::ProcessShutdownRequest(%d)"), aType));
       
   318 	WorkerThread().SetPlayerShutdownComplete(aType == CommsFW::EImmediate);
       
   319 	}
       
   320 
       
   321 /**
       
   322 Walk through all of the subsessions, telling each to complete all blocked requests
       
   323 with KErrServerAbort. We don't attempt to free them - although with a shared
       
   324 heap this could reduce the amount of leakage it seems likely that the more we do
       
   325 with these data structures, the greater the risk that the contagion spreads to
       
   326 other users of the heap. Clients that attempt almost any further operation after KErrAbort
       
   327 will get panicked by the Dealer in the usual bad handle way - this is harsh but fair, and
       
   328 better than simply leaving them hung.
       
   329 */
       
   330 TInt CCommonPlayer::PostMortemCleanup()
       
   331 	{
       
   332 	// No locks are required - we're only here because the owner has died
       
   333 	for(TInt i = 0; i < iSubSessions.Count(); ++i)
       
   334 		{
       
   335 		CWorkerSubSession* subSession = static_cast<CWorkerSubSession*>((iSubSessions[i]));
       
   336 		subSession->FinalCompleteAllBlockedMessages(KErrAbort);
       
   337 		}
       
   338 	return KErrNone;
       
   339 	}
       
   340