commsfwsupport/commselements/serverden/src/sd_pitboss.cpp
changeset 0 dfb7c4ff071f
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 "sd_log.h"
       
    22 #include "sd_roles.h"
       
    23 #include "sd_msgs.h"
       
    24 #include "sd_objectbroker.h"
       
    25 #include <rsshared.h>
       
    26 #include <elements/cfmacro.h>
       
    27 
       
    28 
       
    29 #ifdef _DEBUG
       
    30 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
       
    31 // (if it could happen through user error then you should give it an explicit, documented, category + code)
       
    32 _LIT(KSpecAssert_ElemSvrDenPitBsC, "ElemSvrDenPitBsC");
       
    33 #endif
       
    34 
       
    35 using namespace Den;
       
    36 using namespace CommsFW;
       
    37 
       
    38 //
       
    39 // CCommonPitBoss
       
    40 //
       
    41 
       
    42 
       
    43 EXPORT_C void CCommonPitBoss::ConstructL()
       
    44 	{
       
    45 	User::LeaveIfError(iImmediateShutdownLock.CreateLocal());
       
    46 	iWorkerDataGlobals = CWorkerDataGlobals::NewL();
       
    47 	iConfLevelMonitor = CConfigurationLevelMonitor::NewL(this);
       
    48 	TWorkerThreadRegister* mainProperties = WorkerDataGlobals().GetWorkerGlobals(TWorkerThreadPublicInfo::EMainThread);
       
    49 	mainProperties->iHeap = &User::Heap();
       
    50 	mainProperties->iDealer = OwnerThread()->Dealer();
       
    51 	mainProperties->iPlayer = OwnerThread()->Player();
       
    52 	}
       
    53 
       
    54 EXPORT_C CCommonDealer* CCommonPitBoss::GetDealer(TWorkerId aId)
       
    55 	{
       
    56 	return WorkerDataGlobals().GetWorkerGlobals(aId)->iDealer;
       
    57 	}
       
    58 
       
    59 EXPORT_C CCommonPlayer* CCommonPitBoss::GetPlayer(const TWorkerIntroductionMsg& aMsg)
       
    60 	{
       
    61 	const TWorkerThreadPublicInfo& msgInfo = aMsg.WorkerInfo();
       
    62 	TWorkerThreadRegister& workerReg = *WorkerDataGlobals().GetWorkerGlobals(msgInfo.iWorkerId);
       
    63 	return workerReg.iPlayer;
       
    64 	}
       
    65 
       
    66 EXPORT_C TBool CCommonPitBoss::ModuleConfigurationComplete() const
       
    67 	{
       
    68 	return iConfLevelMonitor == NULL;
       
    69 	}
       
    70 
       
    71 EXPORT_C TBool CCommonPitBoss::IsShuttingDown() const
       
    72 	{
       
    73 	return iShuttingDown;
       
    74 	}
       
    75 
       
    76 void CCommonPitBoss::StartShutdown()
       
    77 	{
       
    78 	iShuttingDown = ETrue;
       
    79 	}
       
    80 
       
    81 EXPORT_C void CCommonPitBoss::SessionShutdownComplete()
       
    82 	{
       
    83 	iSessionShutdownComplete = ETrue;
       
    84 	ShutdownIfReady();
       
    85 	}
       
    86 
       
    87 void CCommonPitBoss::ShutdownIfReady()
       
    88 	{
       
    89 	__ASSERT_DEBUG(iOwnerThread->WorkerId() == TWorkerThreadPublicInfo::EMainThread, User::Panic(KSpecAssert_ElemSvrDenPitBsC, 1));
       
    90 	COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::ShutdownIfReady() - iShuttingDown == %d, iSessionShutdownComplete = %d, iPeerShutdownComplete = %d"),
       
    91 		iShuttingDown, iSessionShutdownComplete, iPeerShutdownComplete));
       
    92 	if(iShuttingDown && iSessionShutdownComplete && iPeerShutdownComplete)
       
    93 		{
       
    94 		iOwnerThread->TriggerThreadShutdownCallback();
       
    95 		}
       
    96 	}
       
    97 
       
    98 /**
       
    99 Immediate shutdowns expose a number of additional race risks; in the face of one happening to
       
   100 any thread at all we stop attempting certain kinds of cleanup. This should be acceptable
       
   101 behaviour since at it will be the whole of ESock shutting down.
       
   102 To avoid races between the testing and setting of this state, testing for it gains a lock
       
   103 which must be explicitly released.
       
   104 @see CPitBoss::ReleaseImmediateShutdownPresent()
       
   105 */
       
   106 TBool CCommonPitBoss::TestAndLockImmediateShutdownPresent() const
       
   107 	{
       
   108 	iImmediateShutdownLock.Wait();
       
   109 	return iImmediateShutdownMark;
       
   110 	}
       
   111 
       
   112 void CCommonPitBoss::ReleaseImmediateShutdownPresent() const
       
   113 	{
       
   114 	iImmediateShutdownLock.Signal();
       
   115 	}
       
   116 
       
   117 void CCommonPitBoss::SetImmediateShutdownPresent()
       
   118 	{
       
   119 	iImmediateShutdownLock.Wait();
       
   120 	iImmediateShutdownMark = ETrue;
       
   121 	iImmediateShutdownLock.Signal();
       
   122 	}
       
   123 
       
   124 /**
       
   125 Tests whether immediate shutdown is signaled. This function does not
       
   126 lock and is used where this knowledge is desired but no action is taken that might
       
   127 race with other threads.
       
   128 @see CPitBoss::TestAndLockImmediateShutdownPresent()
       
   129 @see CPitBoss::ReleaseImmediateShutdownPresent()
       
   130 */
       
   131 EXPORT_C TBool CCommonPitBoss::TestImmediateShutdownPresent() const
       
   132 	{
       
   133 	return iImmediateShutdownMark;
       
   134 	}
       
   135 
       
   136 EXPORT_C CCommonPitBoss::~CCommonPitBoss()
       
   137 	{
       
   138 	delete iConfLevelMonitor;
       
   139 
       
   140 	/* The reason for this bit of code is that when we shut down there's a race between the Pitboss
       
   141 	and an optimal Dealer where the Pitboss doesn't discover the optimal dealer is going down (PB
       
   142 	goes down first) and thus doesn't close the resources it have on it before the Pitboss is destroyed.
       
   143 	*/
       
   144 	for(TWorkerId id = TWorkerThreadPublicInfo::EFirstPlayerThread; id <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++id)
       
   145 		{
       
   146 		if(WorkerExists(id))
       
   147 			{
       
   148 			FreeWorkerReferences(id);
       
   149 			}
       
   150 		}
       
   151 	delete iWorkerDataGlobals;
       
   152 	iImmediateShutdownLock.Close();
       
   153 //#ifdef _DEBUG
       
   154 	iForsakenHeapList.Close();
       
   155 //#endif
       
   156 	}
       
   157 
       
   158 EXPORT_C CCommonPitBoss::CCommonPitBoss(CCommonWorkerThread* aOwnerThread)
       
   159 :	iOwnerThread(aOwnerThread),
       
   160 	iNextUniqueId(1)
       
   161 	{
       
   162 	__ASSERT_DEBUG(iOwnerThread->WorkerId() == TWorkerThreadPublicInfo::EMainThread, User::Panic(KSpecAssert_ElemSvrDenPitBsC, 2));
       
   163 	__ASSERT_DEBUG(iOwnerThread->Player() == NULL, User::Panic(KSpecAssert_ElemSvrDenPitBsC, 3));
       
   164 	}
       
   165 
       
   166 EXPORT_C void CCommonPitBoss::PostMessage(CommsFW::TWorkerId aWorkerId, CommsFW::TCFMessage& aMessage)
       
   167 	{
       
   168 	iOwnerThread->PostMessage(aWorkerId, aMessage);
       
   169 	}
       
   170 
       
   171 /**
       
   172 Check whether a worker Id is legal and a worker with that Id is installed.
       
   173 */
       
   174 EXPORT_C TBool CCommonPitBoss::WorkerExists(TWorkerId aId) const
       
   175 	{
       
   176 	return WorkerDataGlobals().WorkerPresent(aId);
       
   177 	}
       
   178 
       
   179 
       
   180 /**
       
   181 Given the "local" worker thread's id (normally but not necessarily the current worker
       
   182 thread and that of another "foreign" worker thread, if they have different heaps then
       
   183 switch heaps and return the previous one, otherwise return NULL.
       
   184 */
       
   185 EXPORT_C RAllocator* CCommonPitBoss::MaybeSwitchHeap(TWorkerId aForeignWorkerId)
       
   186 	{
       
   187 	const TWorkerThreadPublicInfo& foreignInfo = *WorkerDataGlobals().GetWorkerGlobals(aForeignWorkerId);
       
   188 	__ASSERT_DEBUG(foreignInfo.iHeap, User::Panic(KSpecAssert_ElemSvrDenPitBsC, 4));
       
   189 	RHeap* heap = &User::Heap();
       
   190 	if(heap != foreignInfo.iHeap)
       
   191 		{
       
   192 		COMMONLOG((iOwnerThread->WorkerId(), KECommonSessDetailTag, _L8("CPitBoss::MaybeSwitchHeap - Switching heap to %08x."),foreignInfo.iHeap));
       
   193 		return User::SwitchAllocator(foreignInfo.iHeap);
       
   194 		}
       
   195 	else
       
   196 		{
       
   197 		COMMONLOG((iOwnerThread->WorkerId(), KECommonSessDetailTag, _L8("CPitBoss::MaybeSwitchHeap - No heap switch happened - Heap %08x."),heap));
       
   198 		}
       
   199 
       
   200 	return NULL;
       
   201 	}
       
   202 
       
   203 /**
       
   204 Called by any Player/thread to add a sub-session to a session. It will switch the local heap to that
       
   205 of the peer before performing operations on the session pointer. It is essential that the session lock is used
       
   206 around this call.
       
   207 @see CSubSessionIx::Lock
       
   208 @see CSubSessionIx::UnLock
       
   209 */
       
   210 EXPORT_C TInt CCommonPitBoss::AddSubSession(CWorkerSubSession* aSubSession, CWorkerSession* aSession, TInt& aHandle)
       
   211 	{
       
   212 	RAllocator* prevAllocator = MaybeSwitchHeap(aSession->WorkerId());
       
   213 	TInt err = aSession->SubSessions().Add(static_cast<CWorkerSubSession*>(aSubSession), aHandle);
       
   214 	COMMONLOG((iOwnerThread->WorkerId(),KECommonSessDetailTag, _L8("CPitBoss::AddSubSession(%08x, %08x, => %08x)"), aSubSession, aSession, aHandle));
       
   215 
       
   216 	if(prevAllocator)
       
   217 		{
       
   218 		User::SwitchAllocator(prevAllocator);
       
   219 		}
       
   220 	return err;
       
   221 	}
       
   222 
       
   223 /**
       
   224 Called by any Player/thread to remove a sub-session from a session. It will switch the local heap to that
       
   225 of the peer before performing operations on the session pointer. It is essential that the session lock is used
       
   226 around this call.
       
   227 @see CSubSessionIx::Lock
       
   228 @see CSubSessionIx::UnLock
       
   229 */
       
   230 EXPORT_C void CCommonPitBoss::RemoveSubSession(TInt aHandle, CWorkerSession* aSession)
       
   231 	{
       
   232 	RAllocator* prevAllocator = MaybeSwitchHeap(aSession->WorkerId());
       
   233 	COMMONLOG((iOwnerThread->WorkerId(),KECommonSessDetailTag, _L8("CPitBoss::RemoveSubSession(%08x, %08x)"), aHandle, aSession));
       
   234 	VERIFY(aSession->SubSessions().Remove(aHandle) != NULL);
       
   235 	if(prevAllocator)
       
   236 		{
       
   237 		User::SwitchAllocator(prevAllocator);
       
   238 		}
       
   239 	}
       
   240 
       
   241 CCommonDealer* CCommonPitBoss::Dealer(TWorkerId aWorkerId) const
       
   242 	{
       
   243 	return WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iDealer;
       
   244 	}
       
   245 
       
   246 CCommonPlayer* CCommonPitBoss::Player(TWorkerId aWorkerId) const
       
   247 	{
       
   248 	return WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iPlayer;
       
   249 	}
       
   250 
       
   251 EXPORT_C const RThread& CCommonPitBoss::RThreadRef(TWorkerId aWorkerId) const
       
   252 	{
       
   253 	__ASSERT_DEBUG(aWorkerId <= TWorkerThreadPublicInfo::EMaxWorkerThreadId, User::Panic(KSpecAssert_ElemSvrDenPitBsC, 5));
       
   254 	__ASSERT_DEBUG(WorkerExists(aWorkerId), User::Panic(KSpecAssert_ElemSvrDenPitBsC, 6));	// can't do this to an absent thread
       
   255 	return WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iThread;
       
   256 	}
       
   257 
       
   258 void CCommonPitBoss::AddPendingIntroductionResponse()
       
   259 	{
       
   260 	++iPendingIntroResponses;
       
   261 	}
       
   262 
       
   263 void CCommonPitBoss::RemovePendingIntroductionResponse()
       
   264 	{
       
   265 	--iPendingIntroResponses;
       
   266 	}
       
   267 
       
   268 EXPORT_C void CCommonPitBoss::BindMessageReceived(const CommsFW ::TCFModuleName& aPeerName, TWorkerId aPeerId)
       
   269 	{
       
   270 	WorkerDataGlobals().GetWorkerGlobals(aPeerId)->iModuleName = aPeerName;
       
   271 	AddPendingIntroductionResponse();
       
   272 	}
       
   273 
       
   274 	/**
       
   275 Used during binding when the PitBoss receives a introduction response message from a worker.
       
   276 The PitBoss will set-up housekeeping datastructures for the worker and add the supported
       
   277 protocols to its list of protocol pairings.
       
   278 @see TWorkerMsg::EMainIntroductionResp
       
   279 */
       
   280 EXPORT_C void CCommonPitBoss::ProcessWorkerIntroductionL(const TWorkerIntroductionMsg& aMsg)
       
   281 	{
       
   282 	// Note the arrival of the response - if we leave below then whatever the cause we shouldn't diagnose the peer
       
   283 	// as having failed to respond at all
       
   284 	RemovePendingIntroductionResponse();
       
   285 
       
   286 	const TWorkerThreadPublicInfo& msgInfo = aMsg.WorkerInfo();
       
   287 	__ASSERT_DEBUG(msgInfo.iWorkerId > TWorkerThreadPublicInfo::EMainThread && msgInfo.iWorkerId <= TWorkerThreadPublicInfo::EMaxWorkerThreadId, User::Panic(KSpecAssert_ElemSvrDenPitBsC, 7));
       
   288 	__ASSERT_DEBUG(!WorkerDataGlobals().WorkerPresent(msgInfo.iWorkerId), User::Panic(KSpecAssert_ElemSvrDenPitBsC, 8));
       
   289 	TWorkerThreadRegister& workerReg = *WorkerDataGlobals().GetWorkerGlobals(msgInfo.iWorkerId);
       
   290 	// Passing the thread id rather than opening a reference looks like a race possibility. However
       
   291 	// the worker should not have executed any protocol code yet so shouldn't have died. And even if
       
   292 	// it has the RootServer hasn't had a chance to unbind us, so the id must still be valid.
       
   293 	// Copy the base class details from the worker's response and flesh out frequently looked-up details
       
   294 	static_cast<TWorkerThreadPublicInfo&>(workerReg) = msgInfo;
       
   295 	workerReg.PeerCleanupPending(msgInfo.iWorkerId);	// until the dies we regard it as pending cleanup on itself, so that the exit of peers doesn't provoke premature cleanup
       
   296 	workerReg.iPeerDeathNotifier = new(ELeave) CPeerDeathNotifier(msgInfo.iWorkerId, workerReg.iThread, *this);
       
   297 	workerReg.iDealer = workerReg.iWorker->Dealer();
       
   298 	workerReg.iPlayer = workerReg.iWorker->Player();
       
   299 
       
   300 	//Domain specific stuff here
       
   301 	DoProcessWorkerIntroductionL(aMsg);
       
   302 
       
   303 #ifdef _DEBUG
       
   304 	// We only switch on the configured simulated allocation failures once the bindings are complete, because
       
   305 	// it's too hard to recover from them earlier. This is a regrettable but hopefully harmless limitation in
       
   306 	// practice, ie if we're OOM during boot then recovery strategies aren't obvious.
       
   307 	workerReg.iHasGlobalAllocFails = aMsg.FailType() != RAllocator::ENone;
       
   308 	if(workerReg.iHasGlobalAllocFails)
       
   309 		{
       
   310 		workerReg.iHeap->__DbgSetAllocFail(aMsg.FailType(), aMsg.FailRate());
       
   311 		}
       
   312 #endif
       
   313 	}
       
   314 
       
   315 /**
       
   316 The PitBoss monitors the Comms Configurator sequence level and when the core components
       
   317 have been configured (this includes ESock) this method is called to delete any data structures
       
   318 used only during startup of ESock.
       
   319 @see CConfigurationLevelMonitor
       
   320 @see CPitBoss::iPendingIntroResponses
       
   321 */
       
   322 EXPORT_C void CCommonPitBoss::OnCPMsConfigured()
       
   323 	{
       
   324 	// Replaced ASSERT with Log entry
       
   325 	// shouldn't get here without all bindings complete; if we do then it means a module
       
   326 	// load must have timed out & so the configurator moved on. So the module in question
       
   327 	// probably isn't bound correctly, etc.
       
   328 
       
   329 	if (iPendingIntroResponses != 0)
       
   330 		{
       
   331 		COMMONLOG((iOwnerThread->WorkerId(), KECommonBootingTag, _L8("CPitBoss::OnCPMsConfigured: %d module(s) not bound correctly"),iPendingIntroResponses));
       
   332 		}
       
   333 
       
   334 //#ifdef _DEBUG
       
   335 //	if(iPendingIntroResponses == 0 && iOwnerThread->AllocFailType() != RAllocator::ENone)
       
   336 //		{
       
   337 //		WorkerDataGlobals().GetWorkerGlobals(TWorkerThreadPublicInfo::EMainThread)->iHeap->__DbgSetAllocFail(iOwnerThread->AllocFailType(), iOwnerThread->AllocFailRate());
       
   338 //		}
       
   339 //#endif
       
   340 
       
   341 	delete iConfLevelMonitor;
       
   342 	iConfLevelMonitor = NULL;
       
   343 
       
   344 	DoOnCPMsConfigured();
       
   345 	BroadcastConfigurationComplete(EModuleInitialisation);
       
   346 	}
       
   347 
       
   348 /**
       
   349 If a worker dies the PitBoss will call this method. It will clean up the housekeeping datastructures
       
   350 related to the worker and it will spawn the RedShirt thread which will try to delete the workers own
       
   351 data structures. It is a best effort attempt that doesn't guarantee to free up all the dead workers memory
       
   352 and the RedShirt could be PANICed by the kernel, which is why a short lived seperate thread is doing it.
       
   353 */
       
   354 EXPORT_C void CCommonPitBoss::OnPeerDeath(TWorkerId aWorkerId)
       
   355 	{
       
   356 	COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::OnPeerDeath() worker %d died"), aWorkerId));
       
   357 
       
   358 	TWorkerThreadRegister& worker = *WorkerDataGlobals().GetWorkerGlobals(aWorkerId);
       
   359 	delete worker.iPeerDeathNotifier;
       
   360 	worker.iPeerDeathNotifier = NULL;
       
   361 
       
   362 	// If worker ran a Player all its protocol pairings are now dead. We can't know whether the thread actually
       
   363 	// did run a Player as (presuming it exited cleanly) it cleaned up, but it's adequately cheap & a rare case
       
   364 	DoOnPeerDeath(aWorkerId);
       
   365 
       
   366 	worker.PeerCleanupCompleted(aWorkerId);	// worker is no longer waiting for itself to exit
       
   367 
       
   368 	// Check how the worker died - if it appears to be involuntary then we consider its heap to be
       
   369 	// forsaken and don't check it for leaks later
       
   370 	if(worker.iThread.ExitType() != EExitKill || worker.iThread.ExitReason() != KErrNone)
       
   371 		{
       
   372 		iForsakenHeapList.Add(worker.iHeap);
       
   373 		}
       
   374 
       
   375 	// Main dealer needs to cleanup
       
   376 	Dealer(TWorkerThreadPublicInfo::EMainThread)->CleanupDeadWorker(aWorkerId);
       
   377 
       
   378 	CCommonWorkerThread* deadWorker = WorkerDataGlobals().WorkerThread(aWorkerId);
       
   379 	if(deadWorker)	// always clean-up now
       
   380 		{
       
   381 		// Send in the Red Shirt thread to complete any blocked operations on any remaining
       
   382 		// subsession with KErrAbort. If it dies in vain then we care as briefly as
       
   383 		// Captain Kirk ever did about one of his anonymous security guards.
       
   384 		RThread redShirt;
       
   385 		if(DoCreateRedShirt(redShirt, aWorkerId, *deadWorker) == KErrNone)
       
   386 			{
       
   387 			TRequestStatus rendezStatus;
       
   388 			redShirt.Rendezvous(rendezStatus);
       
   389 			COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::CompleteWorkerThreadCleanup() - releasing RedShirt to complete Player's blocked requests")));
       
   390 			redShirt.Resume();
       
   391 			User::WaitForRequest(rendezStatus);
       
   392 			COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::CompleteWorkerThreadCleanup() - RedShirt completed, status %d"), rendezStatus.Int()));
       
   393 			redShirt.Close();
       
   394 			}
       
   395 		else
       
   396 			{
       
   397 			COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::CompleteWorkerThreadCleanup() - failed creating RedShirt to clean Player")));
       
   398 			}
       
   399 		}
       
   400 
       
   401 	// Tell all peer threads to clean up
       
   402 	for(CommsFW::TWorkerId peerId = TWorkerThreadPublicInfo::EFirstPlayerThread; peerId <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++peerId)
       
   403 		{
       
   404 		if(peerId != aWorkerId && WorkerExists(peerId))
       
   405 			{
       
   406 			// If the cleanup of any peer was waiting for confirmation from the one which just died then regard
       
   407 			// it as complete now
       
   408 			HandleWorkerCleanupCompletionByPeer( peerId, aWorkerId); //Deliberately mirrored sense
       
   409 			// May already have closed transport to peer
       
   410 			if(iOwnerThread->PeerReachable(peerId))
       
   411 				{
       
   412 				COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::OnPeerDeath() instructing peer %d to cleanup"), peerId));
       
   413 				worker.PeerCleanupPending(peerId);
       
   414 				TWorkerCleanupDeadPeerMsg msg(aWorkerId);
       
   415 				iOwnerThread->PostMessage(peerId, msg);
       
   416 				}
       
   417 			else
       
   418 				COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::OnPeerDeath() peer %d no longer bound to main thread"), peerId));
       
   419 			}
       
   420 		}
       
   421 
       
   422 	// Initial clean-up of worker is by PitBoss now complete; final clean-up may
       
   423 	// not occur until any cleanup requests have been completed
       
   424 	COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("Destroying peer #%d handler"),aWorkerId));
       
   425 	iOwnerThread->DropTransportToPeer(aWorkerId);
       
   426 	HandleWorkerCleanupCompletionByPeer(aWorkerId, TWorkerThreadPublicInfo::EMainThread);
       
   427 	}
       
   428 
       
   429 EXPORT_C TInt CCommonPitBoss::DoCreateRedShirt(RThread& aRedShirt, TWorkerId aWorkerId, CCommonWorkerThread& aDeadWorker)
       
   430 	{
       
   431 	//Default implementation - uses CCommonWorkerThread::PostMortemCleanupThreadEntry
       
   432 	return aRedShirt.Create(KNullDesC, CCommonWorkerThread::PostMortemCleanupThreadEntry, 8192, static_cast<RHeap*>(WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iHeap), &aDeadWorker);
       
   433 	}
       
   434 
       
   435 EXPORT_C TBool CCommonPitBoss::ResolvePlayerRoleToId(const TPlayerRole& aRoleId, CommsFW::TWorkerId& aWorkerId) const
       
   436 	{
       
   437 	for(TWorkerId id = TWorkerThreadPublicInfo::EFirstPlayerThread; id <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++id)
       
   438 		{
       
   439 		if (WorkerExists(id) && Player(id)->PlayerRole().Role() == aRoleId.Role())
       
   440 			{
       
   441 			aWorkerId = id;
       
   442 			return ETrue;
       
   443 			}
       
   444 		}
       
   445 #ifdef _DEBUG
       
   446 	aWorkerId = TWorkerThreadPublicInfo::ENullWorkerId;	// help find buggy code which ignores returns
       
   447 #endif
       
   448 	return EFalse;
       
   449 	}
       
   450 
       
   451 
       
   452 EXPORT_C TBool CCommonPitBoss::ResolveWorkerNameToId(const TDesC8& aWorkerName, TWorkerId& aWorkerId) const
       
   453 	{
       
   454 	for(TWorkerId id = TWorkerThreadPublicInfo::EFirstPlayerThread; id <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++id)
       
   455 		{
       
   456 		if(WorkerExists(id) && WorkerDataGlobals().GetWorkerGlobals(id)->iModuleName.CompareF(aWorkerName) == 0)
       
   457 			{
       
   458 			aWorkerId = id;
       
   459 			return ETrue;
       
   460 			}
       
   461 		}
       
   462 #ifdef _DEBUG
       
   463 	aWorkerId = TWorkerThreadPublicInfo::ENullWorkerId;	// help find buggy code which ignores returns
       
   464 #endif
       
   465 	return EFalse;
       
   466 	}
       
   467 
       
   468 EXPORT_C void CCommonPitBoss::HandleWorkerCleanupCompletionByPeer(TWorkerId aWorkerId, TWorkerId aPeerId)
       
   469 	{
       
   470 	COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::HandleWorkerCleanupCompletionByPeer() cleanup of worker %d by peer %d completed"), aWorkerId, aPeerId));
       
   471 	TWorkerThreadRegister& properties(*WorkerDataGlobals().GetWorkerGlobals(aWorkerId));
       
   472 	if(properties.IsValid())	// Might already have processed the worker's own shutdown
       
   473 		{
       
   474 		properties.PeerCleanupCompleted(aPeerId);
       
   475 		if(properties.AllPeerCleanupsCompleted())
       
   476 			{
       
   477 			CompleteWorkerThreadCleanup(aWorkerId);
       
   478 			}
       
   479 		}
       
   480 	}
       
   481 
       
   482 void CCommonPitBoss::CompleteWorkerThreadCleanup(TWorkerId aWorkerId)
       
   483 	{
       
   484 	__ASSERT_DEBUG(aWorkerId != TWorkerThreadPublicInfo::EMainThread, User::Panic(KSpecAssert_ElemSvrDenPitBsC, 9));
       
   485 	COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::CompleteWorkerThreadCleanup() - final cleanup phase for worker %d"), aWorkerId));
       
   486 
       
   487 	// Free resources
       
   488 	FreeWorkerReferences(aWorkerId);
       
   489 
       
   490 	// Test whether all cleanups done
       
   491 	TWorkerId peerId;
       
   492 	for(peerId = TWorkerThreadPublicInfo::EFirstPlayerThread; peerId <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++peerId)
       
   493 		{
       
   494 		if(WorkerExists(peerId))
       
   495 			{
       
   496 			break;
       
   497 			}
       
   498 		}
       
   499 	if(peerId > TWorkerThreadPublicInfo::EMaxWorkerThreadId)
       
   500 		{
       
   501 		iPeerShutdownComplete = ETrue;
       
   502 		ShutdownIfReady();
       
   503 		}
       
   504 	}
       
   505 
       
   506 void CCommonPitBoss::FreeWorkerReferences(TWorkerId aWorkerId)
       
   507 	{
       
   508 	DoFreeWorkerReferences(aWorkerId);
       
   509 
       
   510 	TWorkerThreadRegister& properties(*WorkerDataGlobals().GetWorkerGlobals(aWorkerId));
       
   511 	delete properties.iPeerDeathNotifier;
       
   512 //	properties.iHeap->Close();
       
   513 	properties.Clear();
       
   514 	}
       
   515 
       
   516 #ifdef _DEBUG
       
   517 // If a heap has been configured from boot to have a failure mode then we don't override this here as
       
   518 // the lifetime failure testing is more important than the specific test case doing a SetFailNext
       
   519 EXPORT_C void CCommonPitBoss::SetFailNextForAllHeaps(TInt aFailNext)
       
   520 	{
       
   521 	for(TWorkerId workerId = TWorkerThreadPublicInfo::EMainThread; workerId <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++workerId)
       
   522 		{
       
   523 		if(WorkerExists(workerId))
       
   524 			{
       
   525 			if(WorkerDataGlobals().GetWorkerGlobals(workerId)->iHasGlobalAllocFails)
       
   526 				{
       
   527 				if(aFailNext == KResetAllocFails)
       
   528 					{
       
   529 					// Reset lifetime failure mode.
       
   530 					WorkerDataGlobals().GetWorkerGlobals(workerId)->iHeap->__DbgSetAllocFail(RAllocator::EReset, 0);
       
   531 					}
       
   532 				}
       
   533 			else
       
   534 				{
       
   535 				WorkerDataGlobals().GetWorkerGlobals(workerId)->iHeap->__DbgSetAllocFail((aFailNext < 0)? RAllocator::EReset: RAllocator::EFailNext, aFailNext);
       
   536 				}
       
   537 			}
       
   538 		}
       
   539 	}
       
   540 
       
   541 EXPORT_C TBool CCommonPitBoss::TestFailNextForAllHeaps() const
       
   542 	{
       
   543 	class RPeekHeap : public RHeap
       
   544 		{
       
   545  	public:
       
   546 		RAllocator::TAllocFail FailNextMode() const
       
   547 			{
       
   548 			return iFailType;
       
   549 			}
       
   550 		};
       
   551 
       
   552 	for(TWorkerId workerId = TWorkerThreadPublicInfo::EMainThread; workerId <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++workerId)
       
   553 		{
       
   554  		if(WorkerExists(workerId) && !WorkerDataGlobals().GetWorkerGlobals(workerId)->iHasGlobalAllocFails)
       
   555  			{
       
   556  			RPeekHeap* heap = static_cast<RPeekHeap*>(WorkerDataGlobals().GetWorkerGlobals(workerId)->iHeap);
       
   557  			if(heap->FailNextMode() != RAllocator::EFailNext)
       
   558  				{
       
   559  				return EFalse;	// at least one heap isn't in fail-next mode
       
   560  				}
       
   561  			}
       
   562  		}
       
   563  	return ETrue;
       
   564  	}
       
   565 #else
       
   566 EXPORT_C void CCommonPitBoss::SetFailNextForAllHeaps(TInt /*aFailNext*/)
       
   567 	{}
       
   568 EXPORT_C TBool CCommonPitBoss::TestFailNextForAllHeaps() const
       
   569 	{return EFalse;}
       
   570 #endif
       
   571 
       
   572 /** Called synchronously by worker threads just prior to their exit to signal that their exit completed normally and
       
   573 that external cleanup is not required
       
   574 */
       
   575 EXPORT_C void CCommonPitBoss::PeerWorkerExiting(TWorkerId aWorker)
       
   576 	{
       
   577 	// Remove the pointers to the major control objects which a cleanup thread would use in the event of abnormal exit
       
   578 	TWorkerThreadRegister& properties(*WorkerDataGlobals().GetWorkerGlobals(aWorker));
       
   579 	properties.iWorker = NULL;
       
   580 	properties.iDealer = NULL;
       
   581 	properties.iPlayer = NULL;
       
   582 	}
       
   583 
       
   584 
       
   585 
       
   586 EXPORT_C void CCommonPitBoss::BroadcastConfigurationComplete(TConfigurationCompletionType aType)
       
   587 	{
       
   588 	TWorkerConfigurationComplete msg(aType);
       
   589 	for(CommsFW::TWorkerId peerId = TWorkerThreadPublicInfo::EFirstPlayerThread; peerId <= TWorkerThreadPublicInfo::EMaxWorkerThreadId; ++peerId)
       
   590 		{
       
   591 		if(Dealer(peerId))
       
   592 			{
       
   593 			COMMONLOG((iOwnerThread->WorkerId(), KECommonServerTag, _L8("CPitBoss::OnCPMsConfigured() - notifying peer %d"), peerId));
       
   594 			if(OwnerThread()->PeerReachable(peerId))
       
   595 				{
       
   596 				// Need to make temporary copy of the message as TCFLegacyMessagePacker modifies
       
   597 				// it in place and will assert in debug builds if it detects its own special
       
   598 				// override code indicating that a message is being packed twice if we broadcast
       
   599 				// to more than one peer.
       
   600 				TWorkerConfigurationComplete tempMsg(msg);
       
   601 
       
   602 				OwnerThread()->PostMessage(peerId, tempMsg);
       
   603 				}
       
   604 			}
       
   605 		}
       
   606 	// Process parked requests for the main Dealer
       
   607 	Dealer(TWorkerThreadPublicInfo::EMainThread)->ProcessConfigurationComplete(aType);
       
   608 	}
       
   609 
       
   610 /**
       
   611 */
       
   612 EXPORT_C TBool CCommonPitBoss::FindOptimalDealer(TWorkerId aWorkerId, CCommonWorkerDealer*& aDealer)
       
   613 	{
       
   614 	if(WorkerExists(aWorkerId))
       
   615 		{
       
   616 		CCommonDealer* hostThreadDealer = Dealer(*WorkerDataGlobals().GetWorkerGlobals(aWorkerId));
       
   617 		if (hostThreadDealer)
       
   618 			{
       
   619 			aDealer = hostThreadDealer->WorkerThread().WorkerDealer();
       
   620 			if (aDealer)
       
   621 				{
       
   622 				return ETrue;
       
   623 				}
       
   624 			}
       
   625 		}
       
   626 	return EFalse;
       
   627 	}
       
   628 
       
   629 //
       
   630 // CPitBoss::CPeerDeathNotifier
       
   631 //
       
   632 
       
   633 CPeerDeathNotifier::CPeerDeathNotifier(TWorkerId aWorkerId, RThread aThread, MPeerDeathObserver& aObserver)
       
   634 : CActive(EPriorityLow),
       
   635   iWorkerId(aWorkerId),
       
   636   iThread(aThread),
       
   637   iObserver(aObserver)
       
   638 	{
       
   639 	iThread.Logon(iStatus);
       
   640 	CActiveScheduler::Add(this);
       
   641 	SetActive();
       
   642 	}
       
   643 
       
   644 void CPeerDeathNotifier::DoCancel()
       
   645 	{
       
   646 	iThread.LogonCancel(iStatus);
       
   647 	}
       
   648 
       
   649 void CPeerDeathNotifier::RunL()
       
   650 	{
       
   651 	iObserver.OnPeerDeath(iWorkerId);
       
   652 	}
       
   653 
       
   654 
       
   655 //
       
   656 // CConfigurationLevelMonitor
       
   657 //
       
   658 
       
   659 CConfigurationLevelMonitor* CConfigurationLevelMonitor::NewL(MConfiguratorObserver* aObserver)
       
   660 	{
       
   661 	CConfigurationLevelMonitor* self = new(ELeave) CConfigurationLevelMonitor(aObserver);
       
   662 	TInt err = self->iConfLevelProperty.Attach(KUidSystemCategory, aObserver->PropertyKey().iUid, EOwnerThread);
       
   663 	if(err != KErrNone)
       
   664 		{
       
   665 		delete self;
       
   666 		User::Leave(err);
       
   667 		}
       
   668 	CActiveScheduler::Add(self);
       
   669 	self->Subscribe();
       
   670 	return self;
       
   671 	}
       
   672 
       
   673 CConfigurationLevelMonitor::CConfigurationLevelMonitor(MConfiguratorObserver* aObserver)
       
   674 : CActive(EPriorityLow),
       
   675   iObserver(aObserver)
       
   676 	{
       
   677 	}
       
   678 
       
   679 CConfigurationLevelMonitor::~CConfigurationLevelMonitor()
       
   680 	{
       
   681 	Cancel();
       
   682 	iConfLevelProperty.Close();
       
   683 	}
       
   684 
       
   685 void CConfigurationLevelMonitor::Subscribe()
       
   686 	{
       
   687 	iConfLevelProperty.Subscribe(iStatus);
       
   688 	SetActive();
       
   689 	}
       
   690 
       
   691 /**
       
   692 Monitors the Comms Configurator configuration level. Will notify the listener when
       
   693 core components have been configured.
       
   694 @see CPitBoss::OnCPMsConfigured
       
   695 */
       
   696 void CConfigurationLevelMonitor::RunL()
       
   697 	{
       
   698 	Subscribe();
       
   699 	TInt level;
       
   700 	if(iConfLevelProperty.Get(level) == KErrNone)
       
   701 		{
       
   702 		if(level >= RootServer::EConfigurationComplete && !iCoreComponentsConfigured)
       
   703 			{
       
   704 			iCoreComponentsConfigured = ETrue;
       
   705 			iObserver->OnCPMsConfigured();
       
   706 			}
       
   707 		if(level >= RootServer::EConfigurationComplete)
       
   708 			{
       
   709 			Cancel();
       
   710 			}
       
   711 		}
       
   712 	}
       
   713 
       
   714 void CConfigurationLevelMonitor::DoCancel()
       
   715 	{
       
   716 	iConfLevelProperty.Cancel();
       
   717 	}
       
   718 
       
   719 //
       
   720 // CPitBoss::TWorkerThreadRegister
       
   721 //
       
   722 
       
   723 TWorkerThreadRegister::TWorkerThreadRegister()
       
   724 	{
       
   725 	PeerCleanupPending(TWorkerThreadPublicInfo::EMainThread);
       
   726 #ifdef _DEBUG
       
   727 	iHasGlobalAllocFails = EFalse;
       
   728 #endif
       
   729 	}
       
   730 
       
   731 void TWorkerThreadRegister::Clear()
       
   732 	{
       
   733 	TWorkerThreadPublicInfo::Clear();
       
   734 	iDealer = NULL;
       
   735 	iPlayer = NULL;
       
   736 	}
       
   737 
       
   738 void TWorkerThreadRegister::PeerCleanupPending(TWorkerId aPeerId)
       
   739 	{
       
   740 	iPendingPeerCleanups |= (1 << aPeerId);
       
   741 	}
       
   742 
       
   743 void TWorkerThreadRegister::PeerCleanupCompleted(TWorkerId aPeerId)
       
   744 	{
       
   745 	iPendingPeerCleanups &= ~(1 << aPeerId);
       
   746 	}
       
   747 
       
   748 TBool TWorkerThreadRegister::AllPeerCleanupsCompleted() const
       
   749 	{
       
   750 	return iPendingPeerCleanups == 0;
       
   751 	}
       
   752 
       
   753 
       
   754 //
       
   755 // THeapSwitcher
       
   756 //
       
   757 EXPORT_C THeapSwitcher::THeapSwitcher(CCommonPitBoss& aPitBoss, const Messages::TNodeId& aTarget)
       
   758 	{
       
   759 	MaybeSwitch(aPitBoss, aTarget.Thread());
       
   760 	}
       
   761 
       
   762 EXPORT_C THeapSwitcher::THeapSwitcher(CCommonPitBoss& aPitBoss, TWorkerId aForeignWorkerId)
       
   763 	{
       
   764 	MaybeSwitch(aPitBoss, aForeignWorkerId);
       
   765 	}
       
   766 
       
   767 
       
   768 EXPORT_C THeapSwitcher::~THeapSwitcher()
       
   769 	{
       
   770 	RevertToOwnHeap();
       
   771 	}
       
   772 
       
   773 EXPORT_C void THeapSwitcher::RevertToOwnHeap()
       
   774 	{
       
   775 	if(iPrev)
       
   776 		{
       
   777 		User::SwitchHeap(iPrev);
       
   778 		iPrev = NULL;
       
   779 		}
       
   780 	}
       
   781 
       
   782 EXPORT_C void THeapSwitcher::MaybeSwitch(CCommonPitBoss& aPitBoss, TWorkerId aForeignWorkerId)
       
   783 	{
       
   784 	iPrev = aPitBoss.MaybeSwitchHeap(aForeignWorkerId);
       
   785 	}
       
   786 
       
   787 /*
       
   788 EXPORT_C void CCommonWorkerThread::MaybeIncorporateFCL(TPlayerRoleMasks aPlane, TInt aPeerKindex, const Messages::TNodeId& aPeerId)
       
   789 	{
       
   790 	DoMaybeIncorporateFCL(aPlane, aPeerKindex,aPeerId);
       
   791 	}
       
   792 */
       
   793