|
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 |