serialserver/c32serialserver/SCOMM/cs_roles.cpp
changeset 0 dfb7c4ff071f
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 2005-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 <cfextras.h>
       
    22 #include <comms-infras/c32startcli.h>
       
    23 #include <e32property.h>
       
    24 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    25 #include <cflog.h>
       
    26 #endif
       
    27 #include "cs_roles.h"
       
    28 #include "C32LOG.H"
       
    29 #include "CS_STD.H"
       
    30 #include "cs_msgs.h"
       
    31 #include "cs_glob.h"
       
    32 
       
    33 using namespace RootServer;
       
    34 
       
    35 #define MSG_PRM(prmIndex)		(prmIndex)		// subsession is passed in message as parameter 3
       
    36 
       
    37 const TInt KIniDataBufSizeIncrement = 60;   // Initial buffer of 60 chars - after finding 
       
    38                                            // usual iniData section uses about 40 chars to describe workerId,Role and CSYlist
       
    39 
       
    40 //
       
    41 // CC32WorkerDataGlobals
       
    42 //
       
    43 
       
    44 CC32WorkerDataGlobals* CC32WorkerDataGlobals::NewL()
       
    45 	{
       
    46 	CC32WorkerDataGlobals* self = new(ELeave) CC32WorkerDataGlobals();
       
    47 	CleanupStack::PushL(self);
       
    48 	self->ConstructL(sizeof(TC32WorkerThreadRegister), KMaxWorkerThreadId);
       
    49 	CleanupStack::Pop(self);
       
    50 	return self;
       
    51 	}
       
    52 
       
    53 //
       
    54 // CCSYInfo
       
    55 //
       
    56 
       
    57 CCSYInfo::CCSYInfo(TInt aThreadNum)
       
    58 : iThreadNum(aThreadNum),
       
    59 iLoaded(EFalse),
       
    60 iLoadIndex(-1)
       
    61 	{
       
    62 	}
       
    63 
       
    64 CCSYInfo* CCSYInfo::NewL(const TDesC8& aCSYName, TInt aThreadNum)
       
    65 	{
       
    66 	CCSYInfo* self = new (ELeave) CCSYInfo(aThreadNum);
       
    67 	CleanupStack::PushL(self);
       
    68 	self->ConstructL(aCSYName);
       
    69 	CleanupStack::Pop(self);
       
    70 	return self;
       
    71 	}
       
    72 	
       
    73 	
       
    74 void CCSYInfo::ConstructL(const TDesC8& aCSYName)
       
    75 	{
       
    76 	iCSYName=aCSYName.AllocL();
       
    77 	}
       
    78 
       
    79 CCSYInfo::~CCSYInfo()
       
    80 	{
       
    81 	delete iCSYName;
       
    82 	iCSYPortPrefix.Close();
       
    83 	}
       
    84 	
       
    85 	
       
    86 TInt CCSYInfo::CompareCSYInfo(const CCSYInfo& aFirst,const CCSYInfo& aSecond)
       
    87 // compares CSY records by comparing the csy filenames
       
    88     {
       
    89     //-ve if first is less than second
       
    90     return aFirst.iCSYName->CompareF(*(aSecond.iCSYName));
       
    91     }
       
    92     	
       
    93 TInt CCSYInfo::SetPortNameSizeToMaximum()
       
    94 	{
       
    95 	__ASSERT_DEBUG(iCSYPortPrefix.Length()==0,Fault(EBadState,_L8("CCSYInfo: attempt to grow portname for CSY for a non-null string (ie, module looks loaded)")));
       
    96 	return iCSYPortPrefix.ReAlloc(KMaxFullName);	
       
    97 	}
       
    98 
       
    99     	
       
   100 void CCSYInfo::SetPortName(const TDesC& aPortName)
       
   101 	{
       
   102 	// since this may be called at end of csy load process, we have no reasonable way to deal with OOM,
       
   103 	// so before the csy load process started, the portname
       
   104 	// was grown to max. After setting the string we resize the portname so that the remaining
       
   105 	// memory is freed. An RBuf allows us to resize in-place.
       
   106 	
       
   107 	iCSYPortPrefix = aPortName;
       
   108 	
       
   109 #ifdef _DEBUG
       
   110 	TInt ret = iCSYPortPrefix.ReAlloc(aPortName.Length());
       
   111 	__ASSERT_DEBUG(ret == KErrNone,Fault(EBadState,_L8("CCSYInfo::SetPortName: failed to shrink port prefix. Ret: %d"),ret));
       
   112 #else
       
   113 	(void)iCSYPortPrefix.ReAlloc(aPortName.Length()); // on failure, continue with current size.
       
   114 #endif
       
   115 	
       
   116 	}
       
   117 	
       
   118 	
       
   119 	
       
   120 void CCSYInfo::SetCSYHandle(CSerial* aSerialHandle)
       
   121 //this handle is never actually used by CCSYInfo, just passed back to player later
       
   122 	{
       
   123 	iCSYHandle=aSerialHandle;
       
   124 	}
       
   125 
       
   126 
       
   127 
       
   128 
       
   129 
       
   130 
       
   131 //
       
   132 // CC32ThreadManager::CC32ParsedIniData
       
   133 //
       
   134 
       
   135 CC32ThreadManager::CC32ParsedIniData::CC32ParsedIniData()
       
   136 	{
       
   137 	}
       
   138 
       
   139 
       
   140 CC32ThreadManager::CC32ParsedIniData* CC32ThreadManager::CC32ParsedIniData::NewL(const TDesC8& aIniData, const TBool aIsDealer)
       
   141 
       
   142 // aIsDealer specifies whether this data was sent to us from the configurator as it spawned the
       
   143 // dealer thread
       
   144 	{
       
   145 	CC32ParsedIniData* self = new(ELeave) CC32ParsedIniData();
       
   146 	CleanupStack::PushL(self);
       
   147 	self->ConstructL(aIniData,aIsDealer);
       
   148 	CleanupStack::Pop(self);
       
   149 	return self;
       
   150 	}
       
   151 	
       
   152 
       
   153 CC32ThreadManager::CC32ParsedIniData::~CC32ParsedIniData()
       
   154 	{
       
   155 	iCSYs.Close();
       
   156 	}
       
   157 
       
   158 void CC32ThreadManager::CC32ParsedIniData::ConstructL(const TDesC8& aIniData, const TBool aIsDealer)
       
   159 // we could have had the NewL perform this function, but because that would men creating and destroying
       
   160 // this object for each data read, we chose to save that by making this operation separate
       
   161 // aIsDealer - true if this is the inidata for the dealer loading all the cmi files. This allows
       
   162 //             us to know this is a dealer even if nothing of the sort is in the [iniData] section and
       
   163 //             thus we can preserve backwards compat.
       
   164 
       
   165 
       
   166 // on exit the data should be:
       
   167 // workerID = always correct - if we are dealer it is automatically 0 regardless of what config says. If we
       
   168 //            are player we leave unless this is provided. We leave if it is zero and we are player.
       
   169 // isPlayer - is false if we know we are dealer (aIsDealer) regardless of aIniData. Is true if we
       
   170 //            see Role=player. If role missing and we are not Dealer (!aIsDealer) then we don't try
       
   171 //            any recovery since a workerthread assumes it is a dealer if no role.
       
   172 // isWildcard - true if a wildcard is provided in the csy list
       
   173 // iCSYs - list of the csys in CSYList. It is valid that a dealer may not have a CSY list
       
   174 	{
       
   175 	TPtrC8 roleValue;
       
   176 	TPtrC8 workerIdValue;
       
   177 	TPtrC8 csyListValue;
       
   178 	
       
   179 	if (&aIniData==NULL || aIniData.Length()==0)
       
   180 		{
       
   181 		if (!aIsDealer)
       
   182 			{
       
   183 			C32LOG(KC32Warning,_L8("CC32ParsedIniData: Corrupt CMI file that references C32.DLL: Missing [IniData] section."));
       
   184 			C32LOG(KC32Warning,_L8("CC32ParsedIniData: Please migrate all *.cmi files that reference C32.DLL to include Group token and [IniData] section."));
       
   185 			// we don't panic in this scenario since this could be an old ini file we've found
       
   186 			// in future we will panic here once licencees have migrated any cmi files they need to
       
   187 			User::Leave(KErrCorrupt);
       
   188 			}
       
   189 		else
       
   190 			{
       
   191 			// dealers are allowed to not have CSYLists and we know what the role & workerId should be so continue
       
   192 			// in future this will be a config error but during migration we continue.
       
   193    		    C32LOG(KC32Detail,_L8("CC32ParsedIniData: Supplied inidata for dealer is empty - must be old CMI file. Skipping."));
       
   194 			return;
       
   195 			}
       
   196 		}
       
   197 
       
   198 
       
   199 	if (!GetVarFromIniData(aIniData, KNullDesC8, KWorkerIdLabel, workerIdValue) )
       
   200 		{
       
   201 		C32LOG(KC32Warning,_L8("CC32ParsedIniData: Corrupt [IniData] section - missing workerId value."));
       
   202 		
       
   203 		if (aIsDealer)
       
   204 			{
       
   205 			C32LOG(KC32Warning,_L8("CC32ParsedIniData: As we are dealer, ignoring corruption by setting workerId to 0 and continuing"));
       
   206 			iCMIWorkerId = KMainThreadId;
       
   207 			}
       
   208 		else
       
   209 			{
       
   210 #ifdef _DEBUG
       
   211 			Fault(EBadIniData); // panic
       
   212 #endif
       
   213 			User::Leave(KErrCorrupt);
       
   214 			}
       
   215 		}
       
   216 	else
       
   217 		{
       
   218 		// we accept whatever we get as the workerId
       
   219 		TLex8 lex(workerIdValue);
       
   220 		(void)lex.Val(iCMIWorkerId);		
       
   221 		}
       
   222 		
       
   223 	
       
   224 		
       
   225 	
       
   226 	if (!GetVarFromIniData(aIniData, KNullDesC8, KRoleLabel, roleValue))
       
   227 		{
       
   228 		C32LOG(KC32Warning,_L8("CC32ParsedIniData: Corrupt [IniData] section - missing Role label."));
       
   229 		if (!aIsDealer)
       
   230 			{
       
   231 #ifdef _DEBUG
       
   232 		Fault(EBadIniData); // panic
       
   233 #endif
       
   234 		User::Leave(KErrCorrupt);
       
   235 			}
       
   236 		}
       
   237 	else if(roleValue.CompareF(KPlayerRole)==0)
       
   238 		{
       
   239 		iIsPlayer = ETrue;
       
   240 		}
       
   241 	else if(roleValue.CompareF(KDealerRole)!=0)
       
   242 		{
       
   243 		C32LOG2(KC32Warning,_L8("CC32ParsedIniData: Corrupt [IniData] section: Specified Role not recognised; must be Dealer or Player: %d "),&roleValue);
       
   244 		
       
   245 #ifdef _DEBUG
       
   246 		Fault(EBadIniData); // panic
       
   247 #endif
       
   248 		User::Leave(KErrCorrupt);
       
   249 		}
       
   250 		
       
   251 	
       
   252 	if (iIsPlayer && (iCMIWorkerId < 0 || iCMIWorkerId > KMaxWorkerThreadId))
       
   253 		{
       
   254 		C32LOG2(KC32Warning,_L8("CC32ParsedIniData: Corrupt [IniData] section: Role=Player and WorkerId invalid: %d"),iCMIWorkerId);
       
   255 #ifdef _DEBUG
       
   256 		Fault(EBadIniData); // panic
       
   257 #endif
       
   258 		User::Leave(KErrCorrupt);
       
   259 		}
       
   260 		
       
   261 		
       
   262 	if (!GetVarFromIniData(aIniData, KNullDesC8, KCSYListLabel, csyListValue))
       
   263 		{
       
   264 		if (iIsPlayer)
       
   265 			{
       
   266 			C32LOG(KC32Warning,_L8("CC32ParsedIniData: Corrupt [IniData] section - missing CSYList definition."));
       
   267 #ifdef _DEBUG
       
   268 		Fault(EBadIniData); // panic
       
   269 #endif
       
   270 			User::Leave(KErrCorrupt);
       
   271 			}
       
   272 		}
       
   273 	else
       
   274 		{
       
   275 		
       
   276 		TInt sectionLen = 0;	
       
   277 		TPtrC8 section(csyListValue);
       
   278 
       
   279 		
       
   280 		while (section.Length() > 0)
       
   281 			{
       
   282 			// assume that a CSY name is at least 1 characters long
       
   283 			sectionLen = section.Find(TPtrC8(_S8(",")));
       
   284 			if (sectionLen > 0)
       
   285 				{
       
   286 				iCSYs.AppendL(section.Mid(0,sectionLen));
       
   287 				
       
   288 				if (sectionLen+1 < section.Length())
       
   289 					{
       
   290 					section.Set(section.Mid(sectionLen+1));
       
   291 					} 
       
   292 				else
       
   293 					{
       
   294 					section.Set(KNullDesC8);
       
   295 					}
       
   296 				} 
       
   297 			else if ((sectionLen==0) && (section.Length() > 0))
       
   298 				{
       
   299 				//possibly a double comma - we'll be nice and ignore it
       
   300 				section.Set(section.Mid(sectionLen+1));
       
   301 				} 
       
   302 			else if (section[0]=='*')
       
   303 				{
       
   304 				iIsDefault = ETrue;
       
   305 				if (section.Length() > 1)
       
   306 					{
       
   307 					section.Set(section.Mid(1));
       
   308 					} 
       
   309 				else
       
   310 					{
       
   311 					section.Set(KNullDesC8);
       
   312 					}
       
   313 				}
       
   314 			else
       
   315 				{
       
   316 				iCSYs.AppendL(section);
       
   317 				section.Set(KNullDesC8);
       
   318 				}
       
   319 			}
       
   320 		}		
       
   321 		
       
   322 
       
   323 	}
       
   324 
       
   325 
       
   326 
       
   327 
       
   328 
       
   329 
       
   330 
       
   331 
       
   332 
       
   333 //
       
   334 // CC32ThreadManager::CC32ThreadInfo
       
   335 //
       
   336 
       
   337 CC32ThreadManager::CC32ThreadInfo::CC32ThreadInfo()
       
   338 	{
       
   339 	}
       
   340 	
       
   341 
       
   342 
       
   343 CC32ThreadManager::CC32ThreadInfo* CC32ThreadManager::CC32ThreadInfo::NewL(const TDesC8& aModuleName)
       
   344 	{
       
   345 	CC32ThreadInfo* self = new (ELeave) CC32ThreadInfo();
       
   346 	CleanupStack::PushL(self);
       
   347 	self->ConstructL(aModuleName);
       
   348 	CleanupStack::Pop(self);
       
   349 	return self;	
       
   350 	}
       
   351 	
       
   352 	
       
   353 void CC32ThreadManager::CC32ThreadInfo::ConstructL(const TDesC8& aModuleName)
       
   354 	{
       
   355 	iModuleName = aModuleName.AllocL();
       
   356 	}
       
   357 	
       
   358 void CC32ThreadManager::CC32ThreadInfo::SetModuleNameL(const TDesC8& aModuleName)
       
   359 	{
       
   360 	delete iModuleName;
       
   361 	iModuleName = NULL;
       
   362 	iModuleName = aModuleName.AllocL();
       
   363 	}
       
   364 	
       
   365 CC32ThreadManager::CC32ThreadInfo::~CC32ThreadInfo()
       
   366 	{
       
   367 	delete iModuleName;
       
   368 	}
       
   369 
       
   370 
       
   371 
       
   372 TBool CC32ThreadManager::CC32ThreadInfo::CompareThreadInfo(const CC32ThreadInfo& aFirst,const CC32ThreadInfo& aSecond)
       
   373 // aFirst should always be non-empty. aSecond may be an empty string if it is the dealer entry
       
   374 	{
       
   375 	return (aFirst.iModuleName==aSecond.iModuleName);
       
   376 	}
       
   377 
       
   378 
       
   379 
       
   380 
       
   381 
       
   382 
       
   383 
       
   384 
       
   385 //
       
   386 // CCPMLoader
       
   387 //
       
   388 
       
   389 
       
   390 CC32ThreadManager::CCPMLoader::CCPMLoader()
       
   391     : CActive(EPriorityStandard)
       
   392     {
       
   393     // server is at a super-high priority, so whatever priority we choose is not going to make any difference
       
   394     CActiveScheduler::Add(this);
       
   395 
       
   396     }
       
   397     
       
   398 CC32ThreadManager::CCPMLoader* CC32ThreadManager::CCPMLoader::NewL()
       
   399 	{
       
   400     CCPMLoader* self = new(ELeave) CC32ThreadManager::CCPMLoader();
       
   401 	CleanupStack::PushL(self);
       
   402 	self->ConstructL();
       
   403 	CleanupStack::Pop(self);    
       
   404     return self;
       
   405 	}
       
   406 
       
   407 void CC32ThreadManager::CCPMLoader::ConstructL()
       
   408 	{
       
   409 	TInt ret = iCfgSvr.Connect();
       
   410 	if (ret != KErrNone)
       
   411  		 {
       
   412  		 C32LOG2(KC32Dealer,_L8("CC32Dealer::LoadModule failed during connect to configurator. Code: %d"),ret);
       
   413  		 User::Leave(ret);
       
   414  		 }
       
   415 	}
       
   416 
       
   417 	
       
   418 void CC32ThreadManager::CCPMLoader::DoCancel()
       
   419 	{
       
   420 	C32LOG(KC32Detail,_L8("CC32Dealer::CCPMLoader: DoCancel called"));
       
   421 	
       
   422 	iCfgSvr.CancelLoadCpm(iName);
       
   423 	}
       
   424 	
       
   425 CC32ThreadManager::CCPMLoader::~CCPMLoader()
       
   426     {
       
   427     Cancel();
       
   428     iCfgSvr.Close();
       
   429     // deques on delete of parent
       
   430     }	
       
   431     
       
   432 void CC32ThreadManager::CCPMLoader::RequestModuleLoad(CC32ThreadManager* aThreadMgr, CommsFW::TWorkerId aWorker, const TCFModuleName& aName)
       
   433 // Begin the asynchronous process of loading a player
       
   434 	{
       
   435 	__ASSERT_DEBUG(!IsActive(),Fault(EBadState,_L8("CCPMLoader: Loader already busy with another request when loading module %S. Panicking"),&aName));
       
   436 	
       
   437 	iName = TCFModuleName(aName);    // store so that when we lose stack at this function exit, RRs server can still read data
       
   438 	iThreadManager = aThreadMgr;
       
   439 	iWorkerId = aWorker;
       
   440 
       
   441 	iCfgSvr.LoadCpm(iName,iStatus);
       
   442 	
       
   443 	SetActive();
       
   444 		
       
   445 	C32LOG2(KC32Dealer,_L8("CCPMLoader: Load request for module %S sent to Configurator"),&iName);
       
   446 	}
       
   447 
       
   448 void CC32ThreadManager::CCPMLoader::RunL()
       
   449 // this normally never runs in the success case since new player's response beats it and dealer kills the loader.
       
   450 	{
       
   451 	TInt res = iStatus.Int();
       
   452 
       
   453 	C32LOG4(KC32Dealer,_L8("CC32Dealer: Configurator has completed LoadCPM (%S)(WorkId%d) request with %d"),&iName,iWorkerId,res);
       
   454 	
       
   455 	// assert_debug in here that status is never "already running"
       
   456 	__ASSERT_DEBUG(res != KErrRSModuleAlreadyExist, Fault(EBadState,_L8("CC32Dealer: LoadCPM returned KErrRSModuleAlreadyExists - this is unexpected so Panicking.")));
       
   457 	__ASSERT_DEBUG(res != KErrRSModuleUnknown, Fault(EBadState,_L8("CC32Dealer: LoadCPM returned KErrRSModuleUnknown - probably incorrect CMI file. Panicking.")));
       
   458 	
       
   459 	
       
   460 	// on success there is nothing we need to do with this response - just capture it and log it.
       
   461 	// on failure we clean up.
       
   462 	
       
   463 	if (res==KErrNone)
       
   464 		{
       
   465 		C32LOG2(KC32Detail,_L8("CC32Dealer::LoadCPM: Load for (%S) has been successful"),&iName);
       
   466 		}
       
   467 	else
       
   468 		{
       
   469 		__ASSERT_DEBUG(!iThreadManager->Dealer()->WorkerExists(iWorkerId),Fault(EBadState,_L8("CCPMLoader::RunL - WorkerExists(%d) but configurator returned a failure: %d"),iWorkerId,res));
       
   470 		C32LOG2(KC32Dealer,_L8("CC32Dealer::LoadCPM (%S) has apparently failed so cleaning up pending requests and threadmanager"),&iName);
       
   471 
       
   472 		// give threadmanager a chance to remove any memory we allocated before 
       
   473 		// commencing the module load.
       
   474 		iThreadManager->ProcessModuleLoadFailed(iWorkerId);
       
   475 		
       
   476 		// we now leave ourselves inactive but still valid since we will be needed on the next attempt to load this cpm
       
   477 		// and there is no obvious place to delete ourselves
       
   478 		}
       
   479 	}
       
   480 	
       
   481 
       
   482 
       
   483 
       
   484 //
       
   485 // CC32ThreadManager
       
   486 //
       
   487 
       
   488 CC32ThreadManager::CC32ThreadManager(CC32Dealer* aDealer)
       
   489 	{
       
   490 	iDealer = aDealer;
       
   491 	}
       
   492 	
       
   493 	
       
   494 CC32ThreadManager* CC32ThreadManager::NewL(CC32Dealer* aDealer)
       
   495 	{
       
   496 	CC32ThreadManager* self = new (ELeave) CC32ThreadManager(aDealer);
       
   497 	return self;
       
   498 
       
   499 	}
       
   500 
       
   501 CC32ThreadManager::~CC32ThreadManager()
       
   502 	{
       
   503 	iCSYList.ResetAndDestroy();
       
   504 	iC32ThreadList.ResetAndDestroy();
       
   505 	
       
   506 	for (TInt i=0;i <= KMaxWorkerThreadId ; i++)
       
   507 		{
       
   508 		delete iCPMLoader[i];
       
   509 		}
       
   510 	}
       
   511 	
       
   512 CC32Dealer* CC32ThreadManager::Dealer()
       
   513 	{
       
   514 	__ASSERT_DEBUG(iDealer!=NULL,Fault(EBadState,_L8("CC32ThreadManager: Dealer() - iDealer is NULL. Panicking.")));
       
   515 	return iDealer;
       
   516 	}
       
   517 
       
   518 
       
   519 TWorkerId CC32ThreadManager::DefaultThread()
       
   520 	{
       
   521 	return iDefaultThreadIndex;
       
   522 	}
       
   523 
       
   524 
       
   525 TBool CC32ThreadManager::FindThreadByPortPrefix(const TDesC& aPortName, TWorkerId& aWorker) const
       
   526 // returns EFalse if not found, ETrue otherwise
       
   527 // unloaded csys or csys yet to be loaded have an empty port prefix so will not be found
       
   528 // searching is done in folded way to avoid case problems.
       
   529 	{
       
   530 	TInt idx = 0;
       
   531 	if (&aPortName==NULL)
       
   532 		{
       
   533 		return KErrNotFound;
       
   534 		}
       
   535 		
       
   536 	if (aPortName.Length()==0)
       
   537 		{
       
   538 		return KErrNotFound;
       
   539 		}
       
   540 	
       
   541 	while (idx < iCSYList.Count())
       
   542 		{
       
   543 		if (aPortName.CompareF(iCSYList[idx]->GetPortName())==0)
       
   544 			{
       
   545 			__ASSERT_DEBUG(iCSYList[idx]->IsLoaded(),Fault(EBadState,_L("Panicking due to finding CSY by PortName (%S) that is inactive at index: %d" ),&aPortName,idx));
       
   546 			aWorker=iCSYList[idx]->WorkerId();
       
   547 			return ETrue;
       
   548 			}
       
   549 		idx++;
       
   550 		}
       
   551 		
       
   552 	return EFalse;
       
   553 	}
       
   554 	
       
   555 	
       
   556 	
       
   557 TInt CC32ThreadManager::MapPortprefixToCSYFileName(const TDesC& aPortName, TDes& aCSYFileName)
       
   558 // aPortName is the port prefix format name to search on.
       
   559 // unloaded csys or csys yet to be loaded have an empty port prefix so will not be found.
       
   560 // aCSYFileName - on return contains the filename for the csy with the portprefix
       
   561 // Return: KErrNone if the csy was found, KErrNotFound otherwise.
       
   562 // Panics:
       
   563 //    if aCSYFileName is not long enough to take result.
       
   564 // Returns KErrNotFound in the case of port prefix being null
       
   565 // 
       
   566 	{
       
   567 	TInt idx = 0;
       
   568 	if (&aPortName==NULL)
       
   569 		{
       
   570 		return KErrNotFound;
       
   571 		}
       
   572 	if (aPortName.Length()==0)
       
   573 		{
       
   574 		return KErrNotFound;
       
   575 		}
       
   576 
       
   577 	while (idx < iCSYList.Count())
       
   578 		{
       
   579 		if (aPortName.CompareF(iCSYList[idx]->GetPortName())==0)
       
   580 			{
       
   581 			__ASSERT_DEBUG(iCSYList[idx]->IsLoaded(),Fault(EBadState,_L("Panicking due to finding CSY by PortName (%S) that is inactive at index: %d" ),&aPortName,idx));
       
   582 			aCSYFileName.Copy(*iCSYList[idx]->GetCSYName());
       
   583 			return KErrNone;
       
   584 			}
       
   585 		idx++;
       
   586 		}
       
   587 		
       
   588 	return KErrNotFound;
       
   589 	}
       
   590 	
       
   591 	
       
   592 	
       
   593 TBool CC32ThreadManager::FindThreadByFileName(const TDesC8& aCSYFileName8, TWorkerId &aWorkerId) const
       
   594 // Find thread that would house this CSY, if no match found, return EFalse
       
   595 // CSYFilename - CSY name with extension
       
   596 	{
       
   597 	TInt idx = 0;
       
   598 	while (idx < iCSYList.Count())
       
   599 		{
       
   600 		if (aCSYFileName8.CompareF(*iCSYList[idx]->GetCSYName())==0)
       
   601 			{
       
   602 			aWorkerId = iCSYList[idx]->WorkerId();
       
   603 			return ETrue;
       
   604 			}
       
   605 		idx++;
       
   606 		}
       
   607 		
       
   608 	return EFalse;	
       
   609 	}
       
   610 
       
   611 TBool CC32ThreadManager::FindThreadOfActiveCSYByName(const TDesC& aName, TWorkerId& aWorkerId) const	// GetPortInfo(aName) version, TWorkerId filled with worker
       
   612 // find thread by filename of CSY, if not found try by portnam of CSY.
       
   613 // only searches active CSYs
       
   614 // aName - portprefix or filename of csy to find
       
   615 // aWorkerId - on return contains workerId, unchanged if result is EFalse
       
   616 // returns: ETrue if found, EFalse otherwise
       
   617 	{
       
   618 	TBuf8<KMaxFileName> nameWithExt8;
       
   619 	nameWithExt8.Copy(aName);
       
   620 	
       
   621 	 TInt r=nameWithExt8.LocateReverse('.');
       
   622 	 if (r==KErrNotFound)
       
   623  		 {
       
   624  		 if (nameWithExt8.Length()>KMaxFileName - (TInt)KCSYExtension8.iTypeLength)		 // valid filename is checked here
       
   625 	 		 {
       
   626 	 		 return EFalse;
       
   627 	 		 }
       
   628  		 nameWithExt8.Append(KCSYExtension8);
       
   629  		 }
       
   630 	
       
   631 	
       
   632 	TInt idx = 0;
       
   633 	while (idx < iCSYList.Count())
       
   634 		{
       
   635 		if (iCSYList[idx]->IsLoaded() && ((aName.CompareF(iCSYList[idx]->GetPortName())==0) || (nameWithExt8.CompareF(*iCSYList[idx]->GetCSYName())==0)))
       
   636 			{
       
   637 			aWorkerId = iCSYList[idx]->WorkerId();
       
   638 			return ETrue;
       
   639 			}
       
   640 		idx++;
       
   641 		}
       
   642 
       
   643 	return EFalse;
       
   644 	}
       
   645 
       
   646 TInt CC32ThreadManager::FindThreadByGlobalIndex(const TInt aIndex) const
       
   647 // aIndex is the array position the CSY would be in if it were in the old portmanager structure
       
   648 // This function returns zero or a positive integer if the global index refers to a loaded
       
   649 // csy. If not, then KErrNotFound is returned.
       
   650 
       
   651 	{
       
   652 	__ASSERT_DEBUG(aIndex >= 0,Fault(EBadState));
       
   653 	TInt absIdx = 0;
       
   654 	while (absIdx < iCSYList.Count())
       
   655 		{
       
   656 		if (iCSYList[absIdx]->IsLoaded())
       
   657 			{
       
   658 			if (iCSYList[absIdx]->LoadIndex()==aIndex)
       
   659 				{
       
   660 				return iCSYList[absIdx]->WorkerId();
       
   661 				}
       
   662 			}
       
   663 		absIdx++;
       
   664 		}
       
   665 		
       
   666 	
       
   667 	return KErrNotFound;
       
   668 	}
       
   669 
       
   670 CSerial* CC32ThreadManager::GetSerialObjectFromCSYFileName(const TDesC& aCSYFileName)
       
   671 // We might be asked to do an update even for a CSY that has been loaded since all CSY load requests are
       
   672 // passed through to the player. This is because player needs to record each session that loads the module.
       
   673 	{
       
   674 	TBuf8<KMaxFileName> fileName8;   // convert 16 to 8-bit string. huge stack usage, but no other way
       
   675 	fileName8.Copy(aCSYFileName);
       
   676 	TInt idx = 0;
       
   677 	
       
   678 	while (idx < iCSYList.Count())
       
   679 		{
       
   680 		if (fileName8.CompareF(*iCSYList[idx]->GetCSYName())==0)
       
   681 			{
       
   682 			C32LOG1(KC32Detail, _L8("CC32ThreadManager::GetSerialObjectFromCSYFileName()"));
       
   683 			return iCSYList[idx]->GetCSYHandle();
       
   684 			}
       
   685 		else
       
   686 			{
       
   687 			idx++;
       
   688 			}
       
   689 		}	
       
   690 	return NULL;
       
   691 	}
       
   692 
       
   693 CSerial* CC32ThreadManager::GetSerialL(const TDesC& aPortName)
       
   694 	{
       
   695 	TInt idx;
       
   696 	User::LeaveIfError(GetIndexFromPortPrefix(aPortName, idx));
       
   697 	return GetSerialObjectByIndex(idx);
       
   698 	}
       
   699 
       
   700 TInt CC32ThreadManager::GetIndexFromPortPrefix(const TDesC& aPortName, TInt& aIndex)
       
   701 	{
       
   702 	TInt idx = 0;
       
   703 	
       
   704 	while (idx < iCSYList.Count())
       
   705 		{
       
   706 		if (aPortName.CompareF(iCSYList[idx]->GetPortName())==0)
       
   707 			{
       
   708 			C32LOG1(KC32Detail, _L8("CC32ThreadManager::GetIndexFromPortPrefix()"));
       
   709 			aIndex = idx;
       
   710 			return KErrNone;
       
   711 			}
       
   712 		else
       
   713 			{
       
   714 			idx++;
       
   715 			}
       
   716 		}	
       
   717 	return KErrNotFound;
       
   718 	}
       
   719 
       
   720 CSerial* CC32ThreadManager::GetSerialObjectByIndex(TInt aIndex)
       
   721 	{
       
   722 	return iCSYList[aIndex]->GetCSYHandle();
       
   723 	}
       
   724 
       
   725 TInt CC32ThreadManager::IncrementCountOnLoad(const TDesC& aCSYFileName)
       
   726 	{
       
   727 	TBuf8<KMaxFileName> fileName8;   // convert 16 to 8-bit string. 
       
   728 	fileName8.Copy(aCSYFileName);
       
   729 	TInt idx = 0;
       
   730 	
       
   731 	while (idx < iCSYList.Count())
       
   732 		{
       
   733 		if (fileName8.CompareF(*iCSYList[idx]->GetCSYName())==0)
       
   734 			{
       
   735 			iCSYList[idx]->IncAccessCount();
       
   736 			C32LOG3(KC32Detail, _L8("CC32ThreadManager::IncrementCountOnCSYLoad() AccessCount for %S CSY = %d"), &fileName8, iCSYList[idx]->AccessCount() );
       
   737 			return KErrNone;
       
   738 			}
       
   739 		else
       
   740 			{
       
   741 			idx++;
       
   742 			}
       
   743 		}	
       
   744 	return KErrNotFound;
       
   745 	}
       
   746 
       
   747 TInt CC32ThreadManager::DecrementCountOnCSYUnLoad(const TDesC& aCSYFileName)
       
   748 	{
       
   749 	TBuf8<KMaxFileName> fileName8;   // convert 16 to 8-bit string. 
       
   750 	fileName8.Copy(aCSYFileName);
       
   751 	TInt idx = 0;
       
   752 	
       
   753 	while (idx < iCSYList.Count())
       
   754 		{
       
   755 		if (fileName8.CompareF(*iCSYList[idx]->GetCSYName())==0)
       
   756 			{
       
   757 			if(iCSYList[idx]->AccessCount()==1)
       
   758 				{
       
   759 				// unload CSY as all sesions have unloaded CSYs or closed now.
       
   760 				UpdateThreadManagerOnCSYUnload(fileName8);
       
   761 				}
       
   762 			iCSYList[idx]->DecAccessCount();
       
   763 			C32LOG3(KC32Detail, _L8("CC32ThreadManager::DecrementCountOnCSYUnLoad() AccessCount for %S CSY = %d"), &fileName8, iCSYList[idx]->AccessCount() );
       
   764 			return KErrNone;
       
   765 			}
       
   766 		else
       
   767 			{
       
   768 			idx++;
       
   769 			}
       
   770 		}	
       
   771 	return KErrNotFound;
       
   772 	}
       
   773 
       
   774 
       
   775 TInt CC32ThreadManager::GrowCSYPortNameToMaximumIfNotLoaded(const TDesC& aCSYFileName)
       
   776 	{
       
   777 	TBuf8<KMaxFileName> fileName8;   // convert 16 to 8-bit string. 
       
   778 	fileName8.Copy(aCSYFileName);
       
   779 	TInt idx = 0;
       
   780 	
       
   781 	while (idx < iCSYList.Count())
       
   782 		{
       
   783 		if (fileName8.CompareF(*iCSYList[idx]->GetCSYName())==0)
       
   784 			{
       
   785 			if (!iCSYList[idx]->IsLoaded())
       
   786 				{
       
   787 				return iCSYList[idx]->SetPortNameSizeToMaximum();
       
   788 				}
       
   789 			else
       
   790 				{
       
   791 				return KErrNone;
       
   792 				}
       
   793 			}
       
   794 		else
       
   795 			{
       
   796 			idx++;
       
   797 			}
       
   798 		}	
       
   799 	return KErrNotFound;
       
   800 	}
       
   801 
       
   802 
       
   803 TInt CC32ThreadManager::RequestLoadModule(CommsFW::TWorkerId aWorker)
       
   804 	{
       
   805 	TInt ret = KErrNone;
       
   806 	
       
   807 	__ASSERT_DEBUG(!Dealer()->WorkerExists(aWorker),Fault(EBadState,_L8("CC32ThreadManager::RequestLoadModule: Worker already Exists! Panicking")));
       
   808 
       
   809 	
       
   810 	// loader may already exist but be inactive if a previous load attempt failed
       
   811 	if (iCPMLoader[aWorker] == NULL)
       
   812 		{
       
   813 		C32LOG3(KC32Detail,_L8("ThreadMgr::RequestLoadModule: Loader doesn't exist for worker %d (%S). Starting worker"),aWorker,GetModuleName(aWorker));
       
   814 		TRAP(ret,iCPMLoader[aWorker] = CCPMLoader::NewL());
       
   815 		if (ret != KErrNone)
       
   816 			{
       
   817 			C32LOG2(KC32Detail,_L8("CCPMLoader::NewL() leave occured (%d)"),ret);
       
   818 			return ret;
       
   819 			}
       
   820 		iCPMLoader[aWorker]->RequestModuleLoad(this,aWorker,*GetModuleName(aWorker));
       
   821 		}
       
   822 	else if (!iCPMLoader[aWorker]->IsActive())
       
   823 		{
       
   824 		C32LOG3(KC32Detail,_L8("CC32ThreadManager: Inactive Loader already exists - reusing to start worker %d (%S)."),aWorker,GetModuleName(aWorker));
       
   825 		
       
   826 		iCPMLoader[aWorker]->RequestModuleLoad(this,aWorker,*GetModuleName(aWorker));
       
   827 		}
       
   828 	else
       
   829 		{
       
   830 		C32LOG2(KC32Detail,_L8("ThreadMgr: RequestLoadModule: Attempt to start worker %d ignored due to already outstanding load- dealer should queue this req."),aWorker);
       
   831  		// if timer is already running, we assume load still in progress so we just exit
       
   832  		// and caller can queue request
       
   833 		ret=KErrInUse;
       
   834 		}
       
   835 	return ret;
       
   836 	}
       
   837 
       
   838 
       
   839 void CC32ThreadManager::ProcessModuleLoadFailed(CommsFW::TWorkerId aWorker)
       
   840 // called from LoadCPM when configurator reports that player has failed to start
       
   841 // Gives thread manager a chance to do any cleanup.
       
   842 	{
       
   843 	C32LOG2(KC32Dealer,_L8("CC32ThreadManager:ProcessModuleLoadFailed: Failed worker was %d. Cleaning up pending requests."),aWorker);
       
   844 	
       
   845 	// give dealer a chance to remove any pending requests for the module which did not start
       
   846 	// and undo any memory allocations done as part of load
       
   847 	Dealer()->ProcessFailedPlayerLoad(aWorker);
       
   848 
       
   849 	}
       
   850 
       
   851 
       
   852 void CC32ThreadManager::ProcessModuleLoadSuccess(CommsFW::TWorkerId aWorker)
       
   853 // called when dealer receives introduction msg from player, regardless of how player started
       
   854 	{
       
   855 	C32LOG2(KC32Detail, _L8("CC32ThreadManager::ProcessModuleLoadSuccess for worker %d. Deleting CPMLoader."), aWorker);
       
   856 	
       
   857 	// Delete the load Active object. It turns out that normally by this point the configurator has yet to complete the request,
       
   858 	// even though the player is already running, so by removing the loader here, we will be sending a Cancel to the configurator
       
   859 	// for an operation we know has already completed successfully. This is safe (view a request as consisting of two parts
       
   860 	// - 1) ask a server to make a request and 2) hope the server will let you know how it goes - we are
       
   861 	// now simply cancelling part 2 since we know how part 1 went)
       
   862 	
       
   863 	delete iCPMLoader[aWorker];
       
   864 	iCPMLoader[aWorker] = NULL;
       
   865 	
       
   866 	}
       
   867 
       
   868 
       
   869 
       
   870 void CC32ThreadManager::UpdateThreadManagerOnCSYUnload(const TDesC8& aCSYFileName8)
       
   871 // called when we predict Player will unload CSY, since the indexing of the CSYs and the auto-close on index 0 behaviour
       
   872 // that the player uses (preserved legacy C32 behaviour) does not give an opportunity for this process to be intercepted
       
   873 // on player side and a mesg sent to dealer.
       
   874 	{
       
   875 	TInt idx = 0;	
       
   876 	
       
   877 	// NULL CSerial* and Portname
       
   878 	C32LOG2(KC32Detail, _L8("CC32ThreadManager::UpdateThreadManagerOnCSYUnLoad() for %S"), &aCSYFileName8);
       
   879 	while (idx < iCSYList.Count())
       
   880 		{
       
   881 		if (aCSYFileName8.CompareF(*iCSYList[idx]->GetCSYName())==0)
       
   882 			{
       
   883 			__ASSERT_DEBUG(iCSYList[idx]->IsLoaded(),Fault(EBadState,_L8("UpdateThreadManagerOnCSYUnLoad: CSY marked as not loaded on call to update after unload. Panicking.")));
       
   884 			iCSYList[idx]->SetPortName(KNullDesC16);
       
   885 			iCSYList[idx]->SetCSYHandle(NULL);
       
   886 			iCSYList[idx]->SetLoadState(EFalse);
       
   887 			
       
   888 			// run thru list and adjust index numbers now that this csy has unloaded
       
   889 			for (TInt absIdx = 0; absIdx < iCSYList.Count(); ++absIdx)
       
   890 				{
       
   891 				if ((iCSYList[absIdx]->IsLoaded() && (iCSYList[absIdx]->LoadIndex() > iCSYList[idx]->LoadIndex())))
       
   892 					{
       
   893 					iCSYList[absIdx]->SetLoadIndex(iCSYList[absIdx]->LoadIndex()-1);
       
   894 					}
       
   895 				}
       
   896 			
       
   897 			iCSYList[idx]->SetLoadIndex(-1);
       
   898 			--iNumLoadedModules;
       
   899 
       
   900 			return;
       
   901 			}
       
   902 		else
       
   903 			{
       
   904 			idx++;
       
   905 			}
       
   906 		}	
       
   907 	
       
   908 	C32LOG2(KC32Warning,_L8("UpdateThreadManagerOnCSYUnload: Could not find CSY supposedly unloaded: %S. Will Panic in debug."),&aCSYFileName8);
       
   909 	__ASSERT_DEBUG(0,Fault(EBadState));
       
   910 	}
       
   911 
       
   912 void CC32ThreadManager::UpdateThreadManagerOnCSYLoad(const TDesC& aCSYFileName, const TDesC& aPortPrefix, CSerial* aSerial)
       
   913 // We might be asked to do an update even for a CSY that has been loaded since all CSY load requests are
       
   914 // passed through to the player. This is because player needs to record each session that loads the module.
       
   915 	{
       
   916 	TBuf8<KMaxFileName> fileName8;   // convert 16 to 8-bit string. huge stack usage, but no other way
       
   917 	fileName8.Copy(aCSYFileName);
       
   918 	TInt idx = 0;
       
   919 	
       
   920 
       
   921 	// we update the csyinfo with the new serial and port prefix and mark it active
       
   922 
       
   923 	while (idx < iCSYList.Count())
       
   924 		{
       
   925 		if (fileName8.CompareF(*iCSYList[idx]->GetCSYName())==0)
       
   926 			{
       
   927 			if (iCSYList[idx]->IsLoaded()==EFalse)
       
   928 				{
       
   929 				C32LOG5(KC32Detail, _L("C32ThrdMg::UpdateThreadManagerOnCSYLoad() for CSY[%d](%S).CSerial=%x. PortPrefix=%S"),idx,&aCSYFileName,aSerial,&aPortPrefix);
       
   930 				iCSYList[idx]->SetPortName(aPortPrefix);
       
   931 				iCSYList[idx]->SetCSYHandle(aSerial);
       
   932 				iCSYList[idx]->SetLoadState(ETrue);
       
   933 				
       
   934 				iCSYList[idx]->SetLoadIndex(iNumLoadedModules);
       
   935 				++iNumLoadedModules;
       
   936 				}
       
   937 			else
       
   938 				{
       
   939 				C32LOG3(KC32Detail, _L8("CC32ThreadManager::UpdateThreadManagerOnCSYLoad(): CSY[%d] already updated. Access count is %d"),idx,iCSYList[idx]->AccessCount());
       
   940 				}
       
   941 			return;
       
   942 			}
       
   943 		else
       
   944 			{
       
   945 			idx++;
       
   946 			}
       
   947 		}
       
   948 		
       
   949 		
       
   950 	C32LOG2(KC32Warning,_L8("UpdateThreadManagerOnCSYLoad: Could not find CSY supposedly loaded: %S. Will panic in debug."),&fileName8);
       
   951 	__ASSERT_DEBUG(0,Fault(EBadState));
       
   952 	}
       
   953 
       
   954 void CC32ThreadManager::UpdateThreadManagerOnCSYLoadFailure(const TDesC& aCSYFilename)
       
   955 // called to allow thread manager to clean up any allocations made prior to attempting CSY load.
       
   956 // aCSYFilename - name with extension of CSY that player failed to load
       
   957 	{
       
   958 	CommsFW::TWorkerId worker;
       
   959 	
       
   960 	TBuf8<KMaxFileName> fileName8;   // convert 16 to 8-bit string. huge stack usage, but no other way
       
   961 	fileName8.Copy(aCSYFilename);
       
   962 
       
   963 	
       
   964 	TBool found = FindThreadByFileName(fileName8,worker);
       
   965 	
       
   966 	// it is possible we would not find it if two sessions had requested this csy load at same time and
       
   967 	// this is now the completion of the second sessions load attempt and the first session cleanup
       
   968 	// had destroyed the csyInfo.
       
   969 	if (found)
       
   970 		{
       
   971 		// if this was default thread we might have
       
   972 		// added an unknown CSY so in this case remove it. It does no harm if this CSY was specified in CMI
       
   973 		// file since on next attempt thread manager will place the CSY in same thread anyway.
       
   974 		
       
   975 		if (worker == iDefaultThreadIndex)
       
   976 			{
       
   977 			for (TInt i=0; i < iCSYList.Count(); i++)
       
   978 				{
       
   979 				// comparing the worker Ids first is a bit quicker
       
   980 				if (iCSYList[i]->WorkerId()==worker)
       
   981 					{
       
   982 					if (iCSYList[i]->GetCSYName()->Compare(fileName8)==0)
       
   983 						{
       
   984 						__ASSERT_DEBUG(!iCSYList[i]->IsLoaded(),Fault(EBadState,_L8("CC32ThreadManager::UpdateThreadManagerOnCSYLoadFailure: CSY[%d] is marked as loaded! Panicking."),i));
       
   985 						C32LOG3(KC32Dealer,_L("CC32ThreadManager::UpdateThreadManagerOnCSYLoadFailure: Failed CSY (%S) was for default thread. Deleting CSY[%d]"),&aCSYFilename,i);
       
   986 						delete iCSYList[i];
       
   987 						iCSYList.Remove(i);
       
   988 						return;
       
   989 						}
       
   990 					}
       
   991 				}
       
   992 			C32LOG2(KC32Dealer,_L("CC32ThreadManager::UpdateThreadManagerOnCSYLoadFailure: Failed CSY (%S) was for default thread but could not find. Will panic in debug."),&aCSYFilename);
       
   993 			__ASSERT_DEBUG(0,User::Invariant());
       
   994 			}
       
   995 		}
       
   996 	else
       
   997 		{
       
   998 		C32LOG2(KC32Dealer,_L("CC32ThreadManager::UpdateThreadManagerOnCSYLoadFailure: Failed CSY record (%S) was not found so assuming another request deleted it"),&aCSYFilename);
       
   999 		}
       
  1000 	}
       
  1001 
       
  1002 
       
  1003 CSerial* CC32ThreadManager::FindSerialObjectByGlobalIndex(const TInt aIndex) const
       
  1004 // aIndex is the array position the CSY would be in if it were in the old portmanager structure
       
  1005 // this is now the position of the csy in the active array
       
  1006 // index should be valid so panic if not
       
  1007 	{
       
  1008 		
       
  1009 	TInt absIdx = 0;
       
  1010 	while (absIdx < iCSYList.Count())
       
  1011 		{
       
  1012 		if (iCSYList[absIdx]->IsLoaded())
       
  1013 			{
       
  1014 			if (iCSYList[absIdx]->LoadIndex()==aIndex)
       
  1015 				{
       
  1016 				return iCSYList[absIdx]->GetCSYHandle();
       
  1017 				}
       
  1018 			else
       
  1019 				{
       
  1020 				absIdx++;
       
  1021 				}
       
  1022 			}
       
  1023 		else
       
  1024 			{
       
  1025 			absIdx++;
       
  1026 			}
       
  1027 		}
       
  1028 		
       
  1029 	C32LOG2(KC32Warning,_L8("FindSerialObjectByGlobalIndex - Panicking due to index out of range: %d"),aIndex);
       
  1030 	__ASSERT_ALWAYS(0,Fault(EBadState));
       
  1031 	
       
  1032 	return NULL;
       
  1033 	}
       
  1034 	
       
  1035 const HBufC8* CC32ThreadManager::GetModuleName(TWorkerId aWorkerId)
       
  1036 // aWorkerId assumed to be valid
       
  1037 	{
       
  1038 	return iC32ThreadList[aWorkerId]->ModuleName();
       
  1039 	}
       
  1040 	
       
  1041 
       
  1042 #ifdef __FLOG_ACTIVE
       
  1043 void CC32ThreadManager::DumpThreadInfoAndCSYLists()
       
  1044 	{
       
  1045 	//log in Detail mode only
       
  1046 	
       
  1047 	C32LOG(KC32Detail,_L8("---- Dump of C32 Thread Manager ----"));
       
  1048 	C32LOG2(KC32Detail,_L8("Default Thread: %d"),iDefaultThreadIndex);
       
  1049 	TBuf8<KMaxFullName> shortName8; // TPortName is, rather annoyingly given it probably never needs to be, a 16-bit descriptor
       
  1050 	
       
  1051 	for (TInt i=0;i < iCSYList.Count();i++)
       
  1052 		{
       
  1053 		shortName8.Copy(iCSYList[i]->GetPortName());
       
  1054 		C32LOG8(KC32Detail,_L8("CSY List [%d].CSY Name:%S,ShrtNm:%S,ThrdID:%d,PlyrHdl:%x,Active:%d,Idx:%d"),i,iCSYList[i]->GetCSYName(),&shortName8,iCSYList[i]->WorkerId(),iCSYList[i]->GetCSYHandle(),iCSYList[i]->IsLoaded(),iCSYList[i]->LoadIndex());
       
  1055 		}
       
  1056 
       
  1057 	TBool globalsExist = Dealer()->WorkerDataGlobalsExist();
       
  1058 	if (globalsExist)
       
  1059 		{
       
  1060 		C32LOG(KC32Detail,_L8("Thread List start."));		
       
  1061 		}
       
  1062 	else
       
  1063 		{
       
  1064 		C32LOG(KC32Detail,_L8("Thread List start. Still booting so don't know player thread status yet."));
       
  1065 		}
       
  1066 		
       
  1067 	for (TInt k=0;k < iC32ThreadList.Count(); k++)
       
  1068 		{
       
  1069 		if (iC32ThreadList[k]==NULL)
       
  1070 			{
       
  1071 			C32LOG2(KC32Warning,_L8("DumpThreadInfo: Internal check failure: Found NULL record at WorkerId: %d"),k);
       
  1072 #ifdef _DEBUG
       
  1073 			Fault(EBadState); // panic
       
  1074 #endif
       
  1075 			}
       
  1076 		else if (iC32ThreadList[k]->ModuleName()->CompareF(KNullDesC8)==0)
       
  1077 			{
       
  1078 			if (k==0)
       
  1079 				{
       
  1080 				C32LOG(KC32Detail,_L8("Thread List[0]:Blank (This is normal)"));
       
  1081 				}
       
  1082 			else
       
  1083 				{
       
  1084 				C32LOG2(KC32Warning,_L8("DumpThreadInfo: Internal check failure: Found blank record for a player at WorkerId: %d"),k);
       
  1085 				C32LOG1(KC32Warning,_L8("DumpThreadInfo: This indicates missing cmi file for this workerId. Continuing since this could be a test scenario."));
       
  1086 				// there is no panic here since we allow blanks in case user is mix-and-matching csys to threads
       
  1087 				}
       
  1088 			}
       
  1089 		else
       
  1090 			{
       
  1091 			if (globalsExist)
       
  1092 				{
       
  1093 				C32LOG4(KC32Detail,_L8("Thread List[%d]:Name:%S. Running:%d"),k,iC32ThreadList[k]->ModuleName(),Dealer()->WorkerExists(k));
       
  1094 				}
       
  1095 			else
       
  1096 				{
       
  1097 				C32LOG3(KC32Detail,_L8("Thread List[%d]:Name:%S. Dealer still starting so Running Status unknown."),k,iC32ThreadList[k]->ModuleName());
       
  1098 				}
       
  1099 			}
       
  1100 		}
       
  1101 
       
  1102 	C32LOG(KC32Detail,_L8("---- End Dump of C32 Thread Manager ----"));
       
  1103 	
       
  1104 	
       
  1105 	
       
  1106 	}
       
  1107 #endif	
       
  1108 
       
  1109 
       
  1110 void CC32ThreadManager::LoadCMIDataL(const TDesC8& aDealerIniData)
       
  1111 // load all the data from the CMI files.
       
  1112 // aCSYList provides us with the data for the dealer, but we have to query the Configurator for all 
       
  1113 // the data for the player cmis.
       
  1114 	{
       
  1115 
       
  1116 	TInt ret;
       
  1117 	TRSIter iter;
       
  1118 
       
  1119 
       
  1120 	TCFModuleName moduleName;    // as specified in CMI file
       
  1121 	RArray<TInt>		numCSYsPerCMI;  // used if we find two CSYs the same. Filled in as each
       
  1122 	                                    // cmi processed so that index of element is threadnum, 
       
  1123 	                                    // and value is number of CSYs in that threadnum.
       
  1124 	CleanupClosePushL(numCSYsPerCMI);
       
  1125 	
       
  1126 	TBool skipThisCMI;    // the CMI is a dealer or somehow invalid beyond redemption
       
  1127 	
       
  1128 	CC32ParsedIniData* iniDataParser;
       
  1129 
       
  1130 	RBuf8 iniData;      // to accept data from the configurator
       
  1131 	TInt iniBufSize;   // tracks size of ini data buffer as we grow it
       
  1132 	
       
  1133 	RRsConfigurator cfgSvr;
       
  1134 	
       
  1135 	User::LeaveIfError(cfgSvr.Connect());
       
  1136 	CleanupClosePushL(cfgSvr); 
       
  1137 	
       
  1138 
       
  1139 	iniBufSize=KIniDataBufSizeIncrement;
       
  1140 	iniData.CreateL(iniBufSize);
       
  1141 	iniData.CleanupClosePushL();
       
  1142 	
       
  1143 	CC32ThreadInfo* newThreadRec;
       
  1144 	CC32ThreadInfo* blankThreadRec; // we used to insert NULLs, but inserting this blank is a bit safer/easier to work with.
       
  1145 	
       
  1146 	// KMaxTUint16 magic value indicates no default thread has been identified - need to use unsigned value because
       
  1147 	// TWorkerID is now an unsigned type.
       
  1148 	iDefaultThreadIndex = KMaxTUint16;
       
  1149 	
       
  1150 	// process the dealer's own cmi data. Will leave if the cmi data is bad, unless
       
  1151 	// we are the dealer.
       
  1152 	iniDataParser = CC32ParsedIniData::NewL(aDealerIniData,ETrue);
       
  1153 	CleanupStack::PushL(iniDataParser);
       
  1154 	
       
  1155 
       
  1156 	// add a record to the threadlist so that we have index 0 - it is irrelevant what we put in here
       
  1157 	// so we will make the string an empty string since we won't ever use it - Dealer is always running!
       
  1158 	// It has to be a valid string (so not null) otherwise the comparison (CompareThreadInfo) fails the type check.
       
  1159 	blankThreadRec = CC32ThreadInfo::NewL(KNullDesC8);
       
  1160 	ret = iC32ThreadList.Append(blankThreadRec); //transfer ownership
       
  1161 	if (ret != KErrNone)
       
  1162 		{
       
  1163 		delete blankThreadRec;
       
  1164 		User::Leave(ret);
       
  1165 		}
       
  1166 	blankThreadRec=NULL;
       
  1167 	
       
  1168 	__ASSERT_DEBUG(iC32ThreadList.Count()==1,Fault(EBadState));
       
  1169 	
       
  1170 	if (iniDataParser->IsDefaultThread())
       
  1171 		{
       
  1172 		iDefaultThreadIndex = KMainThreadId;
       
  1173 		}
       
  1174 		
       
  1175 	
       
  1176 	
       
  1177 	for (TInt i=0 ; i < iniDataParser->NumCSYs(); i++)
       
  1178 		{
       
  1179 		TBuf8<KMaxFileName> csyFilename;
       
  1180 		csyFilename.Copy(iniDataParser->iCSYs[i]);
       
  1181 		TInt r=csyFilename.LocateReverse('.');
       
  1182 	 	if (r==KErrNotFound)
       
  1183 			{
       
  1184 			if (csyFilename.Length()>KMaxFileName - (TInt)KCSYExtension8.iTypeLength)
       
  1185 				{
       
  1186 				C32LOG2(KC32Warning,_L("LoadCMIDataL: Corrupt [IniData] section: Dealer has a CSY that is too big: %S. Will panic in debug."),&iniDataParser->iCSYs[i]);
       
  1187 				__ASSERT_DEBUG(0,Fault(EBadIniData));
       
  1188 				_LIT8(KCSYDudName, "BadCsy" );
       
  1189 				csyFilename.Copy(KCSYDudName());  // continue with a dud record
       
  1190 				}
       
  1191 			csyFilename.Append(KCSYExtension8);
       
  1192 			}
       
  1193 		
       
  1194 		CCSYInfo* csyInfoRec = CCSYInfo::NewL(csyFilename, KMainThreadId);
       
  1195 		CleanupStack::PushL(csyInfoRec);
       
  1196 		
       
  1197 		ret = iCSYList.InsertInOrder(csyInfoRec, TLinearOrder<CCSYInfo>(&CCSYInfo::CompareCSYInfo));
       
  1198 		
       
  1199 		if (ret == KErrAlreadyExists)
       
  1200 			{
       
  1201 			C32LOG2(KC32Warning,_L8("LoadCMIDataL: Corrupt [IniData] section: Dealer has the same CSY listed twice: %S"),&iniDataParser->iCSYs[i]);
       
  1202 #ifdef _DEBUG
       
  1203 			Fault(EBadIniData); // panic
       
  1204 #endif
       
  1205 
       
  1206 			// ignore and carry on
       
  1207 			CleanupStack::PopAndDestroy(csyInfoRec); // dont need duplicate further
       
  1208 			}
       
  1209 		else if (ret != KErrNone)
       
  1210 			{
       
  1211 			User::Leave(ret);
       
  1212 			} 
       
  1213 		else
       
  1214 			{
       
  1215 			// ownership transferred
       
  1216 			CleanupStack::Pop(csyInfoRec);
       
  1217 			}
       
  1218 		}
       
  1219 
       
  1220 	CleanupStack::PopAndDestroy(iniDataParser);
       
  1221 
       
  1222 	
       
  1223 	// iterate through all the CMI files
       
  1224 	// Any CMI data sections that don't have "Role=Player" are ignored. Dealer CMIs can be ignored
       
  1225 	// since we processed our dealer's cmi above.
       
  1226 
       
  1227 	// If we find two CMI files with the same module name we fault.
       
  1228 	// The order we find them is the order that Configurator supplies them to us - it is probably alphabetical.
       
  1229 	// If we see the wildcard twice, we process it only the first time.
       
  1230 	// If we do not see the wildcard we make the first player the wildcard thread, or the dealer if no players.
       
  1231 	// If a player has no CSYs, we ignore it.
       
  1232 	
       
  1233 	// We do this in one pass:
       
  1234 	// 1. Read records from each CMI file as they come and add them to the structure. If the thread has no number,
       
  1235 	//    or a duplicate number, or "0" (which should be the dealer) we fault.
       
  1236 	//    After each
       
  1237 	//    CMI file is complete we record the total number of CSYs added for that thread. Before adding
       
  1238 	//    each CSY we scan the list to ensure that CSY has not already been added. If so, then we
       
  1239 	//    move it to whichever of the two threads it is allocated to that has the least number of CSYs.
       
  1240 	//
       
  1241 	// As a small efficiency gain, since we may be searching the CSY names many times we order the 
       
  1242 	// CSY list by CSY name. This order is not preserved once we've finished parsing the CMI files - ie,
       
  1243 	// further discovered csys through loading are simply appended to the end.
       
  1244 	// An efficincy improvement would be to parse the ini data sequentially. At the moment we reuse the commsfw ini
       
  1245 	// file parsing routine but this would re-read the data each time.
       
  1246 	// Also, a bit of string copying goes on so this could potentially be reduced.
       
  1247 	
       
  1248 	
       
  1249 	while ( cfgSvr.EnumerateModules(_L8("C32SerComms"),iter,moduleName) == KErrNone)
       
  1250 		{
       
  1251 	
       
  1252 		//keep enlarging inidata buffer until we get it big enough
       
  1253 		ret=cfgSvr.GetModuleIniData(moduleName, iniData, iniBufSize);
       
  1254 		if (ret==KErrOverflow)
       
  1255 			{
       
  1256 			iniData.ReAllocL(iniBufSize);
       
  1257 			ret=cfgSvr.GetModuleIniData(moduleName, iniData, iniBufSize);
       
  1258 			}
       
  1259 		User::LeaveIfError(ret);
       
  1260 
       
  1261 		skipThisCMI=EFalse;
       
  1262 		
       
  1263 		// if it leaves we check it was due to corrupt data and continue since we can cope
       
  1264 		// with all corrupt data cases
       
  1265 		C32LOG2(KC32Bootup,_L8("LoadCMIDataL: Parsing inidata for module %S"),&moduleName);
       
  1266 		TRAP(ret,iniDataParser = CC32ParsedIniData::NewL(iniData,EFalse));
       
  1267 		CleanupStack::PushL(iniDataParser);
       
  1268 
       
  1269 		
       
  1270 		if ((ret != KErrNone) && (ret != KErrCorrupt))
       
  1271 			{
       
  1272 			User::Leave(ret);
       
  1273 			}
       
  1274 		else
       
  1275 			{
       
  1276 			__ASSERT_DEBUG(iniDataParser,Fault(ESvrStartServer));
       
  1277 			}
       
  1278 
       
  1279 		if (iniDataParser->IsPlayer())
       
  1280 			{
       
  1281 			newThreadRec = CC32ThreadInfo::NewL(moduleName);
       
  1282 			CleanupStack::PushL(newThreadRec);
       
  1283 			
       
  1284 			if (iC32ThreadList.Find(newThreadRec, TIdentityRelation<CC32ThreadInfo>(&CC32ThreadInfo::CompareThreadInfo)) != KErrNotFound)
       
  1285 				{
       
  1286 				// unfortunately there is a rare circumstance where we may miss a duplicate. If the dealer
       
  1287 				// is not part of the group, and then a member in the group has
       
  1288 				// the same name, we won't spot this. only configurator can detect this.
       
  1289 				C32LOG(KC32Warning,_L8("LoadCMIDataL: Corrupt IniData found - duplicate module name."));
       
  1290 #ifdef _DEBUG
       
  1291 				Fault(EBadIniData); // panic
       
  1292 #endif
       
  1293 				User::Leave(KErrCorrupt);
       
  1294 				}
       
  1295 				
       
  1296 			if ((iniDataParser->NumCSYs() < 1) && !iniDataParser->IsDefaultThread())
       
  1297 				{
       
  1298 				C32LOG(KC32Warning,_L8("LoadCMIDataL: Corrupt [IniData] section: Player has no CSY list."));
       
  1299 #ifdef _DEBUG
       
  1300 				Fault(EBadIniData); // panic
       
  1301 #endif
       
  1302 				skipThisCMI=ETrue;
       
  1303 				C32LOG(KC32Bootup,_L8("Skipping CMI file due to no CSYs found"));
       
  1304 				}
       
  1305 			
       
  1306 			
       
  1307 		
       
  1308 			if (!skipThisCMI)
       
  1309 				{
       
  1310 				// workerID range is checked in parser so we don't re-check here
       
  1311 				
       
  1312 							
       
  1313 				if ((iDefaultThreadIndex <= KMainThreadId) && (iniDataParser->IsDefaultThread()))
       
  1314 					{
       
  1315 					// if dealer was default, we override here since we now have a default player
       
  1316 					iDefaultThreadIndex = iniDataParser->WorkerId();
       
  1317 					}
       
  1318 					
       
  1319 				if (iniDataParser->WorkerId() >= iC32ThreadList.Count())
       
  1320 					{
       
  1321 					// expand the array if necessary
       
  1322 					// these elements may be filled in later
       
  1323 					while (iniDataParser->WorkerId() > iC32ThreadList.Count())
       
  1324 						{
       
  1325 						blankThreadRec = CC32ThreadInfo::NewL(KNullDesC8);
       
  1326 						ret = iC32ThreadList.Append(blankThreadRec); //transfer ownership
       
  1327 						if (ret != KErrNone)
       
  1328 							{
       
  1329 							delete blankThreadRec;
       
  1330 							User::Leave(ret);
       
  1331 							}
       
  1332 						blankThreadRec=NULL;
       
  1333 						}
       
  1334 					iC32ThreadList.AppendL(newThreadRec);
       
  1335 					CleanupStack::Pop(newThreadRec); //ownership transferred
       
  1336 					} 
       
  1337 				else
       
  1338 					{
       
  1339 					// we are using up an existing element
       
  1340 					if (iC32ThreadList[iniDataParser->WorkerId()]->ModuleName()->CompareF(KNullDesC8)!=0)
       
  1341 						{
       
  1342 						C32LOG2(KC32Warning,_L8("LoadCMIDataL: Corrupt IniData found - player workerId is a duplicate: %d."),iniDataParser->WorkerId());
       
  1343 #ifdef _DEBUG
       
  1344 						Fault(EBadIniData); // panic
       
  1345 #endif
       
  1346 						User::Leave(KErrCorrupt);
       
  1347 						}
       
  1348 					else
       
  1349 						{
       
  1350 						delete iC32ThreadList[iniDataParser->WorkerId()]; //blank record
       
  1351 						iC32ThreadList[iniDataParser->WorkerId()] = newThreadRec;
       
  1352 						CleanupStack::Pop(newThreadRec); //ownership transferred
       
  1353 						}
       
  1354 					}
       
  1355 					
       
  1356 				if (iniDataParser->WorkerId() >= numCSYsPerCMI.Count())
       
  1357 					{
       
  1358 					// expand the array if neceesary
       
  1359 					while (iniDataParser->WorkerId() > numCSYsPerCMI.Count())
       
  1360 						{
       
  1361 						numCSYsPerCMI.AppendL(-1);
       
  1362 						}
       
  1363 					numCSYsPerCMI.AppendL(iniDataParser->NumCSYs());
       
  1364 					}
       
  1365 				else
       
  1366 					{
       
  1367 					if (numCSYsPerCMI[iniDataParser->WorkerId()]>0)
       
  1368 						{
       
  1369 						C32LOG4(KC32Warning,_L8("LoadCMIDataL: Internal check failure: attempted to add CSYs for workerID twice. WorkerId: %d, CurrNumCSYs: %d, NewNumCSYs: %d"),iniDataParser->WorkerId(),numCSYsPerCMI[iniDataParser->WorkerId()],iniDataParser->NumCSYs());
       
  1370 #ifdef _DEBUG
       
  1371 						Fault(EBadState); // panic
       
  1372 #endif
       
  1373 						User::Leave(KErrCorrupt);
       
  1374 						}
       
  1375 					else
       
  1376 						{
       
  1377 						numCSYsPerCMI[iniDataParser->WorkerId()]=iniDataParser->NumCSYs();
       
  1378 						}
       
  1379 					}
       
  1380 					
       
  1381 				for (TInt i=0 ; i < iniDataParser->NumCSYs(); i++)
       
  1382 					{
       
  1383 					TBuf8<KMaxFileName> csyFilename;
       
  1384 					csyFilename.Copy(iniDataParser->iCSYs[i]);
       
  1385 					TInt r=csyFilename.LocateReverse('.');
       
  1386 				 	if (r==KErrNotFound)
       
  1387 						{
       
  1388 						if (csyFilename.Length()>KMaxFileName - (TInt)KCSYExtension8.iTypeLength)
       
  1389 							{
       
  1390 							C32LOG2(KC32Warning,_L("LoadCMIDataL: Corrupt [IniData] section: Player has a CSY that is too big: %S. Will panic in debug."),&iniDataParser->iCSYs[i]);
       
  1391 							__ASSERT_DEBUG(0,Fault(EBadIniData));
       
  1392 							_LIT8(KCSYDudName, "BadCsy" );
       
  1393 							csyFilename.Copy(KCSYDudName());  // continue with a dud record
       
  1394 							}
       
  1395 						csyFilename.Append(KCSYExtension8);
       
  1396 						}
       
  1397 					
       
  1398 					CCSYInfo* csyInfoRec = CCSYInfo::NewL(csyFilename, iniDataParser->WorkerId());
       
  1399 					CleanupStack::PushL(csyInfoRec);
       
  1400 					
       
  1401 					ret = iCSYList.InsertInOrder(csyInfoRec, TLinearOrder<CCSYInfo>(&CCSYInfo::CompareCSYInfo));
       
  1402 					if (ret == KErrAlreadyExists)
       
  1403 						{
       
  1404 						// duplicate discovered
       
  1405 						ret = iCSYList.FindInOrder(csyInfoRec, TLinearOrder<CCSYInfo>(&CCSYInfo::CompareCSYInfo));
       
  1406 						if (numCSYsPerCMI[iniDataParser->WorkerId()] > numCSYsPerCMI[iCSYList[ret]->WorkerId()])
       
  1407 							{
       
  1408 							C32LOG4(KC32Bootup,_L8("Reallocating ThreadId for CSY %S [%d -> %d] due to duplicate appearance in CMI files"),iCSYList[ret]->GetCSYName(),iCSYList[ret]->WorkerId(),iniDataParser->WorkerId());
       
  1409 							numCSYsPerCMI[iCSYList[ret]->WorkerId()]--;
       
  1410 							iCSYList[ret]->SetWorkerId(iniDataParser->WorkerId());
       
  1411 							}
       
  1412 						else
       
  1413 							{
       
  1414 							C32LOG3(KC32Bootup,_L8("CSY %S appears in two CMI files. Leaving in current thread (%d) due to equal CSY balance across threads."),iCSYList[ret]->GetCSYName(),iCSYList[ret]->WorkerId());
       
  1415 							numCSYsPerCMI[iniDataParser->WorkerId()]--;
       
  1416 							}
       
  1417 						CleanupStack::PopAndDestroy(csyInfoRec); // dont need duplicate further
       
  1418 						}
       
  1419 					else if (ret != KErrNone)
       
  1420 						{
       
  1421 						User::Leave(ret);
       
  1422 						} 
       
  1423 					else
       
  1424 						{
       
  1425 						// ownership transferred
       
  1426 						CleanupStack::Pop(csyInfoRec);
       
  1427 						}
       
  1428 			
       
  1429 					}
       
  1430 				} // if skip
       
  1431 			else
       
  1432 				{
       
  1433 				CleanupStack::PopAndDestroy(&newThreadRec);
       
  1434 				}
       
  1435 			
       
  1436 			} //if is player
       
  1437 			CleanupStack::PopAndDestroy(iniDataParser);
       
  1438 	
       
  1439 		}//while enumerate modules
       
  1440 	
       
  1441 		
       
  1442 	if (iDefaultThreadIndex == KMaxTUint16)
       
  1443 		{
       
  1444 		// try to find any usable players for the default. otherwise, we use dealer.
       
  1445 		TInt k=TC32WorkerThreadPublicInfo::EFirstPlayerThread;  // 
       
  1446 		while (k < iC32ThreadList.Count())
       
  1447 			{
       
  1448 			if (iC32ThreadList[k]!=blankThreadRec)
       
  1449 				{
       
  1450 				iDefaultThreadIndex = k;
       
  1451 				}
       
  1452 			k++;
       
  1453 			}
       
  1454 		if (iDefaultThreadIndex == KMaxTUint16)
       
  1455 			{
       
  1456 			iDefaultThreadIndex = KMainThreadId;
       
  1457 			}
       
  1458 		}
       
  1459 				
       
  1460 	CleanupStack::PopAndDestroy(&iniData);
       
  1461 	CleanupStack::PopAndDestroy(&cfgSvr);
       
  1462 	CleanupStack::PopAndDestroy(); // numCSYsPerCMI
       
  1463 	 
       
  1464 
       
  1465 
       
  1466 #ifdef __FLOG_ACTIVE
       
  1467 	DumpThreadInfoAndCSYLists();
       
  1468 #endif
       
  1469 
       
  1470 	}
       
  1471 
       
  1472 void CC32ThreadManager::SetDefaults()
       
  1473 // called if the initialisation of the threadmanager goes wrong (LoadCMIDataL leaves), which is probably when
       
  1474 // there is no memory. So this function sets up the thread manager into a state so that it is still
       
  1475 // internally consistent and able to load modules so C32 can keep booting. If memory is available
       
  1476 // by the time a module load request is received, it can be loaded successfully.
       
  1477 	{
       
  1478 	iDefaultThreadIndex = KMainThreadId;
       
  1479 	
       
  1480 	// by destroying whatever is in the csylist, all CSYs will default to the main thread
       
  1481 	iCSYList.ResetAndDestroy();
       
  1482 
       
  1483 	// we don't need the thread list anymore - all csy load attempts will go to default thread
       
  1484 	// so this list will never be checked. If a player is loading at boot as well,
       
  1485 	// the bind at that stage will see the list is destroyed and the player will just sit there unused.
       
  1486 	iC32ThreadList.ResetAndDestroy();
       
  1487 	
       
  1488 	// iCPMLoader will be empty at this point, so we leave it null.
       
  1489 	}
       
  1490 
       
  1491 
       
  1492 //
       
  1493 //	CC32Dealer
       
  1494 //
       
  1495 
       
  1496 
       
  1497 CC32Dealer* CC32Dealer::NewL(CC32WorkerThread* aOwnerThread, const TDesC8& aDealerIniData)
       
  1498 	{
       
  1499 	CC32Dealer* self = new(ELeave) CC32Dealer(aOwnerThread);
       
  1500 	CleanupStack::PushL(self);
       
  1501 	self->ConstructL(aDealerIniData);
       
  1502 	CleanupStack::Pop(self);
       
  1503 	return self;
       
  1504 	}
       
  1505 	
       
  1506 CC32Dealer::CC32Dealer(CC32WorkerThread* aOwnerThread) 
       
  1507 : CC32Server(aOwnerThread, EPriority), 
       
  1508 iOwnerThread(aOwnerThread)
       
  1509 	{
       
  1510 	}
       
  1511 
       
  1512 // aCSYList is the CSY list as extracted from the ini data that the CWorkerThread receives from the
       
  1513 // configurator.
       
  1514 void CC32Dealer::ConstructL(const TDesC8& aDealerIniData)
       
  1515 	{
       
  1516 	// set up the thread manager, which will load the cmi data
       
  1517 	// if this fails we have two possible methods of recovery.
       
  1518 	// The first is to attempt to set some defaults, which at least allows c32 to provide service
       
  1519 	// If this fails too (possibly low memory) then we mark the Dealer as having failed to start
       
  1520 	// which then means it will not start its server.
       
  1521 
       
  1522 	TRAPD(ret,iThreadManager = CC32ThreadManager::NewL(this));
       
  1523 	if (ret!=KErrNone)
       
  1524 		{
       
  1525 		C32LOG2(KC32Bootup,_L8("CC32Dealer::ConstructL: Could not create thread manager so setting iFailedStartup TRUE. Ret=%d"),ret);
       
  1526 		iFailedStartup=ETrue;
       
  1527 		} 
       
  1528 	else
       
  1529 		{
       
  1530 		
       
  1531 		TRAP(ret,iThreadManager->LoadCMIDataL(aDealerIniData));
       
  1532 		if (ret != KErrNone)
       
  1533 			{
       
  1534 			C32LOG2(KC32Bootup,_L8("CC32Dealer: CMI data load left with %d. Ignoring CMI files and defaulting to loading all CSYs into main thread."),ret);
       
  1535 			iThreadManager->SetDefaults();
       
  1536 			}
       
  1537 		
       
  1538 		}
       
  1539 	
       
  1540 	
       
  1541 	if(!iFailedStartup)
       
  1542 		{
       
  1543 		iWorkerDataGlobals = CC32WorkerDataGlobals::NewL();
       
  1544 
       
  1545 		TC32WorkerThreadRegister& mainProperties = *WorkerDataGlobals().GetWorkerGlobals(TC32WorkerThreadPublicInfo::EMainThread);
       
  1546 		// players set their heap when they get introduction from main thread, but
       
  1547 		// as this does not happen for main thread we set main thread's heap here separately
       
  1548 		mainProperties.iHeap = &User::Heap();
       
  1549 		mainProperties.iDealer = this;
       
  1550 		if(!iOwnerThread->Player())
       
  1551 			{
       
  1552 			mainProperties.iPlayer = iOwnerThread->Player();	
       
  1553 			}
       
  1554 
       
  1555 #ifdef _DEBUG
       
  1556 		if(iOwnerThread->AllocFailType() != RAllocator::ENone)
       
  1557 			{
       
  1558 			WorkerDataGlobals().GetWorkerGlobals(TC32WorkerThreadPublicInfo::EMainThread)->iHeap->__DbgSetAllocFail(iOwnerThread->AllocFailType(), iOwnerThread->AllocFailRate());
       
  1559 			}
       
  1560 #endif
       
  1561 
       
  1562 		C32LOG1(KC32Dealer,_L8("calling inherited ConstructL()"));
       
  1563 		inherited::ConstructL(iThreadManager);
       
  1564 		}
       
  1565 	}
       
  1566 
       
  1567 
       
  1568 /**
       
  1569 When deleting a session it will be in response to a disconnect from the client, so we
       
  1570 signal that to the session. If this thread is in the process of shutting down we need to
       
  1571 check whether it was just waiting for this session (if this was the last one) and if this is
       
  1572 the case we can initiate the asynchronous process of shutting down the worker thread.
       
  1573 */
       
  1574 void CC32Dealer::DeleteSession(CCommSession* aSession) 
       
  1575 	{ 
       
  1576 	// If we ever see evidence of shutdowns nested inside active calls (ie "this" deleted prematurely then consider
       
  1577 	// switching handling to use a CAsyncOneShot)
       
  1578 	aSession->CompleteDisconnect();
       
  1579 	if(WorkerThread().ShuttingDown() && CanShutdown())
       
  1580 		{
       
  1581 		WorkerThread().SetDealerShutdownComplete(ETrue);
       
  1582 		WorkerThread().MaybeTriggerThreadShutdownCallback();
       
  1583 		}
       
  1584 	}
       
  1585 
       
  1586 
       
  1587 /**
       
  1588 Iterate through all sessions and make sure they deploy the SubSessionProcessor on each owned sub-session.
       
  1589 It is not known here what the SubSessionProcessor actually does as it is implemented by the caller.
       
  1590 */
       
  1591 void CC32Dealer::ProcessSubSessions(TWorkerId aPeerId, CCommSession::TSubSessionProcessor aSubSessionProcessor, TAny* aPtr)
       
  1592 	{
       
  1593 	iSessionIter.SetToFirst();
       
  1594 	CCommSession* sess;
       
  1595 	while((sess = static_cast<CCommSession*>(iSessionIter++)) != NULL)
       
  1596 		{
       
  1597 		sess->ProcessSubSessions(aPeerId, aSubSessionProcessor, aPtr);
       
  1598 		}
       
  1599 	}
       
  1600 
       
  1601 TInt CC32Dealer::SubsessionCountInPlayer(TWorkerId aPeerId)
       
  1602 	{
       
  1603 	TInt numSubSessions = 0;
       
  1604 	ProcessSubSessions(aPeerId, CCommSession::CountSubSessions, &numSubSessions);
       
  1605 	return numSubSessions;
       
  1606 	}
       
  1607 	
       
  1608 CC32Dealer::~CC32Dealer()
       
  1609 	{
       
  1610 	C32LOG1(KC32Shutdown,_L8("CC32Dealer::~CC32Dealer()."));
       
  1611 
       
  1612 #ifdef __FLOG_ACTIVE
       
  1613 	iSessionIter.SetToFirst();
       
  1614 	CCommSession* pSession;
       
  1615 	// we log any sessions remaining
       
  1616 	while((pSession=static_cast<CCommSession*>(iSessionIter++))!=NULL)
       
  1617 		{
       
  1618 		C32LOG2(KC32Shutdown, _L8("CC32Dealer::~CC32Dealer(): Session(%08x): Remaining. WARNING: this will cause objects to leak."), pSession);
       
  1619 		}
       
  1620 #endif
       
  1621 	
       
  1622 	iParkedRequests.Close();
       
  1623 	delete iThreadManager;
       
  1624 	iThreadManager = NULL;
       
  1625 
       
  1626 	if (WorkerDataGlobalsExist())    //won't exist if we've OOM'd during construction and reached here during cleanup.
       
  1627 		{
       
  1628 		for(TWorkerId id = TC32WorkerThreadPublicInfo::EMaxWorkerThreadId; id >=  TC32WorkerThreadPublicInfo::EFirstPlayerThread; --id)
       
  1629 			{
       
  1630 			if(WorkerExists(id))
       
  1631 				{
       
  1632 				FreeWorkerReferences(id);
       
  1633 				}
       
  1634 			}
       
  1635 		}
       
  1636 
       
  1637 		
       
  1638 	delete iWorkerDataGlobals;
       
  1639 	iWorkerDataGlobals = NULL;
       
  1640 	C32LOG(KC32Shutdown,_L8("CC32Dealer::~CC32Dealer() complete."));
       
  1641 
       
  1642 	}
       
  1643 
       
  1644 void CC32Dealer::ShutdownIfReady()
       
  1645 	{
       
  1646 	ASSERT(iOwnerThread->WorkerId() == TC32WorkerThreadPublicInfo::EMainThread); // protect against this being called for a dealerPlayer
       
  1647 	C32LOG2(KC32Shutdown, _L("CC32Dealer::ShutdownIfReady() - iSessionShutdownComplete = %d"), iSessionShutdownComplete );
       
  1648 	if(iSessionShutdownComplete)
       
  1649 		{
       
  1650 		iOwnerThread->TriggerThreadShutdownCallback();
       
  1651 		}
       
  1652 	}
       
  1653 
       
  1654 
       
  1655 /** 
       
  1656 Used during binding when the Dealer receives a introduction response message from a worker.
       
  1657 The Dealer will set-up housekeeping datastructures for the worker
       
  1658 @see TC32WorkerMsg::EMainIntroductionResp
       
  1659 */
       
  1660 
       
  1661 void CC32Dealer::ProcessWorkerIntroductionResponse(const TC32WorkerMainIntroductionRespMsg& aMsg)
       
  1662 	{
       
  1663 	const TC32WorkerThreadPublicInfo& msgInfo = aMsg.WorkerInfo();
       
  1664 	C32LOG2(KC32Dealer, _L("Process Worker Introduction Response for worker: %d"),msgInfo.iWorkerId);
       
  1665 	ASSERT(msgInfo.iWorkerId > TC32WorkerThreadPublicInfo::EMainThread && msgInfo.iWorkerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId);
       
  1666 	ASSERT(!WorkerDataGlobals().WorkerPresent(msgInfo.iWorkerId));
       
  1667 	TC32WorkerThreadRegister& workerReg = *WorkerDataGlobals().GetWorkerGlobals(msgInfo.iWorkerId);
       
  1668 	static_cast<TC32WorkerThreadPublicInfo&>(workerReg) = msgInfo;
       
  1669 	workerReg.iDealer = workerReg.iWorker->Dealer();
       
  1670 	workerReg.iPlayer = workerReg.iWorker->Player();
       
  1671 	RemovePendingIntroductionResponse();
       
  1672 
       
  1673 	// process response message. Process parked request here
       
  1674     ProcessParkedRequest();
       
  1675 
       
  1676 #ifdef _DEBUG
       
  1677   	// We only switch on the configured simulated allocation failures once the bindings are complete, because
       
  1678   	// it's too hard to recover from them earlier. This is a regrettable but hopefully harmless limitation in
       
  1679   	// practice, ie if we're OOM during boot then recovery strategies aren't obvious.
       
  1680   	workerReg.iHasGlobalAllocFails = aMsg.FailType() != RAllocator::ENone;
       
  1681   	if(workerReg.iHasGlobalAllocFails)
       
  1682   		{
       
  1683   		workerReg.iHeap->__DbgSetAllocFail(aMsg.FailType(), aMsg.FailRate());
       
  1684   		}
       
  1685 #endif
       
  1686 
       
  1687 	}
       
  1688 
       
  1689 void CC32Dealer::DeleteCPMLoader(CommsFW::TWorkerId aWorkerId)
       
  1690 	{
       
  1691 	// remove waiting LoadCPM object
       
  1692 	iThreadManager->ProcessModuleLoadSuccess(aWorkerId);
       
  1693 	}
       
  1694 
       
  1695 void CC32Dealer::RemoveParkedRequestsOnSessionClose(CCommSession* aSession)
       
  1696 	{
       
  1697 	const TInt parkedCount = iParkedRequests.Count();
       
  1698 	for(TInt i = parkedCount - 1; i >= 0; --i)
       
  1699  		{
       
  1700 		const TSessionMessagePair& pair = iParkedRequests[i];
       
  1701 		if(pair.iSession == aSession)
       
  1702 			{
       
  1703 			C32LOG2(KC32Dealer, _L8("CC32Dealer::RemoveParkedRequest() - found parked for closing session %08x "), aSession);
       
  1704 			SafeComplete(pair.iMessage, KErrSessionClosed);		// session is being closed
       
  1705 			iParkedRequests.Remove(i);
       
  1706 		 	}
       
  1707  		}
       
  1708 	}
       
  1709 
       
  1710 void CC32Dealer::ProcessParkedRequest()
       
  1711 	{
       
  1712 	 const TInt parkedCount = iParkedRequests.Count();
       
  1713 	 C32LOG2(KC32Bootup, _L8("CC32Dealer::ProcessParkedRequestL() - %d parked messages to process"), parkedCount);
       
  1714 	 for(TInt i = parkedCount - 1; i >= 0; --i)
       
  1715  		 {
       
  1716  		 const TSessionMessagePair& pair = iParkedRequests[i];
       
  1717  		 // Check that the session still exists
       
  1718  		 iSessionIter.SetToFirst();
       
  1719  		 CSession2* ss;
       
  1720  		 while((ss = iSessionIter++) != NULL && ss != pair.iSession)
       
  1721 	 		 {
       
  1722 	 		 }
       
  1723 		 if(ss && !pair.iMessage.IsNull())
       
  1724 	 		 {
       
  1725 	 		 C32LOG2(KC32Bootup, _L8("CC32Dealer::ProcessParkedRequestL() - parked messages for sess %08x"), ss);
       
  1726 	 		 RMessage2 tempMsg = pair.iMessage;
       
  1727 	 		 iParkedRequests.Remove(i);		// remove parked request
       
  1728 		 	 TRAPD(res, ss->ServiceL(tempMsg));
       
  1729 		 	 if(res != KErrNone)
       
  1730 				{
       
  1731 		 	 	SafeComplete(tempMsg, res);
       
  1732 		 	 	}
       
  1733 	 		 }
       
  1734  		 }
       
  1735 	 }
       
  1736 
       
  1737 TInt CC32Dealer::ParkRequest(CCommSession* aSession, const RMessage2& aMessage)
       
  1738 	 {
       
  1739 	 __ASSERT_DEBUG(aMessage.Function()==ECommLoadCommModule,Fault(EBadState,_L8("CC32Dealer::ParkRequest - Attempt to park a non-moduleLoad request. Panicking. Session(%08x) Message(%08x)"), aSession, aMessage.Handle()));
       
  1740 	 
       
  1741 	 C32LOG3(KC32Bootup, _L8("CC32Dealer::ParkRequest Session(%08x) Message(%08x)"), aSession, aMessage.Handle());
       
  1742 	 return iParkedRequests.Append(TSessionMessagePair(aSession, aMessage));
       
  1743 	 }
       
  1744 
       
  1745 
       
  1746 TInt CC32Dealer::LoadCPMOnLoadCommModule(CommsFW::TWorkerId aWorker)
       
  1747 	 {
       
  1748 	 return iThreadManager->RequestLoadModule(aWorker);
       
  1749 	 }
       
  1750 	 
       
  1751 	 
       
  1752 void CC32Dealer::ProcessFailedPlayerLoad(CommsFW::TWorkerId aWorker)
       
  1753 // called from CPMLoader if configurator reported load failed.
       
  1754 // gives dealer a chance to do any cleanup.
       
  1755 	{
       
  1756 	// sweep parked requests array and remove any CSY load requests that were hoping to be loaded into the
       
  1757 	// failed player
       
  1758 	// They will be completed with appropriate KErrNoMemory (most likely reason for player load to fail)
       
  1759 	// error code. Transversing the array is somewhat expensive since we're reprocessing all queued messages.
       
  1760 	TFileName csyfilename;
       
  1761 	C32LOG2(KC32Dealer,_L8("CC32Dealer:ProcessFailedPlayerLoad: Sweeping parked requests array to complete(w/KErrNoMemory) and remove any waiting on failed player %d"),aWorker);
       
  1762 	const TInt parkedCount = iParkedRequests.Count();
       
  1763 	for (TInt i = parkedCount -1 ;i >= 0; --i)
       
  1764 		{
       
  1765 	    const TSessionMessagePair& pair = iParkedRequests[i];
       
  1766 		TInt res = pair.iMessage.Read(0,csyfilename);
       
  1767 		
       
  1768 		TBuf8<KMaxFileName> fileName8;
       
  1769 		fileName8.Copy(csyfilename);
       
  1770 		
       
  1771 		
       
  1772 		if (res==KErrNone)
       
  1773 			{
       
  1774 			TInt r=csyfilename.LocateReverse('.');
       
  1775 		 	if (r==KErrNotFound)
       
  1776 				{
       
  1777 				// length was checked when message first processed before queuing
       
  1778 				__ASSERT_DEBUG(csyfilename.Length() <= KMaxFileName - (TInt)KCSYExtension.iTypeLength, Fault(EBadState,_L("CC32Dealer::ProcessFailedPlayerLoad: Message(%08x) filename is too long. Panicking."),&pair.iMessage));
       
  1779 				csyfilename.Append(KCSYExtension);
       
  1780 				}
       
  1781 
       
  1782 			CommsFW::TWorkerId worker;
       
  1783 			TBool found = iThreadManager->FindThreadByFileName(fileName8,worker);
       
  1784 			
       
  1785 
       
  1786 			
       
  1787 			if (!found)
       
  1788 				{
       
  1789 				// CSY must have been destined for the default thread
       
  1790 				worker = iThreadManager->DefaultThread();
       
  1791 				}
       
  1792 			
       
  1793 			if (worker == aWorker)
       
  1794 				{
       
  1795 				C32LOG3(KC32Detail,_L8("CC32Dealer:ProcessFailedPlayerLoad: Completing and removing message(%08x) at index %d"),&pair.iMessage,i);
       
  1796 				SafeComplete(pair.iMessage,KErrNoMemory);
       
  1797 				iParkedRequests.Remove(i);
       
  1798 				}
       
  1799 			
       
  1800 			}
       
  1801 		else
       
  1802 			{
       
  1803 			__ASSERT_DEBUG(res==KErrNone,Fault(EBadState,_L8("CC32Dealer::ProcessFailedPlayerLoad: Could not read filename from Message at iParkedRequests[%d]. Res=%d Panicking."),i,res));
       
  1804 			// in release mode just ignore mesg and keep going
       
  1805 			}
       
  1806 
       
  1807 		}
       
  1808 		
       
  1809 	}
       
  1810 
       
  1811 
       
  1812 /** ThreadManager is updated with CSerial* and PortPrefix. PortPrefix is mapped to CSYFileName 
       
  1813 * and this mapping then provides CSYFileName, which is searched in CSYcontainer in session to 
       
  1814 * test whether the CSY in question is loaded in this session or not - this mapping is used while
       
  1815 * closing Comm Module
       
  1816 */
       
  1817 void CC32Dealer::ProcessLoadCommModuleSuccessResponse(const RMessage2& aMessage, CSerial* aSerial)
       
  1818 // called from workerthread dispatchMsg, or directly if load is for co-resident player
       
  1819 	{
       
  1820 	/** Map find CSYFileName in ThreadManager and update PortPrefix and CSerial* field against it. In case of duplication, 
       
  1821 	* the CSerial* will be updated again though it'll be point to the same physical address
       
  1822 	*/
       
  1823 	
       
  1824 	TFileName csyFilename;
       
  1825 	Read(0, aMessage, csyFilename, 0);
       
  1826 	TInt r=csyFilename.LocateReverse('.');
       
  1827  	if (r==KErrNotFound)
       
  1828 		{
       
  1829 		csyFilename.Append(KCSYExtension);
       
  1830 		}
       
  1831 	C32LOG2(KC32Dealer, _L("CC32Dealer::ProcessLoadCommModuleSuccessResponse, insert CSerial* and PortPrefix for: %S"),&csyFilename);
       
  1832 
       
  1833 	iThreadManager->UpdateThreadManagerOnCSYLoad(csyFilename, aSerial->Name(), aSerial);
       
  1834 	
       
  1835 	// complete message in dealer after update is done in ThreadManager
       
  1836 	SafeComplete(aMessage, KErrNone);
       
  1837 	}
       
  1838 
       
  1839 void CC32Dealer::ProcessLoadCommModuleFailureResponse(const RMessage2& aMessage, TInt aFailReason)
       
  1840 	{
       
  1841 	TBool dummy;
       
  1842 	TFileName csyFilename;
       
  1843 	Read(0, aMessage, csyFilename, 0);
       
  1844 	
       
  1845 	TInt ret = AddCSYExtension(csyFilename,aMessage);
       
  1846 	__ASSERT_DEBUG(ret == KErrNone, Fault(EBadState,_L("CC32Dealer::ProcessLoadCommModuleFailureResponse: Could not add extension to CSY filename. This is inconsistent since should not get here in such case. Panicking.")));
       
  1847 		
       
  1848 
       
  1849 	C32LOG1(KC32Dealer, _L("CC32Dealer::ProcessLoadCommModuleFailureResponse, remove CSY from Session csy container and de-allocate memory for this csy in ThreadManager"));
       
  1850 	static_cast<CCommSession*>(aMessage.Session())->RemoveCSYFromSession(csyFilename,dummy);
       
  1851 	// de-allocate memory on this call
       
  1852 	iThreadManager->UpdateThreadManagerOnCSYLoadFailure(csyFilename);
       
  1853 	// complete message after removing csy from session CSY container and de-allocating memory
       
  1854 	SafeComplete(aMessage, aFailReason);
       
  1855 	}
       
  1856 	
       
  1857 
       
  1858 TInt CC32Dealer::Read(TInt aPos, const RMessagePtr2& aMessage , TDes16& aDes, TInt aOffset)
       
  1859 	{
       
  1860 	C32LOG3(KC32Dealer, _L8("CC32Dealer::Read(), Pos (%d), Offset (%d)"), aPos, aOffset);
       
  1861 
       
  1862 	TInt ret = aMessage.Read(aPos, aDes, aOffset);
       
  1863 	if (ret!=KErrNone)
       
  1864 		{
       
  1865 		C32LOG1(KC32Dealer, _L8("Error at the time of reading data from client"));
       
  1866 		PanicClient(EBadDescriptor,aMessage);
       
  1867 		}
       
  1868 	return ret;
       
  1869 	}
       
  1870 
       
  1871 void CC32Dealer::FreeWorkerReferences(TWorkerId aWorkerId)
       
  1872 	{	
       
  1873 	C32LOG2(KC32Shutdown, _L("CC32Dealer::FreeWorkerReferences(%d)"), aWorkerId );
       
  1874 	TC32WorkerThreadRegister& properties(*WorkerDataGlobals().GetWorkerGlobals(aWorkerId));
       
  1875 #ifdef _DEBUG
       
  1876 	// The RootServer normally checks the heap for leaks when the module unloads
       
  1877 	// but for C32 CSY modules this is commonly too early, since the Dealer (acting as PitBoss) holds
       
  1878 	// its reference open until the cleanup completes. Hence here we check for 
       
  1879 	// remaining allocations if we hold the last reference and if no thread 
       
  1880 	// which used it died involuntarily
       
  1881 	RCFSharedHeap* heap = static_cast<RCFSharedHeap*>(properties.iHeap);
       
  1882 	C32LOG4(KC32Warning, _L8("~~~CC32Dealer::FreeWorkerReferences heap(%08x).AccessCount()==%d, cell count=%d"), (TUint) heap, heap->AccessCount(), heap->Count());
       
  1883 	if(heap->AccessCount() <= 2)
       
  1884 		{
       
  1885 		if(heap->Count() > 0)
       
  1886 			{
       
  1887 			//C32LOG2(KRSModule,KRSModuleLeak,_L8("~~~SerComms-CC32Dealer::FreeWorkerReferences.Following leaks are from Ser-Comms C32 (more info logged under: C32SerComms *)"));
       
  1888 			C32LOG1(KRSModule,KRSModuleLeak);
       
  1889 			heap->LogAllocatedCells(RootServer::KLogSubSysRSModule, RootServer::KLogRSLeakTag);
       
  1890 			RProperty pubsub;
       
  1891 			TInt res = pubsub.Attach(RootServer::KUidCommsProcess, RootServer::KUidCommsModuleLeakCounter);
       
  1892 			//No nead for cleanup stack, cannot leave before Close
       
  1893 			if (res == KErrNone)
       
  1894 				{
       
  1895 				TInt count;
       
  1896 				res =pubsub.Get(count);
       
  1897 				if (res == KErrNone)
       
  1898 					{
       
  1899 					count += heap->Count();
       
  1900 					res =pubsub.Set(count);
       
  1901 					}
       
  1902 				}
       
  1903 			pubsub.Close();
       
  1904 			if (res != KErrNone)
       
  1905 				{
       
  1906 				__CFLOG_1(RootServer::KLogSubSysRSModule, RootServer::KLogRSLeakTag, _L8("Unable to report leaks. Error: %d"), res);
       
  1907 				}
       
  1908 			// As much as anything this log line is here to make it apparent that the breakpoint above was hit
       
  1909 			C32LOG1(KC32Warning, _L8("--- end of leaked cell log. If leaks not shown enable logging for: RSModule *"));
       
  1910 			}
       
  1911 		}
       
  1912 #endif
       
  1913 	properties.Clear();
       
  1914 	}			
       
  1915 
       
  1916 /** 
       
  1917 Check if we can unbind from a worker. This is only possible if the local Dealer doesn't 
       
  1918 have any outstanding sub-sessions terminating in the peer and it doesn't have any sessions 
       
  1919 with outstanding closes against the peer. Otherwise the channel is still needed. 
       
  1920 */
       
  1921 TBool CC32Dealer::CanUnbindFromWorker(TWorkerId aWorker)
       
  1922 	{
       
  1923 	if (!WorkerThread().DealerByRef().Player(aWorker))
       
  1924 		{
       
  1925 		return ETrue;
       
  1926 		}
       
  1927 	if(SubsessionCountInPlayer(aWorker) == 0)
       
  1928 		{
       
  1929 		// Check for any sessions which have outstanding session closes against the Worker
       
  1930 		iSessionIter.SetToFirst();
       
  1931 		CCommSession* sess;
       
  1932 		while((sess = static_cast<CCommSession*>(iSessionIter++)) != NULL)
       
  1933 			{
       
  1934 			if(sess->IsPlayerInDisconnectList(aWorker))
       
  1935 				{
       
  1936 				return EFalse;
       
  1937 				}
       
  1938 			}
       
  1939 		return ETrue;
       
  1940 		}
       
  1941 	return EFalse;
       
  1942 	}
       
  1943 	
       
  1944 
       
  1945 /** 
       
  1946 Check whether a worker Id is legal and a worker with that Id is installed.
       
  1947 */
       
  1948 TBool CC32Dealer::WorkerExists(TWorkerId aId) const
       
  1949 	{
       
  1950 	return WorkerDataGlobals().WorkerPresent(aId);
       
  1951 	}
       
  1952 
       
  1953 void CC32Dealer::SessionShutdownComplete()
       
  1954 	{
       
  1955 	iSessionShutdownComplete = ETrue;
       
  1956 	ShutdownIfReady();
       
  1957 	}
       
  1958 
       
  1959 
       
  1960 void CC32Dealer::PostMessage(TWorkerId aWorkerId, TCFMessage& aMessage)
       
  1961 	{
       
  1962 	iOwnerThread->PostMessage(aWorkerId, aMessage);
       
  1963 	}
       
  1964 
       
  1965 #ifdef _DEBUG
       
  1966   // If a heap has been configured from boot to have a failure mode then we don't override this here as
       
  1967   // the lifetime failure testing is more important than the specific test case doing a SetFailNext
       
  1968   void CC32Dealer::SetFailNextForAllHeaps(TInt aFailNext)
       
  1969   	{
       
  1970   	for(TWorkerId workerId = TC32WorkerThreadPublicInfo::EMainThread; workerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId; ++workerId)
       
  1971   		{
       
  1972   		const TC32WorkerThreadRegister& worker = *WorkerDataGlobals().GetWorkerGlobals(workerId);
       
  1973   		if(WorkerExists(workerId) && !worker.iHasGlobalAllocFails)
       
  1974   			{
       
  1975   			worker.iHeap->__DbgSetAllocFail((aFailNext < 0)? RAllocator::EReset: RAllocator::EFailNext, aFailNext);
       
  1976   			}
       
  1977   		}
       
  1978   	}
       
  1979 #endif
       
  1980 
       
  1981 /** 
       
  1982 Given the "local" worker thread's id (normally but not necessarily the current worker
       
  1983 thread and that of another "foreign" worker thread, if they have different heaps then 
       
  1984 switch heaps and return the previous one, otherwise return NULL. 
       
  1985 */
       
  1986 RAllocator* CC32Dealer::MaybeSwitchHeap(TWorkerId aForeignWorkerId)
       
  1987 	{
       
  1988 	
       
  1989 	const TC32WorkerThreadPublicInfo& foreignInfo = *WorkerDataGlobals().GetWorkerGlobals(aForeignWorkerId);
       
  1990 	ASSERT(foreignInfo.iHeap);
       
  1991 	RHeap* heap = &User::Heap();
       
  1992 	if(heap != foreignInfo.iHeap)
       
  1993 		{
       
  1994 		C32LOG2(KC32Detail, _L8("CC32Dealer::MaybeSwitchHeap - Switching heap to %08x."),foreignInfo.iHeap);
       
  1995 		return User::SwitchAllocator(foreignInfo.iHeap);
       
  1996 		}
       
  1997 	else
       
  1998 		{
       
  1999 		C32LOG2(KC32Detail, _L8("CC32Dealer::MaybeSwitchHeap - No heap switch happened - Heap %08x."),heap);
       
  2000 		}	
       
  2001 		
       
  2002 	return NULL;
       
  2003 	}
       
  2004 
       
  2005 /**
       
  2006 Called by any Player/thread to add a sub-session to a session. It will switch the local heap to that 
       
  2007 of the peer before performing operations on the session pointer. It is essential that the session lock is used
       
  2008 around this call.
       
  2009 @see CC32SubSessionIx::Lock
       
  2010 @see CC32SubSessionIx::UnLock
       
  2011 */
       
  2012 TInt CC32Dealer::AddSubSession(CCommSubSession* aSubSession, CCommSession* aSession, TInt& aHandle)
       
  2013 	{
       
  2014 	RAllocator* prevAllocator = MaybeSwitchHeap(aSession->WorkerId());
       
  2015 	TInt err = aSession->iSubSessions.Add(aSubSession, aHandle);
       
  2016 	C32LOG4(KC32Detail, _L8("CC32Dealer::AddSubSession(%08x, %08x, => %08x)"), aSubSession, aSession, aHandle);
       
  2017 	if(prevAllocator)
       
  2018 		{
       
  2019 		User::SwitchAllocator(prevAllocator);
       
  2020 		}
       
  2021 	return err;
       
  2022 	}
       
  2023 
       
  2024 /**
       
  2025 Called by any Player/thread to remove a sub-session from a session. It will switch the local heap to that 
       
  2026 of the peer before performing operations on the session pointer. It is essential that the session lock is used
       
  2027 around this call.
       
  2028 @see CC32SubSessionIx::Lock
       
  2029 @see CC32SubSessionIx::UnLock
       
  2030 */
       
  2031 void CC32Dealer::RemoveSubSession(TInt aHandle, CCommSession* aSession)
       
  2032 	{
       
  2033 	RAllocator* prevAllocator = MaybeSwitchHeap(aSession->WorkerId());
       
  2034 	C32LOG3(KC32Detail, _L8("CC32Dealer::RemoveSubSession(%08x, %08x"), aHandle, aSession);
       
  2035 	VERIFY(aSession->iSubSessions.Remove(aHandle) != NULL);
       
  2036 	if(prevAllocator)
       
  2037 		{
       
  2038 		User::SwitchAllocator(prevAllocator);
       
  2039 		}
       
  2040 	}
       
  2041 
       
  2042 /**
       
  2043 Called by any Player/thread to find handle for a sub-session. It will switch the local heap to that 
       
  2044 of the peer before performing operations on the session pointer. It is essential that the session lock is used
       
  2045 around this call.
       
  2046 @see CC32SubSessionIx::Lock
       
  2047 @see CC32SubSessionIx::UnLock
       
  2048 */
       
  2049 TInt CC32Dealer::FindSubSession(CCommSubSession* aSubSession, CCommSession* aSession, TInt& aHandle)
       
  2050 	{
       
  2051 	RAllocator* prevAllocator = MaybeSwitchHeap(aSession->WorkerId());
       
  2052 	TInt err = aSession->iSubSessions.Find(aSubSession, aHandle);
       
  2053 	C32LOG4(KC32Detail, _L8("CC32Dealer::FindSubSession(%08x, %08x, => %08x)"), aSubSession, aSession, aHandle);
       
  2054 	if(prevAllocator)
       
  2055 		{
       
  2056 		User::SwitchAllocator(prevAllocator);
       
  2057 		}
       
  2058 	return err;
       
  2059 	}
       
  2060 
       
  2061 CC32Dealer* CC32Dealer::Dealer(TWorkerId aWorkerId) const
       
  2062 	{
       
  2063 	return WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iDealer;
       
  2064 	}
       
  2065 
       
  2066 CC32Player* CC32Dealer::Player(TWorkerId aWorkerId) const
       
  2067 	{
       
  2068 	return WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iPlayer;
       
  2069 	}
       
  2070 
       
  2071 void CC32Dealer::SendIntroductionToWorker(CommsFW::TWorkerId aWorkerId)
       
  2072 	{
       
  2073 	// Send the worker peer the Dealer introduction message
       
  2074 	TC32WorkerMainIntroductionMsg msg(this);
       
  2075 	PostMessage(aWorkerId, msg);
       
  2076 	AddPendingIntroductionResponse();
       
  2077 	}
       
  2078 
       
  2079 void CC32Dealer::AddPendingIntroductionResponse()
       
  2080 	{
       
  2081 	++iPendingIntroResponses;
       
  2082 	}
       
  2083 
       
  2084 void CC32Dealer::RemovePendingIntroductionResponse()
       
  2085 	{
       
  2086 	--iPendingIntroResponses;
       
  2087 	}
       
  2088 
       
  2089 /**
       
  2090 This is a simple check shutting down is not possible if there are still open sessions, unless
       
  2091 shutdown type is EImmediate but then this method is not called. 
       
  2092 */
       
  2093 TBool CC32Dealer::CanShutdown()
       
  2094 	{
       
  2095 	CC32Data* globals = CC32DataInTls();
       
  2096     C32LOG2(KC32Detail, _L8("CC32Dealer::CanShutdown() \t iNumSessions = %d "), globals->iNumSessions);
       
  2097 	return globals->iNumSessions <= 0;
       
  2098 	}
       
  2099 
       
  2100 
       
  2101 void CC32Dealer::ProcessShutdownRequest(CommsFW::TCFShutdownType aType)
       
  2102 // Since the c32 framework mimmicks esock's but does not yet contain a DealerPlayer concept,
       
  2103 // this function will be called by whichever thread sees a shutdown first.
       
  2104 	{
       
  2105 	TBool commenceShutdown = CanShutdown();
       
  2106 
       
  2107 	// If have to do now and there are still sessions then we exit anyway but suppress the heap check and log a rude message. We
       
  2108 	// used to delete the sessions but that isn't safe
       
  2109 	if(EImmediate==aType)
       
  2110 		{
       
  2111     	commenceShutdown = ETrue;
       
  2112 
       
  2113 #ifdef __FLOG_ACTIVE
       
  2114 		iSessionIter.SetToFirst();
       
  2115 		if(iSessionIter++ != NULL)
       
  2116 			{
       
  2117 			TInt cnt = 0;
       
  2118 			iSessionIter.SetToFirst();
       
  2119 			CSession2* ss;
       
  2120 			while((ss = iSessionIter++) != NULL)
       
  2121 				{
       
  2122 				C32LOG2(KC32Detail, _L8("<==Session(%08x): remaining"), ss);
       
  2123 				++cnt;
       
  2124 				}
       
  2125 			C32LOG2(KC32Detail, _L8("NB! Immediate shutdown commanded but #%d client sessions remaining (bad test code?)"), cnt);
       
  2126 			}
       
  2127 #endif
       
  2128 		}
       
  2129 
       
  2130 	if(WorkerThread().IsMainThread())
       
  2131 		{
       
  2132 		// this section will always be called by each thread since no dealerPlayer yet
       
  2133 		
       
  2134 		// Even the Dealer (acting as pitboss) yields to the immediate shutdown
       
  2135 		if(commenceShutdown)
       
  2136 			{
       
  2137 			WorkerThread().DealerByRef().SessionShutdownComplete();
       
  2138 			}
       
  2139 		}
       
  2140 	WorkerThread().SetDealerShutdownComplete(commenceShutdown);
       
  2141 	}
       
  2142 
       
  2143 //
       
  2144 // TC32WorkerThreadRegister
       
  2145 //
       
  2146 
       
  2147 TC32WorkerThreadRegister::TC32WorkerThreadRegister()
       
  2148 	{
       
  2149 #ifdef _DEBUG
       
  2150   	iHasGlobalAllocFails = EFalse;
       
  2151 #endif
       
  2152 	}
       
  2153 
       
  2154 void TC32WorkerThreadRegister::Clear()
       
  2155 	{
       
  2156 	inherited::Clear();
       
  2157 	iDealer = NULL;
       
  2158 	iPlayer = NULL;
       
  2159 	}
       
  2160 
       
  2161 //
       
  2162 // CC32SubSessionIx
       
  2163 //
       
  2164 
       
  2165 void CC32SubSessionIx::InitialiseL()
       
  2166 	{
       
  2167 	User::LeaveIfError(iLock.CreateLocal());
       
  2168 	}
       
  2169 
       
  2170 CC32SubSessionIx::~CC32SubSessionIx()
       
  2171 	{
       
  2172 	iLock.Close(); 
       
  2173 	User::Free(iIx);
       
  2174 	}
       
  2175 
       
  2176 TInt CC32SubSessionIx::Find(CCommSubSession* aSubSession, TSubSessionHandle& aHandle) const
       
  2177 	{
       
  2178 	iLock.AssertLockHeld();
       
  2179 	for(TInt ix = 0; ix < iSize; ++ix)
       
  2180 		{
       
  2181 		TEntry& e = iIx[ix];
       
  2182 		if(e.iType != CCommSubSession::ENull && e.iObject == aSubSession)
       
  2183 			{
       
  2184 			aHandle = MakeHandle(ix, e.iMagic, e.iType);
       
  2185 			return KErrNone;
       
  2186 			}
       
  2187 		}
       
  2188 	return KErrNotFound;
       
  2189 	}
       
  2190 
       
  2191 TInt CC32SubSessionIx::Add(CCommSubSession* aSubSession, TSubSessionHandle& aHandle)
       
  2192 	{
       
  2193 	iLock.AssertLockHeld();
       
  2194 	if(TUint(iFreeListHead) >= TUint(iSize))
       
  2195 		{
       
  2196 		TInt err = ExpandArray();
       
  2197 		if(err != KErrNone)
       
  2198 			{
       
  2199 			return err;
       
  2200 			}
       
  2201 		}
       
  2202 	TInt ix = iFreeListHead;
       
  2203 	TEntry& e = iIx[ix];
       
  2204 	ASSERT(e.iType == CCommSubSession::ENull);
       
  2205 	iFreeListHead = e.iNextFree;
       
  2206 	ASSERT(TUint(iFreeListHead) <= TUint(iSize));
       
  2207 	e.iObject = aSubSession;
       
  2208 	e.iType = TUint8(aSubSession->Type());
       
  2209 	TInt magic = (e.iMagic + 1) & KMagicMask;
       
  2210 	e.iMagic = TUint16(magic);
       
  2211 	aHandle = MakeHandle(ix, magic, e.iType);
       
  2212 	++iActiveCount;
       
  2213 	return KErrNone;
       
  2214 	}
       
  2215 
       
  2216 CCommSubSession* CC32SubSessionIx::Remove(TSubSessionHandle aHandle)
       
  2217 	{
       
  2218 	iLock.AssertLockHeld();
       
  2219 	ASSERT(TUint(iFreeListHead) <= TUint(iSize));
       
  2220 	TEntry* e = At(aHandle);
       
  2221 	ASSERT(e);
       
  2222 	CCommSubSession* subSess = e->iObject;
       
  2223 	e->iType = TUint8(CCommSubSession::ENull);
       
  2224 	e->iNextFree = iFreeListHead;
       
  2225 	iFreeListHead = e - &iIx[0];
       
  2226 	ASSERT(TUint(iFreeListHead) < TUint(iSize));
       
  2227 	--iActiveCount;
       
  2228 	return subSess;
       
  2229 	}
       
  2230 
       
  2231 CCommSubSession* CC32SubSessionIx::At(TInt aHandle, CCommSubSession::TSubSessionType aType) const
       
  2232 	{
       
  2233 	iLock.AssertLockHeld();
       
  2234 	TEntry* e = At(aHandle);
       
  2235 	if(e && (e->iType == aType || aType == CCommSubSession::EAny))
       
  2236 		{
       
  2237 		return e->iObject;
       
  2238 		}
       
  2239 	return NULL;
       
  2240 	}
       
  2241 
       
  2242 CC32SubSessionIx::TEntry* CC32SubSessionIx::At(TSubSessionHandle aHandle) const
       
  2243 	{
       
  2244 	TEntry* e = 0;
       
  2245 	TInt ix = IndexFromHandle(aHandle);
       
  2246 	if(TUint(ix) < TUint(iSize))
       
  2247 		{
       
  2248 		e = &iIx[ix];
       
  2249 		if(MakeHandle(ix, e->iMagic, e->iType) != aHandle)
       
  2250 			{
       
  2251 			e = 0;
       
  2252 			}
       
  2253 		}
       
  2254 	return e;
       
  2255 	}
       
  2256 
       
  2257 TInt CC32SubSessionIx::ExpandArray()
       
  2258 	{
       
  2259 	ASSERT(TUint(iFreeListHead) <= TUint(iSize));
       
  2260 	TInt size = iSize + EIndexGranularity;
       
  2261 	if(size > KIndexLimit)
       
  2262 		{
       
  2263 		return KErrNoMemory;
       
  2264 		}
       
  2265 	TEntry* ix = reinterpret_cast<TEntry*>(User::ReAlloc(iIx, size * sizeof(TEntry)));
       
  2266 	if(!ix)
       
  2267 		{
       
  2268 		return KErrNoMemory;
       
  2269 		}
       
  2270 	iIx = ix;
       
  2271 	iSize = size;
       
  2272 	for(TInt ii = iFreeListHead; ii < size;)
       
  2273 		{
       
  2274 		TEntry& e = ix[ii];
       
  2275 		e.iNextFree = ++ii;
       
  2276 		e.iType = TUint8(CCommSubSession::ENull);
       
  2277 		}
       
  2278 	return KErrNone;
       
  2279 	}
       
  2280 
       
  2281 CC32SubSessionIx::TIter::TIter(CC32SubSessionIx& aContainer)
       
  2282 : iContainer(aContainer)
       
  2283 	{
       
  2284 	SetToFirst();
       
  2285 	}
       
  2286 
       
  2287 void CC32SubSessionIx::TIter::SetToFirst()
       
  2288 	{
       
  2289 	iPos = 0;
       
  2290 	}
       
  2291 
       
  2292 CCommSubSession* CC32SubSessionIx::TIter::operator++(TInt)
       
  2293 	{
       
  2294 	TSubSessionHandle dummyHandle;
       
  2295 	return Next(dummyHandle);
       
  2296 	}
       
  2297 
       
  2298 CCommSubSession* CC32SubSessionIx::TIter::Next(TSubSessionHandle& aHandle)
       
  2299 	{
       
  2300 	iContainer.iLock.AssertLockHeld();
       
  2301 	TEntry* e = &iContainer.iIx[iPos];
       
  2302 	while(iPos < iContainer.iSize)
       
  2303 		{
       
  2304 		TInt oldPos = iPos++;
       
  2305 		if(e->iType != CCommSubSession::ENull)
       
  2306 			{
       
  2307 			aHandle = iContainer.MakeHandle(oldPos, e->iMagic, e->iType);
       
  2308 			return e->iObject;
       
  2309 			}
       
  2310 		++e;
       
  2311 		}
       
  2312 	return NULL;
       
  2313 	}
       
  2314 
       
  2315 
       
  2316 //
       
  2317 //	CC32Player class definitions
       
  2318 //
       
  2319 
       
  2320 
       
  2321 CC32Player* CC32Player::NewL(CC32WorkerThread* aOwnerThread)
       
  2322 	{
       
  2323 	CC32Player* self = new(ELeave) CC32Player(aOwnerThread);
       
  2324 	CleanupStack::PushL(self);
       
  2325 	self->ConstructL();
       
  2326 	CleanupStack::Pop(self);
       
  2327 	return self;
       
  2328 	}
       
  2329 
       
  2330 CC32Player::CC32Player(CC32WorkerThread* aOwnerThread)
       
  2331 : iOwnerThread(aOwnerThread)
       
  2332 	{
       
  2333 	}
       
  2334 
       
  2335 void CC32Player::ConstructL()
       
  2336 	{
       
  2337 	iPortManager = CPortManager::NewL();
       
  2338 	}
       
  2339 
       
  2340 /** 
       
  2341 The Player destructor doesn't have much to do as a lot of the cleanup is done during the
       
  2342 normal shutdown routines. Here the Player merely deletes all sub-sessions it owns. 
       
  2343 */
       
  2344 CC32Player::~CC32Player()
       
  2345 	{
       
  2346 	// The object container is stored as a packed array, so working backwards through it avoids invalidating
       
  2347 	// the iterator when removing entries (and as a bonus is more efficient)
       
  2348 	C32LOG1(KC32Shutdown, _L8("CC32Player::~CC32Player()"));
       
  2349 	for(TInt i = iSubSessions.Count() - 1; i >= 0; --i)
       
  2350 		{
       
  2351 		CCommSubSession* subSession = iSubSessions[i];
       
  2352 		C32LOG2(KC32Shutdown, _L8("-- destroying -- %08x"), subSession );
       
  2353 		// This subsession needs deletion, which we do by closing it until it disappears
       
  2354 		// (generally this should only require a single close, but it's possible that the
       
  2355 		// Dealer died with it additionally open)
       
  2356 		ASSERT(subSession);
       
  2357 		ASSERT(subSession->AccessCount() > 0);
       
  2358 		// Following logic presumes that each Close() decrements AccessCount() by one;
       
  2359 		// anything else is too broken for words
       
  2360 		for(TInt cnt = subSession->AccessCount(); cnt > 0; --cnt)
       
  2361 			{
       
  2362 			CPort* p = CPortFromSubSession(subSession);		// subSession->iPort
       
  2363 			p->Close();							// close CPort
       
  2364 			subSession->Close();				// close CCommSubSession
       
  2365 			}
       
  2366 		}
       
  2367 	iSubSessions.ResetAndDestroy();
       
  2368 	delete iPortManager;
       
  2369 	iPortManager = NULL;
       
  2370 	}
       
  2371 
       
  2372 /**
       
  2373 The Player can unbind from another worker thread if it doesn't have any sub-sessions 
       
  2374 belonging to a session in the peer. 
       
  2375 */
       
  2376 TBool CC32Player::CanUnbindFromWorker(TWorkerId aWorker)
       
  2377 	{
       
  2378 	C32LOG3(KC32Bootup, _L8("CC32Player::CanUnbindFromWorker(%d): %d subsess"), aWorker, iSubSessions.Count() );
       
  2379 	for(TInt idx = iSubSessions.Count() - 1; idx >= 0; --idx)
       
  2380 		{
       
  2381 		CCommSubSession* ss = iSubSessions[idx];
       
  2382 		C32LOG3(KC32Bootup, _L8("-- subsess %08x worker=%d"), ss, ss->Session()->WorkerId());
       
  2383 		if(iSubSessions[idx]->Session()->WorkerId() == aWorker)
       
  2384 			{
       
  2385 			return EFalse;
       
  2386 			}
       
  2387 		}
       
  2388 	return ETrue;
       
  2389 	}
       
  2390 
       
  2391 /** 
       
  2392 Check whether the Player is ready to shut down and if so, tells the Worker Thread who owns it. 
       
  2393 */
       
  2394 void CC32Player::MaybeSetPlayerShutdownComplete(TBool aForceShutdownNow)
       
  2395 	{
       
  2396 	TBool shutdownNow = aForceShutdownNow || (iSubSessions.Count() == 0);
       
  2397 	C32LOG4(KC32Bootup, _L8("CC32Player::MaybeSetPlayerShutdownComplete(), shutdownNow = %d [forced=%d, #subSess=%d]"), 
       
  2398 		shutdownNow, aForceShutdownNow, iSubSessions.Count() );
       
  2399 	WorkerThread().SetPlayerShutdownComplete(shutdownNow);
       
  2400 	}
       
  2401 
       
  2402 /**
       
  2403 If an incoming shutdown request is of type EImmediate, informs the
       
  2404 Worker Thread that Player shutdown is complete, otherwise do nothing here. 
       
  2405 */
       
  2406 void CC32Player::ProcessShutdownRequest(CommsFW::TCFShutdownType aType)
       
  2407 	{
       
  2408 	C32LOG2(KC32Bootup, _L8("CC32Player::ProcessShutdownRequest(%d)"), aType );
       
  2409 	WorkerThread().SetPlayerShutdownComplete(aType == EImmediate);
       
  2410 	}
       
  2411 
       
  2412 void CC32Player::ProcessUnLoadCommModuleMsg(CSerial* aSerial)
       
  2413 	{
       
  2414 	__ASSERT_DEBUG(aSerial != NULL, Fault(EBadState, _L8("NULL CSerial* passed to player !")));
       
  2415 	__ASSERT_DEBUG(aSerial->AccessCount() > 0, Fault(EBadState, _L8("CC32Player::ProcessUnLoadCommModuleMsg - AccessCount < 0 before Close()")));
       
  2416 	if(aSerial->AccessCount() > 0)
       
  2417 		{
       
  2418 		aSerial->Close();
       
  2419 		}
       
  2420 	else
       
  2421 		{
       
  2422 		C32LOG2(KC32Warning, _L8("CC32Player::ProcessUnLoadCommModuleMsg - AccessCount negative  %d, Cannot call close()"), aSerial->AccessCount() );
       
  2423 		}
       
  2424 	return;
       
  2425 	}
       
  2426 
       
  2427 /**
       
  2428 Write a handle back to Ptr3 of the current message
       
  2429 */
       
  2430 TInt CC32Player::WriteSubSessionHandle(TInt aHandle)
       
  2431 	{
       
  2432 	TPckgC<TInt> pH(aHandle);
       
  2433 	return iSession->Write(MSG_PRM(3), Message(),pH);
       
  2434 	}
       
  2435 
       
  2436 // CC32Player::CloseSubSession closes a CPort so CommCancel is not used.
       
  2437 void CC32Player::CloseSubSession(const RMessage2& aMessage, CCommSubSession* aSubSession)
       
  2438 	{
       
  2439 	ASSERT(aSubSession);
       
  2440 	CPort* p = CPortFromSubSession(aSubSession);
       
  2441 	C32LOG1(KC32Player, _L8("CC32Player::CloseSubSession"));
       
  2442 	p->FreeSession(aSubSession->Session());		// check if CPort can be freed in this session
       
  2443 	p->Close();								// close CPort
       
  2444 	if(aSubSession->AccessCount()==1)
       
  2445 	// the access count == 1 and subsession is being closed. Remove subsession from session's CC32SubSessionIx
       
  2446 		{
       
  2447 		aSubSession->Session()->SubSessions().Lock();
       
  2448 		TInt handle;
       
  2449 		TInt res = CC32DealerByRef().FindSubSession(aSubSession, aSubSession->Session(), handle); 
       
  2450 		if(res == KErrNone)
       
  2451 			{
       
  2452 			CC32DealerByRef().RemoveSubSession(handle, aSubSession->Session());
       
  2453 			}
       
  2454 		else
       
  2455 			{
       
  2456 			__ASSERT_DEBUG(EFalse, Fault(EFindSubSessionFailed, _L8("Could not find subsession in CC32SubSessionIx while subsession count is 1")));
       
  2457 			}
       
  2458 		aSubSession->Session()->SubSessions().Unlock();
       
  2459 		}
       
  2460 	aSubSession->Close();	// close CCommSubSession, removes from TSubSessionContainer if access count drops to zero
       
  2461 	SafeComplete(aMessage, KErrNone);
       
  2462 	}
       
  2463 
       
  2464 /**
       
  2465 This method is uses for example when the session is closed by the client whilst still having
       
  2466 active sub-sessions. All outstanding requests on CPort are cancelled using CPort::CommCancel
       
  2467 @see CC32Player::CloseSession
       
  2468 */
       
  2469 void CC32Player::CloseAllOwnedSubSessions(CCommSession* aSession)
       
  2470 	{
       
  2471 	// The object container is stored as a packed array, so working backwards through it avoids invalidating
       
  2472 	// the iterator when removing entries (and as a bonus is more efficient)
       
  2473 	C32LOG2(KC32Player, _L8("CC32Player::CloseAllOwnedSubSessions() subsessions in TSubSessionContainer = %d"), iSubSessions.Count() );
       
  2474 	for(TInt i = iSubSessions.Count() - 1; i >= 0; --i)
       
  2475 		{
       
  2476 		CCommSubSession* subSession = iSubSessions[i];
       
  2477 		if(subSession->Session() == aSession)		// close subsessions belonging to the closing session
       
  2478 			{
       
  2479 			C32LOG2(KC32Player, _L8("CC32Player::CloseAllOwnedSubSessions()-closing subsession %x"), iSubSessions[i] );
       
  2480 			// close all subSessions in 'this' aSession as session is being closed.
       
  2481 			// may not lead to ~CPort being called if CPort is being shared across sessions
       
  2482 			// AccessCount of all subsession = AccessCount of CPort
       
  2483 			while(subSession->AccessCount() >= 1)
       
  2484 				{
       
  2485 				CPort* p = CPortFromSubSession(subSession);		// subSession->iPort
       
  2486 				C32LOG3(KC32Player, _L8("CC32Player::CloseAllOwnedSubSessions()-Closing CPort %x for subsession %x"),p, iSubSessions[i] );
       
  2487 				p->CommCancel(0, aSession);	// cancel all outstanding requests
       
  2488 				p->Close();					// close all CPorts in this session
       
  2489 				if (subSession->AccessCount() == 1)
       
  2490                     {
       
  2491                     subSession->Close();        // close CCommSubSession. This also deletes object
       
  2492                     break; //avoid accessing deleted subSession object 
       
  2493                     }
       
  2494                 else
       
  2495                     {
       
  2496                     subSession->Close();        // close CCommSubSession
       
  2497                     }
       
  2498 				}
       
  2499 			}
       
  2500 		}
       
  2501 	}
       
  2502 
       
  2503 /** 
       
  2504 Used when the dealer signals it is closing a session and the Player needs to cleanup 
       
  2505 all resources related to/owned by the session.
       
  2506 @see TPlayerMsg::ESessionClose
       
  2507 */
       
  2508 void CC32Player::CloseSession(CCommSession* aSession)
       
  2509 	{
       
  2510 	// Remove all subsessions in this aSession
       
  2511 	CloseAllOwnedSubSessions(aSession);
       
  2512 	}
       
  2513 
       
  2514 #ifdef _DEBUG
       
  2515 // I'm worried that we'll have dangling session usage, hence this debug-build deliberate
       
  2516 // corruption of it
       
  2517 static void CorruptSessionPointer(TAny* aSessionPtr)
       
  2518 	{
       
  2519 	CCommSession** sessPtr = reinterpret_cast<CCommSession** >(aSessionPtr);
       
  2520 	*sessPtr = reinterpret_cast<CCommSession* >(-1);
       
  2521 	}
       
  2522 #endif
       
  2523 
       
  2524 CPort* CC32Player::CPortFromSubSession(CCommSubSession* aSubSession)
       
  2525 	{
       
  2526 	return aSubSession->iPort;
       
  2527 	}
       
  2528 
       
  2529 /** 
       
  2530 Process the client message forwarded from the Dealer. For subsession-Close commands
       
  2531 the Dealer provides the subsession pointer explicitly as it has already been removed from
       
  2532 the index. 
       
  2533 */
       
  2534 void CC32Player::ProcessMessageL(const RMessage2& aMessage, CCommSubSession* aSubSession)
       
  2535 	{
       
  2536 	iSession = static_cast<CCommSession*>(aMessage.Session());
       
  2537 	iCurrentMessage = &aMessage;
       
  2538 	C32LOG4(KC32Player, _L8("CC32Player:\tProcessMessageL: session=%08x, subsess=%08x, Message(%08x) "), iSession, aSubSession, aMessage.Handle());	
       
  2539 	iComplete = ETrue;
       
  2540 #ifdef _DEBUG
       
  2541 	CleanupStack::PushL(TCleanupItem(CorruptSessionPointer, &iSession));
       
  2542 #endif
       
  2543 
       
  2544 	switch (aMessage.Function())
       
  2545         {
       
  2546 	case ECommLoadCommModule:
       
  2547 		LoadCommModule(aMessage);	
       
  2548 #ifdef _DEBUG
       
  2549 		CleanupStack::PopAndDestroy();
       
  2550 #endif
       
  2551 		return;
       
  2552 	case ECommCloseCommModule:
       
  2553 		CloseCommModule(aMessage);
       
  2554 #ifdef _DEBUG
       
  2555 		CleanupStack::PopAndDestroy();
       
  2556 #endif
       
  2557 		return;
       
  2558 	case ECommPortInfoByName:
       
  2559 		{
       
  2560 		TPortName name;
       
  2561 		Read(1,aMessage,name);
       
  2562 		PortInfo(aMessage,name);
       
  2563 #ifdef _DEBUG
       
  2564 		CleanupStack::PopAndDestroy();
       
  2565 #endif
       
  2566 		return;
       
  2567 		}
       
  2568 	//case ECommPortInfoByNumber:	as the global index is not valid in player !
       
  2569 	// instead CSerial* is forwarded to player to obtain PortInfo through TC32PlayerGetPortInfoMsg msg
       
  2570         }
       
  2571 
       
  2572 	if((aMessage.Function()==ECommOpen)
       
  2573 	   ||
       
  2574 	   (aMessage.Function()==ECommOpenWhenAvailable))
       
  2575 		{
       
  2576 		NewPortL(aMessage);
       
  2577 #ifdef _DEBUG
       
  2578 		CleanupStack::PopAndDestroy();
       
  2579 #endif
       
  2580 		return;
       
  2581 		}
       
  2582 
       
  2583 	if (aMessage.Function()==ECommClose)
       
  2584 		{
       
  2585 		CloseSubSession(aMessage, aSubSession);
       
  2586 #ifdef _DEBUG
       
  2587 		CleanupStack::PopAndDestroy();
       
  2588 #endif
       
  2589 		return;
       
  2590 		}
       
  2591 	
       
  2592 	CPort *p = CPortFromSubSession(aSubSession);
       
  2593 	
       
  2594 	if(p->SessionHasBeenPreempted(iSession))
       
  2595 		{
       
  2596 		SafeComplete(aMessage, KErrCancel);
       
  2597 #ifdef _DEBUG
       
  2598 		CleanupStack::PopAndDestroy();
       
  2599 #endif
       
  2600 		return;
       
  2601 		}
       
  2602 
       
  2603 	// These functions need to be dispatched before the check below is made
       
  2604 	if(aMessage.Function()==ECommSetAccess)
       
  2605 		{
       
  2606 		p->CommSetAccess(aMessage, *iSession);
       
  2607 #ifdef _DEBUG
       
  2608 		CleanupStack::PopAndDestroy();
       
  2609 #endif
       
  2610 		return;
       
  2611 		}
       
  2612 	else if(aMessage.Function()==ECommOpenWhenAvailableCancel)
       
  2613 		{
       
  2614 		if (p->IsBlockedSetAccessWaiting(*iSession))
       
  2615 			{
       
  2616 			p->CommSetAccessCancel(0, iSession);
       
  2617 			SafeComplete(aMessage, KErrNone);
       
  2618 			}
       
  2619 		else
       
  2620 			{
       
  2621 			SafeComplete(aMessage, KErrNotFound);
       
  2622 			}
       
  2623 
       
  2624 #ifdef _DEBUG
       
  2625 		CleanupStack::PopAndDestroy();
       
  2626 #endif
       
  2627 		return;
       
  2628 		}
       
  2629 
       
  2630 	// Any other requests will be denied until the port is fully open
       
  2631 	if(p->SessionIsAwaitingOpen(iSession))
       
  2632 		{
       
  2633 		SafeComplete(aMessage, KErrNotReady);
       
  2634 #ifdef _DEBUG
       
  2635 		CleanupStack::PopAndDestroy();
       
  2636 #endif
       
  2637 		return;
       
  2638 		}
       
  2639 
       
  2640 	switch (aMessage.Function())
       
  2641        {
       
  2642     case ECommRead:
       
  2643     	p->CommRead(aMessage, iSession);
       
  2644     	break;
       
  2645 	case ECommReadCancel:
       
  2646 		p->CommReadCancel(aMessage.Int3(), iSession);
       
  2647 		SafeComplete(aMessage, KErrNone);
       
  2648 		break;
       
  2649 	case ECommQueryReceiveBuffer:
       
  2650 		p->CommQueryReceiveBuffer(aMessage, *iSession);
       
  2651 		break;
       
  2652 	case ECommResetBuffers:
       
  2653 		p->CommResetBuffers(aMessage, *iSession);
       
  2654 		break;
       
  2655 	case ECommWrite:
       
  2656 		p->CommWrite(aMessage, iSession);
       
  2657 		break;
       
  2658 	case ECommWriteCancel:
       
  2659 		p->CommWriteCancel(aMessage.Int3(), iSession);
       
  2660 		SafeComplete(aMessage, KErrNone);
       
  2661 		break;
       
  2662 	case ECommBreak:
       
  2663 		p->CommBreak(aMessage, iSession);
       
  2664 		break;
       
  2665 	case ECommBreakCancel:
       
  2666 		p->CommBreakCancel(aMessage.Int3(), iSession);
       
  2667 		SafeComplete(aMessage, KErrNone);
       
  2668 		break;
       
  2669 	case ECommCancel:
       
  2670 		p->CommCancel(aMessage.Int3(), iSession);
       
  2671 		SafeComplete(aMessage, KErrNone);
       
  2672 		break;
       
  2673 	case ECommConfig:
       
  2674 		p->CommConfig(aMessage, *iSession);
       
  2675 		break;
       
  2676 	case ECommSetConfig:
       
  2677 		p->CommSetConfig(aMessage, *iSession);
       
  2678 		break;
       
  2679 	case ECommCaps:
       
  2680 		p->CommCaps(aMessage, *iSession);
       
  2681 		break;
       
  2682 	case ECommSetMode:
       
  2683 		p->CommSetServerConfig(aMessage, *iSession);
       
  2684 		break;
       
  2685 	case ECommGetMode:
       
  2686 		p->CommGetServerConfig(aMessage, *iSession);
       
  2687 		break;
       
  2688 	case ECommSignals:
       
  2689 		p->CommSignals(aMessage, *iSession);
       
  2690 		break;
       
  2691 	case ECommSetSignalsToMark:
       
  2692 		p->CommSetSignalsToMark(aMessage, *iSession);
       
  2693 		break;
       
  2694 	case ECommSetSignalsToSpace:
       
  2695 		p->CommSetSignalsToSpace(aMessage, *iSession);
       
  2696 		break;
       
  2697 	case ECommReceiveBufferLength:
       
  2698 		p->CommReceiveBufferLength(aMessage, *iSession);
       
  2699 		break;
       
  2700 	case ECommSetReceiveBufferLength:
       
  2701 		p->CommSetReceiveBufferLength(aMessage, *iSession);
       
  2702 		break;
       
  2703 	case ECommSetAccess:
       
  2704 		p->CommSetAccess(aMessage, *iSession);
       
  2705 		break;
       
  2706 
       
  2707 #ifdef _DEBUG
       
  2708 	case ECommDebugState:
       
  2709 		p->CommDebugState( aMessage, *iSession);
       
  2710 		break;
       
  2711 #endif
       
  2712 
       
  2713 #ifdef _DEBUG_DEVCOMM
       
  2714 	case ECommDbgDoDumpDebugInfo:
       
  2715 		p->CommDumpDebugInfo(aMessage);
       
  2716 		break;
       
  2717 #endif
       
  2718        }
       
  2719 
       
  2720 	// Extensions to the CCommSession starts from here
       
  2721    	switch (aMessage.Function())
       
  2722         {
       
  2723 	case ECommNotifySignals:
       
  2724 		p->CommNotifySignalChange(aMessage, iSession);
       
  2725 		break;
       
  2726 	case ECommNotifySignalsCancel:
       
  2727 		p->CommNotifySignalChangeCancel(aMessage.Int3(), iSession);
       
  2728 		SafeComplete(aMessage, KErrNone);
       
  2729 		break;
       
  2730 	case ECommNotifyFlowControl:
       
  2731 		p->CommNotifyFlowControlChange(aMessage, iSession);
       
  2732 		break;
       
  2733 	case ECommNotifyFlowControlCancel:
       
  2734 		p->CommNotifyFlowControlChangeCancel(aMessage.Int3(), iSession);
       
  2735 		SafeComplete(aMessage, KErrNone);	
       
  2736 		break;
       
  2737 	case ECommGetFlowControl:
       
  2738 		p->CommGetFlowControlStatus(aMessage, iSession);
       
  2739 		break;			
       
  2740 	case ECommNotifyConfigChange:
       
  2741 		p->CommNotifyConfigChange(aMessage, iSession);
       
  2742 		break;
       
  2743 	case ECommNotifyConfigChangeCancel:
       
  2744 		p->CommNotifyConfigChangeCancel(aMessage.Int3(), iSession);
       
  2745 		SafeComplete(aMessage, KErrNone);
       
  2746 		break;
       
  2747 	case ECommNotifyBreak:
       
  2748 		p->CommNotifyBreak(aMessage, iSession);
       
  2749 		break;
       
  2750 	case ECommNotifyBreakCancel:
       
  2751 		p->CommNotifyBreakCancel(aMessage.Int3(), iSession);
       
  2752 		SafeComplete(aMessage, KErrNone);
       
  2753 		break;
       
  2754 	case ECommGetRole:
       
  2755 		p->CommGetRole(aMessage, iSession);
       
  2756 		break;
       
  2757 	case ECommNotifyDataAvailable:
       
  2758 		p->CommNotifyDataAvailable(aMessage, iSession);
       
  2759 		break;
       
  2760 	case ECommNotifyDataAvailableCancel:
       
  2761 		p->CommNotifyDataAvailableCancel(aMessage.Int3(), iSession);
       
  2762 		SafeComplete(aMessage, KErrNone);
       
  2763 		break;
       
  2764 	case ECommNotifyOutputEmpty:
       
  2765 		p->CommNotifyOutputEmpty(aMessage, iSession);
       
  2766 		break;
       
  2767 	case ECommNotifyOutputEmptyCancel:
       
  2768 		p->CommNotifyOutputEmptyCancel(aMessage.Int3(), iSession);
       
  2769 		SafeComplete(aMessage, KErrNone);	
       
  2770 		break;
       
  2771 	// case default: 	// no default case here as it is dealt with in CCommSession::ServiceL
       
  2772 		}
       
  2773 	// Extensions to the CCommSession ends to here
       
  2774 #ifdef _DEBUG
       
  2775 	CleanupStack::PopAndDestroy();  // TCleanupItem(CorruptSessionPointer, &iSession));
       
  2776 #endif
       
  2777 	}
       
  2778 
       
  2779 void CC32Player::SafeComplete(const RMessagePtr2& aMessage, TInt aCompletionCode)
       
  2780 	{
       
  2781 	if(iComplete)
       
  2782 		{
       
  2783 		::SafeComplete(aMessage, aCompletionCode);
       
  2784 		}
       
  2785 	}
       
  2786 
       
  2787 void CC32Player::DontCompleteCurrentRequest()
       
  2788 	{
       
  2789 	iComplete = EFalse;
       
  2790 	}
       
  2791 
       
  2792 void CC32Player::LoadCommModule(const RMessage2& aMessage)
       
  2793 /**
       
  2794  * Load a comm module
       
  2795  */
       
  2796 	{
       
  2797 	TFileName csyfilename;
       
  2798 	Read(0,aMessage,csyfilename);
       
  2799 
       
  2800 	TInt r=csyfilename.LocateReverse('.');
       
  2801  	if (r==KErrNotFound)
       
  2802 		{
       
  2803 		csyfilename.Append(KCSYExtension);
       
  2804 		}
       
  2805 
       
  2806 	C32LOG3(KC32Player, _L("CC32Player::LoadCommModule : %S. aMessage:%08x"), &csyfilename,aMessage.Handle());
       
  2807 	CSerial *s=NULL;
       
  2808 	TRAPD(res,s=iPortManager->LoadCommModuleL(csyfilename)); // if you see a crash with (iPortManager == null) here, you might have mis-configured cmi files
       
  2809 	if(res == KErrNone)
       
  2810 		{
       
  2811 		// no leave occurred, library loaded successfully ! Send pointers to message, CsyFilename, and portPrefix
       
  2812 		// back to dealer, dealer updates the information in ThreadManager and completes the message
       
  2813 		CC32WorkerThread& owner = WorkerThread();
       
  2814 		if(owner.WorkerId()==TC32WorkerThreadPublicInfo::EMainThread)
       
  2815 			{
       
  2816 			// co-resident player, make direct function call
       
  2817 			owner.Dealer()->ProcessLoadCommModuleSuccessResponse(aMessage, s);
       
  2818 			DontCompleteCurrentRequest();
       
  2819 			}
       
  2820 		else if(owner.PeerReachable(TC32WorkerThreadPublicInfo::EMainThread))
       
  2821 			{
       
  2822 			// different thread, send via transports
       
  2823 			TC32PlayerLoadCommModuleSuccessResp respMsg(aMessage, s);
       
  2824 			owner.PostMessage(TC32WorkerThreadPublicInfo::EMainThread, respMsg);
       
  2825 			DontCompleteCurrentRequest();
       
  2826 			const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage);
       
  2827 			forwardedMsg.NullHandle();
       
  2828 			}
       
  2829 		else
       
  2830 			{
       
  2831 			C32LOG1(KC32Warning, _L8("CC32Player::LoadCommModule() Peer Thread Unreachable"));
       
  2832 			DontCompleteCurrentRequest();
       
  2833 			__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker));
       
  2834 			}
       
  2835 		C32LOG1(KC32Player, _L("CC32Player::LoadCommModule : Load completed successfully - message sent to Dealer"));
       
  2836 			
       
  2837 		}
       
  2838 	else
       
  2839 		{
       
  2840 		// library load failure ! Mesg sent back to dealer to inform of failed load attempt, dealer 
       
  2841 		// removes CSY from session CSY container and de-allocates memory allocated to this to-be-loaded
       
  2842 		// CSY, and completes message with reason of load failure
       
  2843 		CC32WorkerThread& owner = WorkerThread();
       
  2844 		if(owner.WorkerId()==TC32WorkerThreadPublicInfo::EMainThread)
       
  2845 			{
       
  2846 			// co-resident player, make direct function call
       
  2847 			owner.Dealer()->ProcessLoadCommModuleFailureResponse(aMessage, res);
       
  2848 			DontCompleteCurrentRequest();
       
  2849 			}
       
  2850 		else if(owner.PeerReachable(TC32WorkerThreadPublicInfo::EMainThread))
       
  2851 			{
       
  2852 			// different thread, send via transports
       
  2853 			TC32PlayerLoadCommModuleFailureResp respMsg(aMessage, res);
       
  2854 			owner.PostMessage(TC32WorkerThreadPublicInfo::EMainThread, respMsg);
       
  2855 			DontCompleteCurrentRequest();
       
  2856 			const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage);
       
  2857 			forwardedMsg.NullHandle();
       
  2858 			}
       
  2859 		else
       
  2860 			{
       
  2861 			C32LOG1(KC32Warning, _L8("CC32Player::LoadCommModule() Peer Thread Unreachable"));
       
  2862 			DontCompleteCurrentRequest();
       
  2863 			__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker));
       
  2864 			}
       
  2865 		}
       
  2866 	}
       
  2867 
       
  2868 void CC32Player::CloseCommModule(const RMessage2& aMessage)
       
  2869 /**
       
  2870  * Close a comm module
       
  2871  */
       
  2872 	{
       
  2873 	TFullName name;      // not a TPortName for backwards compat reasons
       
  2874 	Read(0,aMessage,name);
       
  2875 	C32LOG2(KC32Player, _L("CC32Player::CloseCommModule() called, CommModule : %S"), &name);
       
  2876 	CSerial* s=NULL;
       
  2877 	TRAPD(res,s=iPortManager->GetSerialL(name));
       
  2878 	if (res==KErrNone)
       
  2879 		{
       
  2880 		s->Close();		// call Close() on CSerial object
       
  2881 		}
       
  2882 	SafeComplete(aMessage, res);
       
  2883 	}
       
  2884 
       
  2885 void CC32Player::NewPortL(const RMessage2& aMessage)	// do we need to pass CCommSession* here ?
       
  2886 /**
       
  2887  * Ask the port manager to open a port in the CSY which is then added
       
  2888  * to this session's port list (CC32SubSessionIx). If another session 
       
  2889  * has already opened the same port, the port manager will still give 
       
  2890  * us a reference if the port is not being used exclusively.
       
  2891  *
       
  2892  * @param aMessage handle to the IPC message from the client
       
  2893  */
       
  2894 	{
       
  2895 	C32LOG1(KC32Player, _L8("CC32Player::NewPortL()"));
       
  2896 	iSession = static_cast<CCommSession*>(aMessage.Session());
       
  2897 	C32LOG3(KC32Player, _L8("CC32Player:NewPort: session=%08x, Message(%08x) "), iSession, aMessage.Handle());	
       
  2898 	CPort *p=NULL;
       
  2899 	CSerial *s=NULL;
       
  2900 	TFullName name;
       
  2901 	TUint port;
       
  2902 	TInt len;
       
  2903 	TInt handle;
       
  2904 
       
  2905 	// Extract port name and number
       
  2906 	VERIFY_RESULT(ExtractPortNameAndNumber(aMessage, name, port, len), KErrNone);	 // must be valid as it is already checked in dealer
       
  2907 	TRAPD(res,s=iPortManager->GetSerialL(name.Left(len)));
       
  2908 	/**
       
  2909 	We can't ASSERT here as the client should have loaded the CSY before opening the port.
       
  2910 	This will fail only in the circumstance when the other session unloads the Comm Module and
       
  2911 	by the  time message is received on player, the GetSerial fails due to module not present.
       
  2912 	*/
       
  2913 	if (res!=KErrNone)
       
  2914 		{
       
  2915 		SafeComplete(aMessage, res);
       
  2916 		return;
       
  2917 		}
       
  2918 	if(aMessage.Function()==ECommOpenWhenAvailable)
       
  2919 		{
       
  2920 		// This default role, as specified in aMessage.Int2(), will only be used
       
  2921 		// if the port is being opened for the first time
       
  2922 		TRAP(res,p=iPortManager->GetPortL(name,port,s,(TUint)EIntCommWaitUntilAvailable,
       
  2923 												(TUint)aMessage.Int2(), iSession));
       
  2924 		}
       
  2925 	else
       
  2926 		{
       
  2927 		TRAP(res,p=iPortManager->GetPortL(name,port,s,aMessage.Int1(),aMessage.Int2(), iSession));
       
  2928 		}
       
  2929 
       
  2930 	if(res!=KErrNone)
       
  2931 		{
       
  2932 		SafeComplete(aMessage, res);
       
  2933 		return;
       
  2934 		}
       
  2935 	else
       
  2936 		{
       
  2937 		/** no leaves occurred, either new or existing CPort opened successfully
       
  2938 		* Iterate through TSubSessionContainer if (p==CPortFromSubSession() && subSess->Session() == iSession)
       
  2939 		* call subSess->Open() so that its AccessCount is incremented else 
       
  2940 		* create a "new" subsession. Iterating the TSubSessionContainer won't
       
  2941 		* be a performance bottleneck as RComm::Open() call is made only once
       
  2942 		*/
       
  2943 		TBool existingSubSess = EFalse;			// Set ETrue when existing subsession found
       
  2944 		TInt idxFound = 0;			// stores the index of existing sub-session from TSubSessionContainer
       
  2945 		for(TInt i = iSubSessions.Count() - 1; i >= 0; --i)
       
  2946 			{
       
  2947 			if(CPortFromSubSession(iSubSessions[i]) == p && iSubSessions[i]->Session() == iSession)	// check for existing CPort* && check for session
       
  2948 				{
       
  2949 				existingSubSess=ETrue;		// existing CPort* found which is this session
       
  2950 				idxFound = i;				// store index
       
  2951 				break;
       
  2952 				}
       
  2953 			}
       
  2954 
       
  2955 		if(existingSubSess == EFalse)
       
  2956 			{
       
  2957 			/** new SubSession
       
  2958 			* create "new" subsession
       
  2959 			* Add CPort* (p) to this newly created subsession
       
  2960 			* Add CCommSubSession to TSubSessionContainer
       
  2961 			* Add CCommSubSession* to CC32SubSessionIx to obtain subsession handle
       
  2962 			* Write the handle back to client
       
  2963 			* if writing handle back to client fails, remove subsession from CC32SubSessionIx
       
  2964 			*/
       
  2965 			
       
  2966 			C32LOG1(KC32Player, _L8("CC32Player::NewPortL() - NEW SUBSESSION"));
       
  2967 			CCommSubSession* css = CCommSubSession::NewL(iSession, p, this); 	// create CCommSubSession	
       
  2968 			res = iSubSessions.Append(css);		// add to TSubSessionContainer
       
  2969 			if(res != KErrNone)
       
  2970 				{
       
  2971 				css->Close();		// Close() newly created sub-session (which will delete it as accesscount = 1) this could not be appended to TSubSessionContainer
       
  2972 				SafeComplete(aMessage, res);	// complete message with error returned from Append
       
  2973 				return;
       
  2974 				}
       
  2975 			// lock SubSessionIx container in dealer and obtain "new" TSubSessionHandle - TInt
       
  2976 			iSession->SubSessions().Lock();
       
  2977 			res = CC32DealerByRef().AddSubSession(css, iSession, handle);
       
  2978 			if(res == KErrNone)
       
  2979 				{
       
  2980 				// write subsession handle to client
       
  2981 				res = WriteSubSessionHandle(handle);
       
  2982 				if(res != KErrNone)	// if cannot write handle to client
       
  2983 					{
       
  2984 					// we can remove the index from CC32SubSessionIx for this session as its a new subSess
       
  2985 					CC32DealerByRef().RemoveSubSession(handle, iSession);
       
  2986 					}
       
  2987 				}
       
  2988 			iSession->SubSessions().Unlock();
       
  2989 			
       
  2990 			if(res != KErrNone)		// if cannot write handle to client
       
  2991 				{
       
  2992 				p->Close();			// close CPort
       
  2993 				css->Close();	// close CCommSubSession, removes from TSubSessionContainer if access count drops to zero.
       
  2994 				}
       
  2995 			
       
  2996 			SafeComplete(aMessage, res);
       
  2997 			return;
       
  2998 			}
       
  2999 		else
       
  3000 			{
       
  3001 			/** existing SubSession, 
       
  3002 			* call Open() on subSess to increment AccessCount
       
  3003 			* CC32Dealer::FindSubSession() to find subsession aHandle
       
  3004 			* write the aHandle back to client
       
  3005 			* if writing handle back to client, call Close() on subsession and CPort to decrement reference counts
       
  3006 			*/
       
  3007 			C32LOG1(KC32Player, _L8("CC32Player::NewPortL() - EXISTING SUBSESSION"));		
       
  3008 			iSubSessions[idxFound]->Open();		// increment AccessCount
       
  3009 
       
  3010 			// lock SubSessionIx container in dealer
       
  3011 			iSession->SubSessions().Lock();
       
  3012 			// find existing sub-session from this session's CC32SubSessionIx
       
  3013 			res = CC32DealerByRef().FindSubSession(iSubSessions[idxFound], iSession, handle); // should not fail
       
  3014 			if(res != KErrNone)
       
  3015 				{
       
  3016 				C32LOG1(KC32Warning, _L8("CC32Player::NewPortL() - Failed to find existing sub-session in this session "));
       
  3017 				}
       
  3018 			__ASSERT_DEBUG(res == KErrNone, Fault(EFindSubSessionFailed));
       
  3019 			// write existing or new subsession handle back to client
       
  3020 			res = WriteSubSessionHandle(handle);
       
  3021 
       
  3022 			iSession->SubSessions().Unlock();			
       
  3023 
       
  3024 			if(res != KErrNone)		// if cannot write handle to client
       
  3025 				{
       
  3026 				p->Close();			// close CPort
       
  3027 				iSubSessions[idxFound]->Close();	// close CCommSubSession
       
  3028 				}
       
  3029 			
       
  3030 			SafeComplete(aMessage, res);
       
  3031 			return;
       
  3032 			}
       
  3033 		}
       
  3034 	}
       
  3035 
       
  3036 TInt CC32Player::ExtractPortNameAndNumber(const RMessagePtr2& aMessage, TDes& aPortName, TUint& aPortNumber, TInt& aLength) 
       
  3037 /**
       
  3038 Extract the port name and number from RMessage
       
  3039 */
       
  3040 	{
       
  3041   	Read(0,aMessage, aPortName);
       
  3042 	
       
  3043 	_LIT(KDoubleColon, "::");
       
  3044 	aLength = aPortName.Find(KDoubleColon);
       
  3045 	if (aLength == KErrNotFound)
       
  3046 		{
       
  3047 		return KErrNotFound;
       
  3048 		}
       
  3049 	// extract the numeric value after ::
       
  3050 	TInt numPos = aLength + KDoubleColon.iTypeLength;
       
  3051 	TPtrC numPtr(&aPortName[numPos], aPortName.Length() - numPos);
       
  3052 	TLex lexer(numPtr);
       
  3053 	TInt ret = lexer.Val(aPortNumber);
       
  3054 	
       
  3055 	return ret;
       
  3056 	}
       
  3057 
       
  3058 void CC32Player::PortInfo(const RMessage2& aMessage,const TPortName& aPortName)
       
  3059 /**
       
  3060  * Write back the port info to the client for a specified port
       
  3061  *
       
  3062  * @param aPortName name of the port to get information about
       
  3063  */
       
  3064 	{
       
  3065 	TSerialInfo port;
       
  3066 	TInt ret=0;
       
  3067 	if((ret=iPortManager->PortInfo(aPortName,port))==KErrNone)
       
  3068 		{
       
  3069 		TPckgC<TSerialInfo> p(port);
       
  3070 		Write(0,aMessage,p);
       
  3071 		}
       
  3072 	SafeComplete(aMessage, ret);
       
  3073 	}
       
  3074 
       
  3075 void CC32Player::PortInfo(const RMessage2& aMessage, CSerial* aSerialPtr)
       
  3076 /**
       
  3077  * Write back the port info to the client for a specified port
       
  3078  *
       
  3079  * @param aSerial CSerial Pointer obtained by lookup in CC32ThreadManager
       
  3080  */
       
  3081 	{
       
  3082 	iComplete = ETrue;
       
  3083 	TFileName name;
       
  3084 	TSerialInfo port;
       
  3085 	TInt ret=0;
       
  3086 	ASSERT(aSerialPtr);
       
  3087 	aSerialPtr->Info(port);
       
  3088 	aSerialPtr->ModuleName(name);
       
  3089 	TPckgC<TSerialInfo> p(port);
       
  3090 	ret = Write(0,aMessage,p);
       
  3091 	if(ret == KErrNone)	//if not KErrNone then client will already be panic'd so do not atttempt further write as this will panic the server
       
  3092 		{
       
  3093 		Write(1,aMessage,name);	
       
  3094 		}
       
  3095 	SafeComplete(aMessage, ret);
       
  3096 	}
       
  3097 
       
  3098 TInt CC32Player::Write(TInt aPos, const RMessagePtr2& aMessage , const TDesC8& aDes, TInt aOffset)
       
  3099 /**
       
  3100  * Write and kill the client if it leaves.
       
  3101  *
       
  3102  * Copies data from an 8 bit descriptor in the server address space to the client
       
  3103  * thread's address space. The target location must be a valid modifiable descriptor.
       
  3104  * Data is copied from the source descriptor to the specified offset position within
       
  3105  * the target descriptor data area. The length of data copied is the length of the
       
  3106  * source descriptor. The length of the target descriptor is set to the length of
       
  3107  * the source descriptor plus the value of the offset.
       
  3108  *
       
  3109  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  3110  *                The data type at this location must be a modifiable descriptor, i.e. aTDes8 type.
       
  3111  * @param aDes    An 8 bit descriptor in the server address space. This is the source of the copy operation.
       
  3112  * @param aOffset The offset from the start of the target descriptor data area where copying is to begin.
       
  3113  *                This value must be greater than or equal to zero.
       
  3114  *
       
  3115  * @panic This function will panic the client if the WriteL() leaves
       
  3116  */	
       
  3117 	{
       
  3118 	//C32LOG4(KC32Player, _L8("CC32Player::Write() Data = (%s), Pos (%d) Offset (%d)"), aDes.Ptr(), aPos, aOffset);
       
  3119 
       
  3120 	TInt ret = aMessage.Write(aPos, aDes, aOffset);
       
  3121 	if (ret!=KErrNone)
       
  3122 		{
       
  3123 		C32LOG1(KC32Player, _L8("CC32Player::Write \t Error at the time of writing data to client"));
       
  3124 		PanicClient(EBadDescriptor,aMessage);
       
  3125 		}
       
  3126 	return ret;
       
  3127 	}
       
  3128 
       
  3129 
       
  3130 TInt CC32Player::Read(TInt aPos, const RMessagePtr2& aMessage , TDes8& aDes, TInt aOffset)
       
  3131 /**
       
  3132  * Read and kill the client if it leaves.
       
  3133  * 
       
  3134  * Copies data from the client thread's address space into an 8 bit descriptor
       
  3135  * in the server address space. The source data must be a valid descriptor.
       
  3136  * Data is copied from the specified offset position within the source descriptor
       
  3137  * data area. The length of data copied is the length of source descriptor data
       
  3138  * minus the offset value. If the offset value is greater than the length of the
       
  3139  * source descriptor, then no data is copied. The length of data copied is limited
       
  3140  * to the maximum length of the target descriptor.
       
  3141  *
       
  3142  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  3143  *                The data at this pointer must be a descriptor, i.e. a TDesC8 type.
       
  3144  * @param aDes    An 8 bit descriptor in the server address space. This is the target
       
  3145  *                of the copy operation.
       
  3146  * @param aOffset The offset from the start of the source descriptor data area from where
       
  3147  *                copying is to begin. This value must be greater than or equal to zero.
       
  3148  *
       
  3149  * @panic This function will panic the client if the ReadL() leaves
       
  3150  */
       
  3151 	{
       
  3152 	C32LOG3(KC32Player, _L8("CC32Player::Read(), Pos (%d), Offset (%d)"), aPos, aOffset);
       
  3153 
       
  3154 	TInt ret = aMessage.Read(aPos, aDes, aOffset);
       
  3155 	if (ret!=KErrNone)
       
  3156 		{
       
  3157 		C32LOG1(KC32Player, _L8("CC32Player::Read \t Error at the time of reading data from client"));
       
  3158 		PanicClient(EBadDescriptor,aMessage);
       
  3159 		}
       
  3160 	return ret;
       
  3161 	}
       
  3162 
       
  3163 
       
  3164 TInt CC32Player::Write(TInt aPos, const RMessagePtr2& aMessage , const TDesC16& aDes, TInt aOffset)
       
  3165 /**
       
  3166  * Write and kill the client if it leaves.
       
  3167  *
       
  3168  * (see CC32Player::Write() with 8-bit descriptor)
       
  3169  *
       
  3170  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  3171  *                The data type at this location must be a modifiable descriptor, i.e. aTDes16 type.
       
  3172  * @param aDes    A 16 bit descriptor in the server address space. This is the source of the copy operation.
       
  3173  * @param aOffset The offset from the start of the target descriptor data area where copying is to begin.
       
  3174  *                This value must be greater than or equal to zero.
       
  3175  *
       
  3176  * @panic This function will panic the client if the WriteL() leaves
       
  3177  */	
       
  3178 	{
       
  3179 	//C32LOG4(KC32Player, _L8("CC32Player::Write(), Data = (%s), Pos (%d), Offset (%d)"), aDes.Ptr(), aPos, aOffset);
       
  3180 
       
  3181 	TInt ret = aMessage.Write(aPos, aDes, aOffset);
       
  3182 	if (ret!=KErrNone)
       
  3183 		{
       
  3184 		C32LOG1(KC32Player, _L8("CC32Player::Write \t Error at the time of writing data to client"));
       
  3185 		PanicClient(EBadDescriptor,aMessage);
       
  3186 		}
       
  3187 	return ret;
       
  3188 	}
       
  3189 
       
  3190 
       
  3191 TInt CC32Player::Read(TInt aPos, const RMessagePtr2& aMessage , TDes16& aDes, TInt aOffset)
       
  3192 /**
       
  3193  * Read and kill the client if it leaves.
       
  3194  *
       
  3195  * (see CC32Player::Write() with 8-bit descriptor)
       
  3196  *
       
  3197  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  3198  *                The data at this pointer must be a descriptor, i.e. a TDesC16 type.
       
  3199  * @param aDes    A 16 bit descriptor in the server address space. This is the target
       
  3200  *                of the copy operation.
       
  3201  * @param aOffset The offset from the start of the source descriptor data area from where
       
  3202  *                copying is to begin. This value must be greater than or equal to zero.
       
  3203  *
       
  3204  * @panic This function will panic the client if the ReadL() leaves
       
  3205  */	
       
  3206 	{
       
  3207 	C32LOG3(KC32Player, _L8("CC32Player::Read(), Pos (%d), Offset (%d)"), aPos, aOffset);
       
  3208 
       
  3209 	TInt ret = aMessage.Read(aPos, aDes, aOffset);
       
  3210 	if (ret!=KErrNone)
       
  3211 		{
       
  3212 		C32LOG1(KC32Player, _L8("CC32Player::Read \t Error at the time of reading data from client"));
       
  3213 		PanicClient(EBadDescriptor,aMessage);
       
  3214 		}
       
  3215 	return ret;
       
  3216 	}
       
  3217 
       
  3218 
       
  3219 // EOF - CS_ROLES.CPP
       
  3220 
       
  3221