--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwsupport/commselements/serverden/src/sd_player.cpp Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,340 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <e32base.h>
+#include <cfshared.h>
+#include "sd_log.h"
+#include "sd_roles.h"
+#include "sd_msgs.h"
+#include "sd_std.h"
+#include "sd_errors.h"
+
+
+#ifdef _DEBUG
+// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
+// (if it could happen through user error then you should give it an explicit, documented, category + code)
+_LIT(KSpecAssert_ElemSvrDenPlayrC, "ElemSvrDenPlayrC");
+#endif
+
+using namespace Den;
+using namespace CommsFW;
+
+//
+// CSockSessionProxy
+//
+EXPORT_C CCommonSessionProxy::CCommonSessionProxy(CWorkerSession* aSession, CCommonPlayer& aPlayer)
+: iSession(aSession),
+ iPlayer(aPlayer),
+ iNumSubSessClosing(ELivingSession)
+ {
+ //COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CSockSessionProxy %08x:\tCSockSessionProxy(), iSockSession %08x"), this, iSession) );
+ }
+
+EXPORT_C CCommonSessionProxy::~CCommonSessionProxy()
+ {
+ //LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\t~CSockSessionProxy(), iSockSession %08x"), this, iSockSession) );
+ if(iLink.iNext)
+ {
+ iLink.Deque();
+ }
+ }
+
+void CCommonSessionProxy::BeginSessionClose()
+ {
+ //COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CSockSessionProxy %08x:\tBeginSessionClose(), iSockSession %08x"), this, iSession) );
+ /* Only do something if the message is within the deadline and we're sure
+ the session pointer is safe to use */
+ CCommonWorkerThread& worker = iPlayer.WorkerThread();
+ worker.IncProlongBindingLife();
+ __ASSERT_DEBUG(!IsClosing(), User::Panic(KSpecAssert_ElemSvrDenPlayrC, 1));
+ iNumSubSessClosing = 1; // dummy subsession to prevent premature suicide during this close loop
+
+ // The object container is stored as a packed array, so working backwards through it avoids invalidating
+ // the iterator when removing entries (and as a bonus is more efficient)
+ CCommonPlayer::TSubSessionContainer& subSessions(iPlayer.SubSessions());
+ for(TInt i = subSessions.Count() - 1; i >= 0; --i)
+ {
+ CWorkerSubSession* subSession = subSessions[i];
+ if(subSession->Session() == iSession)
+ {
+ ++iNumSubSessClosing;
+ if(!subSession->IsClosing())
+ {
+ subSession->DeleteMe();
+ }
+ }
+ }
+
+ NotifySubSessionDestroyed(); // remove the dummy subsession
+ }
+
+EXPORT_C void CCommonSessionProxy::NotifySubSessionDestroyed()
+ {
+ //COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CSockSessionProxy %08x:\tNotifySubSessionDestroyed(), iSockSession %08x"), this, iSession) );
+ if(IsClosing() && --iNumSubSessClosing <= 0)
+ {
+ __ASSERT_DEBUG(iNumSubSessClosing == 0, User::Panic(KSpecAssert_ElemSvrDenPlayrC, 2));
+ CCommonWorkerThread& worker = iPlayer.WorkerThread();
+ worker.CompleteSessionClose(iSession);
+ delete this;
+ }
+ }
+
+
+//
+// CCommonPlayer
+//
+
+/**
+The Player destructor doesn't have much to do as a lot of the cleanup is done during the
+normal shutdown routines. Here the Player merely deletes all sub-sessions it owns.
+*/
+EXPORT_C CCommonPlayer::~CCommonPlayer()
+ {
+ // The object container is stored as a packed array, so working backwards through it avoids invalidating
+ // the iterator when removing entries (and as a bonus is more efficient)
+ COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CCommonPlayer::~CCommonPlayer()")));
+
+ for(TInt i = iSubSessions.Count() - 1; i >= 0; --i)
+ {
+ CWorkerSubSession* subSession = iSubSessions[i];
+ COMMONLOG((WorkerId(),KECommonBootingTag, _L8("-- destroying %08x"), subSession));
+ subSession->DeleteMe();
+ }
+
+ // Subsessions belong to sessions and get removed when those close. The only time a Player should be going down
+ // with leftover subsessions is an immediate shutdown, else either a session wasn't destroyed properly or a subsession
+ // got leaked off it. We do this after the cleanup loop above so the ptrs are helpfully listed
+ __ASSERT_DEBUG((iSubSessions.Count() == 0 || PitBoss().TestImmediateShutdownPresent()), User::Panic(KSpecAssert_ElemSvrDenPlayrC, 3));
+
+ iSubSessions.ResetAndDestroy();
+ }
+
+EXPORT_C CCommonPlayer::CCommonPlayer(CCommonWorkerThread* aOwnerThread, TPlayerRole aPlayerRole)
+: iOwnerThread(aOwnerThread),
+ iPlayerRole(aPlayerRole)
+ {
+ COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CCommonPlayer::CCommonPlayer()")));
+ iSessionProxies.SetOffset(CCommonSessionProxy::GetLinkOffset());
+ }
+
+/**
+MultiTool function to return the current session proxy for a session, but also to create it
+if it doesn't exist. This avoids having the same pattern in multiple places where we first check
+to see if it exists then creates it if not.
+*/
+EXPORT_C CCommonSessionProxy* CCommonPlayer::CurrentSessionProxyL()
+ {
+ if(!iCurrentSessionProxy)
+ {
+ iCurrentSessionProxy = FindOrCreateSessionProxyL(Session());
+ }
+ return iCurrentSessionProxy;
+ }
+
+CCommonSessionProxy* CCommonPlayer::FindOrCreateSessionProxyL(CWorkerSession* aSession)
+ {
+ CCommonSessionProxy* proxy = FindSessionProxy(aSession);
+ if(proxy==NULL)
+ {
+ // No existing proxy; create a new one and append to list
+ proxy = DoCreateSessionProxyL(aSession);
+ iSessionProxies.AddLast(*proxy);
+ }
+ return proxy;
+ }
+
+CCommonSessionProxy* CCommonPlayer::FindSessionProxy(CWorkerSession* aSession)
+ {
+ TDblQueIter<CCommonSessionProxy> iter(iSessionProxies);
+ CCommonSessionProxy* proxy;
+ while((proxy = iter++) != NULL)
+ {
+ if(proxy->Session() == aSession)
+ {
+ break;
+ }
+ }
+ return proxy;
+ }
+
+/**
+The Player can unbind from another worker thread if it doesn't have any sub-sessions
+belonging to a session in the peer's Dealer and there are no interface cookies left registered
+at all
+*/
+TBool CCommonPlayer::CanUnbindFromWorker(TWorkerId aWorker)
+ {
+ COMMONLOG((WorkerId(), KECommonBootingTag, _L8("CCommonPlayer::CanUnbindFromWorker(%d): %d subsess"), aWorker, iSubSessions.Count()));
+
+ TInt regItfCount = WorkerThread().Transport()->RegisteredCount();
+ TInt persistentItfCount = Messages::TlsGlobals::Get().PersistentItfCount();
+ if(regItfCount > persistentItfCount)
+ {
+ COMMONLOG((WorkerId(), KECommonBootingTag, _L8("-- can't; %d interfaces still registered (%d transient)"), regItfCount, regItfCount - persistentItfCount) );
+ return EFalse;
+ }
+
+ for(TInt idx = iSubSessions.Count() - 1; idx >= 0; --idx)
+ {
+ const CWorkerSubSession* ss = iSubSessions[idx];
+ COMMONLOG((WorkerId(),KECommonBootingTag, _L8("-- subsess %08x worker=%d"), ss, ss->Session()->WorkerId()));
+ if(ss->Session()->WorkerId() == aWorker)
+ {
+ COMMONLOG((WorkerId(),KECommonBootingTag, _L8("-- can't; subsess %08x belongs to this peer"), ss) );
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+
+EXPORT_C void CCommonPlayer::MaybeSetPlayerShutdownComplete(TBool aForceShutdownNow)
+ {
+ //A forced shutdown trumps all other considerations
+ TBool shutdownComplete = aForceShutdownNow || (SubSessions().Count() == 0 && IsPlayerShutdownComplete());
+
+ COMMONLOG((WorkerId(), KECommonBootingTag, _L8("CPlayer::MaybeSetPlayerShutdownComplete(), shutdownComplete = %d [forced=%d, #subSess=%d]"),
+ shutdownComplete, aForceShutdownNow, SubSessions().Count()));
+
+ WorkerThread().SetPlayerShutdownComplete(shutdownComplete);
+ }
+
+EXPORT_C CWorkerSubSession* CCommonPlayer::SubSession(const TSubSessionUniqueId& aSubSessionUniqueId) const
+ {
+ __ASSERT_DEBUG(aSubSessionUniqueId!=0, User::Panic(KDenFaultPanic, ECommonBadSubSessionUniqueId));
+ CWorkerSubSession* ss = NULL;
+ for (TInt i = iSubSessions.Count() - 1; i>=0 && ss==NULL ; i--)
+ {
+ if (iSubSessions[i]->UniqueId()==aSubSessionUniqueId)
+ {
+ ss = iSubSessions[i];
+ }
+ }
+ return ss;
+ }
+
+EXPORT_C void CCommonPlayer::ProcessMessageL(const RSafeMessage& aMessage, CWorkerSubSession* aSubSession)
+ {
+ SetSession(static_cast<CWorkerSession*>(aMessage.Session()));
+ iCurrentSessionProxy = NULL;
+ Reset();
+ iCurrentMessage = &aMessage;
+
+ DoProcessMessageL(aMessage,aSubSession);
+ }
+
+/**
+Panic the client in response to an operation on an existing subsession, after
+which the request mustn't be completed
+*/
+void CCommonPlayer::PanicClient(CWorkerSubSession& /*aSubSession*/, TInt aPanic)
+ {
+ SafeMessage().PanicClient(KDenFaultPanic, aPanic);
+ DontCompleteCurrentRequest();
+ }
+
+/**
+Panic the client in response to an operation on an existing subsession, after
+which the request mustn't be completed
+
+This version allows panic categories to be passed in to support expected legacy
+behaviour.
+*/
+void CCommonPlayer::PanicClient(CWorkerSubSession& /*aSubSession*/, const TDesC &aCategory, TInt aPanic)
+ {
+ SafeMessage().PanicClient(aCategory, aPanic);
+ DontCompleteCurrentRequest();
+ }
+
+EXPORT_C void CCommonPlayer::PanicClient(TInt aPanic)
+ {
+ SafeMessage().PanicClient(KDenFaultPanic, aPanic);
+ DontCompleteCurrentRequest();
+ }
+
+EXPORT_C void CCommonPlayer::PanicClient(const TDesC& aCategory, TInt aPanic)
+ {
+ SafeMessage().PanicClient(aCategory, aPanic);
+ DontCompleteCurrentRequest();
+ }
+
+EXPORT_C void CCommonPlayer::DontCompleteCurrentRequest()
+ {
+ iComplete=EFalse;
+ }
+
+EXPORT_C TBool CCommonPlayer::ShouldCompleteCurrentRequest() const
+ {
+ return iComplete;
+ }
+
+EXPORT_C void CCommonPlayer::SetReturn(TInt aReturn/*, TInt anError, TUid anOwner*/)
+ {
+ iReturn=aReturn;
+
+ }
+
+/**
+Remove all subsessions belonging to sessions of the nominated worker. No locks required; only the
+Player accesses the object container.
+@see TWorkerMsg::ECleanupDeadPeer
+*/
+EXPORT_C void CCommonPlayer::CleanupDeadWorker(TWorkerId aWorkerId)
+ {
+ (void)aWorkerId;
+ //TBDAA - it's in ss_glob.h ASSERT_HOME_THREAD;
+
+ // The object container is stored as a packed array, so working backwards through it avoids invalidating
+ // the iterator when removing entries (and as a bonus is more efficient)
+ for(TInt i = iSubSessions.Count() - 1; i >= 0; --i)
+ {
+ iSubSessions[i]->CleanupDeadWorker(aWorkerId);
+ }
+ }
+/**
+If an incoming shutdown request is of type EImmediate, informs the
+Worker Thread that Player shutdown is complete, otherwise do nothing here.
+*/
+void CCommonPlayer::ProcessShutdownRequest(TCFShutdownType aType)
+ {
+ COMMONLOG((WorkerId(),KECommonBootingTag, _L8("CPlayer::ProcessShutdownRequest(%d)"), aType));
+ WorkerThread().SetPlayerShutdownComplete(aType == CommsFW::EImmediate);
+ }
+
+/**
+Walk through all of the subsessions, telling each to complete all blocked requests
+with KErrServerAbort. We don't attempt to free them - although with a shared
+heap this could reduce the amount of leakage it seems likely that the more we do
+with these data structures, the greater the risk that the contagion spreads to
+other users of the heap. Clients that attempt almost any further operation after KErrAbort
+will get panicked by the Dealer in the usual bad handle way - this is harsh but fair, and
+better than simply leaving them hung.
+*/
+TInt CCommonPlayer::PostMortemCleanup()
+ {
+ // No locks are required - we're only here because the owner has died
+ for(TInt i = 0; i < iSubSessions.Count(); ++i)
+ {
+ CWorkerSubSession* subSession = static_cast<CWorkerSubSession*>((iSubSessions[i]));
+ subSession->FinalCompleteAllBlockedMessages(KErrAbort);
+ }
+ return KErrNone;
+ }
+