|
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalTechnology |
|
19 */ |
|
20 |
|
21 #ifndef SYMBIAN_DEN_THREAD_H |
|
22 #define SYMBIAN_DEN_THREAD_H |
|
23 |
|
24 #include <cfextras.h> |
|
25 #include <cfshared.h> |
|
26 #include <elements/cftransport.h> |
|
27 |
|
28 |
|
29 #ifdef _DEBUG |
|
30 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module |
|
31 // (if it could happen through user error then you should give it an explicit, documented, category + code) |
|
32 _LIT(KSpecAssert_ElemSvrDenThredH, "ElemSvrDenThredH"); |
|
33 #endif |
|
34 |
|
35 namespace CommsFW |
|
36 { |
|
37 struct TCFModuleInfo; |
|
38 class TCFBindMsg; |
|
39 class TCFUnbindMsg; |
|
40 class TCFShutdownMsg; |
|
41 class TCFForwardMsg; |
|
42 } |
|
43 |
|
44 namespace Den |
|
45 { |
|
46 class CWorkerSession; |
|
47 class CWorkerRootServChannelHandler; |
|
48 class CCommonDealer; |
|
49 class CCommonWorkerDealer; |
|
50 class CCommonPlayer; |
|
51 class CCommonPitBoss; |
|
52 class CShutdownWatchDog; |
|
53 class CCommonWorkerThread; |
|
54 class CPeerDeathNotifier; |
|
55 class TPlayerRole; |
|
56 class TWorkerIntroductionMsg; |
|
57 |
|
58 class TWorkerThreadPublicInfo : public CommsFW::TWorkerThreadDataBase |
|
59 { |
|
60 public: |
|
61 enum TType |
|
62 { |
|
63 ENullWorkerId = 0xFFFF, //< Non-existent worker |
|
64 EMainThread = 0, //< the Pit Boss and Main Dealer run here |
|
65 EFirstPlayerThread = 1, //< Lowest possible player id |
|
66 EMaxWorkerThreadId = CommsFW::KMaxWorkerId //< Highest possible player id (NB: this is an inclusive bound. Be very careful in array-bound contexts!) |
|
67 }; |
|
68 |
|
69 //RServer2 iSessionSustainer; //< Used by the PitBoss to keep open a handle to a dealer so it can clean up its resources gracefully before closing the server, if the dealer thread dies. |
|
70 CCommonWorkerThread* iWorker; |
|
71 }; |
|
72 |
|
73 /** |
|
74 @class TWorkerThreadRegister |
|
75 Structure containing information pertaining to a particular worker thread. |
|
76 */ |
|
77 NONSHARABLE_CLASS(TWorkerThreadRegister) : public TWorkerThreadPublicInfo |
|
78 { |
|
79 friend class CCommonPitBoss; |
|
80 //friend class CCommonWorkerThread; |
|
81 |
|
82 public: |
|
83 TWorkerThreadRegister(); |
|
84 |
|
85 private: |
|
86 void Clear(); |
|
87 void PeerCleanupPending(CommsFW::TWorkerId aPeerId); |
|
88 void PeerCleanupCompleted(CommsFW::TWorkerId aPeerId); |
|
89 TBool AllPeerCleanupsCompleted() const; |
|
90 |
|
91 private: |
|
92 CPeerDeathNotifier* iPeerDeathNotifier; //< When the PitBoss binds to the worker thread this will be set up to monitor the thread, in case it dies. |
|
93 TBool iShuttingDown; //< Unused, should be removed. |
|
94 CCommonDealer* iDealer; //< Dealer instance of the worker thread (if exists). |
|
95 CCommonPlayer* iPlayer; //< Player instance of the worker thread (if exists). |
|
96 CommsFW::TCFModuleName iModuleName; |
|
97 |
|
98 private: |
|
99 /** |
|
100 If a worker thread dies the Pitboss will set a bit corresponding to the dead worker thread ID (/number) |
|
101 in iPendingPeerCleanups in the TWorkerThreadRegister instance for each other worker and send them a TWorkerCleanupDeadPeerMsg. |
|
102 The worker threads will respond by sending TWorkerMsg::ECleanupDeadPeerResp back when they have cleaned up anything |
|
103 related to the dead worker and the PitBoss will reset the bit in their TWorkerThreadRegister instance. |
|
104 @see HandleWorkerCleanupCompletionByPeer() |
|
105 */ |
|
106 TUint32 iPendingPeerCleanups; |
|
107 |
|
108 #ifdef _DEBUG |
|
109 TBool iHasGlobalAllocFails; |
|
110 #endif |
|
111 }; |
|
112 |
|
113 typedef CommsFW::CWorkerThreadRegister<TWorkerThreadRegister, CommsFW::KMaxWorkerId> CWorkerRegister; |
|
114 |
|
115 |
|
116 /** |
|
117 @class CCommonWorkerThread |
|
118 The Worker Thread is the holder of the relevant ESock objects in the CPM instance, |
|
119 e.g. the PitBoss, the Dealer and the Player (depending on configuration). It is also |
|
120 in charge of inter-thread communication as it holds the object enabling communication |
|
121 with the RootServer (CWorkerRootServChannelHandler) and a list of objects for |
|
122 communication with other Worker threads (CWorkerTransport). |
|
123 |
|
124 @see CWorkerRootServChannelHandler |
|
125 @see CWorkerTransport |
|
126 */ |
|
127 class CCommonWorkerThread : public CBase, public CommsFW::MLegacyMessageReceiver |
|
128 /** |
|
129 @internalComponent |
|
130 */ |
|
131 { |
|
132 friend class CWorkerRootServChannelHandler; |
|
133 |
|
134 public: |
|
135 IMPORT_C ~CCommonWorkerThread(); |
|
136 |
|
137 /** |
|
138 @return the pointer to the Dealer in this thread. This method might return NULL if the worker thread doesnt have a Dealer. |
|
139 */ |
|
140 CCommonDealer* Dealer() const |
|
141 { |
|
142 return iDealer; |
|
143 } |
|
144 IMPORT_C CCommonWorkerDealer* WorkerDealer() const; |
|
145 |
|
146 /** |
|
147 @return the pointer to the Player in this thread. This method might return NULL if the worker thread doesnt have a Player. |
|
148 */ |
|
149 CCommonPlayer* Player() const |
|
150 { |
|
151 return iPlayer; |
|
152 } |
|
153 |
|
154 CommsFW::TWorkerId WorkerId() const |
|
155 { |
|
156 return iWorkerId; |
|
157 } |
|
158 |
|
159 Messages::CGlobals& TransportGlobals() |
|
160 { |
|
161 __ASSERT_DEBUG(iGlobals, User::Panic(KSpecAssert_ElemSvrDenThredH, 1)); |
|
162 return *iGlobals; |
|
163 } |
|
164 |
|
165 /** |
|
166 Return the pointer to the domain PitBoss. This will be initialised when: |
|
167 -# If this is Main thread: In CCommonWorkerThread::ConstructL(TCFModuleInfo* aModuleInfo). |
|
168 -# In other common worker threads: When receiving TWorkerMsg::EMainIntroduction. |
|
169 */ |
|
170 CCommonPitBoss& PitBoss() const |
|
171 { |
|
172 __ASSERT_DEBUG(iPitBoss, User::Panic(KSpecAssert_ElemSvrDenThredH, 2)); |
|
173 return *iPitBoss; |
|
174 } |
|
175 |
|
176 /** |
|
177 Use this to discover whether this Worker Thread is EMainThread ("Esock_Main") which is |
|
178 the main Dealer also containing the PitBoss. |
|
179 @see TWorkerThreadInfo |
|
180 */ |
|
181 TBool IsMainThread() |
|
182 { |
|
183 return WorkerId()==TWorkerThreadRegister::EMainThread; |
|
184 } |
|
185 |
|
186 TWorkerThreadRegister* WorkerProperties(CommsFW::TWorkerId aWorker) |
|
187 { |
|
188 return iWorkerRegister->GetWorkerGlobals(aWorker); |
|
189 } |
|
190 |
|
191 IMPORT_C void SetDealerShutdownComplete(TBool aComplete); |
|
192 TBool DealerShutdownComplete() const |
|
193 { |
|
194 return iDealerShutdownComplete; |
|
195 } |
|
196 |
|
197 IMPORT_C void SetPlayerShutdownComplete(TBool aComplete); |
|
198 TBool PlayerShutdownComplete() const |
|
199 { |
|
200 return iPlayerShutdownComplete; |
|
201 } |
|
202 |
|
203 IMPORT_C TBool ShuttingDown() const; |
|
204 IMPORT_C void SetShuttingDown(); |
|
205 IMPORT_C void SessionShutdownComplete(); |
|
206 IMPORT_C void MaybeTriggerThreadShutdownCallback(); |
|
207 void TriggerThreadShutdownCallback(); |
|
208 IMPORT_C void DestroyDealer(); |
|
209 IMPORT_C void DestroyPlayer(); |
|
210 void DropTransportToPeer(TInt aPeer); |
|
211 IMPORT_C TBool MaybeCompleteUnbindings(); |
|
212 |
|
213 // RS control binding processing & message forwarding |
|
214 void CFUnbindMessageReceived(const CommsFW::TCFUnbindMsg& aMsg); |
|
215 void CFShutdownMessageReceived(const CommsFW::TCFShutdownMsg& aMsg); |
|
216 |
|
217 // Test whether a message |
|
218 TBool PeerReachable(CommsFW::TWorkerId aPeerId) const |
|
219 { |
|
220 return iTransport->PeerReachable(aPeerId); |
|
221 } |
|
222 |
|
223 // Send a message to a peer |
|
224 IMPORT_C void PostMessage(CommsFW::TWorkerId aWorkerId, CommsFW::TCFMessage& aMessage); |
|
225 CommsFW::CCommsTransport* Transport() const |
|
226 { |
|
227 return iTransport; |
|
228 } |
|
229 |
|
230 //< Thread nominates self as the default optimal dealer |
|
231 TBool DefaultOptimalDealer() const |
|
232 { |
|
233 return iDefaultOptimalDealer; |
|
234 } |
|
235 |
|
236 // |
|
237 IMPORT_C void DispatchL(const CommsFW::TCFMessage& aMessage, CommsFW::TWorkerId aSenderId); |
|
238 virtual TBool DoDispatchL(const CommsFW::TCFMessage& aMessage, CommsFW::TWorkerId aSenderId)=0; |
|
239 IMPORT_C void OnDispatchLeave(const CommsFW::TCFMessage& aMessage, CommsFW::TWorkerId aSenderId, TInt aFirstDispatchLeaveReason); |
|
240 |
|
241 // Process a non-internal message from a peer worker. Returns error code |
|
242 IMPORT_C void IncProlongBindingLife(); |
|
243 IMPORT_C void DecProlongBindingLife(); |
|
244 IMPORT_C void CompleteSessionClose(CWorkerSession* aSession); |
|
245 IMPORT_C void ConstructL(CommsFW::TCFModuleInfo& aModuleInfo, CShutdownWatchDog& aShutdownWatchDog); |
|
246 //Default post mortem cleanup handler |
|
247 IMPORT_C static TInt PostMortemCleanupThreadEntry(TAny* aArg); |
|
248 |
|
249 protected: |
|
250 virtual CCommonPitBoss* DoCreatePitBossL(CCommonWorkerThread* aWorkerThread)=0; |
|
251 virtual CCommonPlayer* DoCreatePlayerL(CCommonWorkerThread* aWorkerThread, TPlayerRole aPlayerRole)=0; |
|
252 virtual CCommonDealer* DoCreateDealerL(CCommonWorkerThread* aWorkerThread, TPlayerRole aPlayerRole)=0; |
|
253 virtual void DoCompleteUnbinding(CommsFW::TWorkerId aWorker) = 0; |
|
254 virtual void DoSetShuttingDown() = 0; |
|
255 virtual void DoPostMortemCleanup() = 0; |
|
256 virtual void CFBindMessageReceived(const CommsFW::TCFBindMsg& aMsg) = 0; |
|
257 virtual void CFMessageForward(const CommsFW::TCFForwardMsg& aMessage) = 0; |
|
258 |
|
259 virtual void DoProcessWorkerIntroductionL(const TWorkerIntroductionMsg& aMessage) = 0; |
|
260 |
|
261 IMPORT_C void SendIntroMessage(const CommsFW::TCFModuleName& aPeerName, CommsFW::TWorkerId aPeerId); |
|
262 virtual void DoFillIntroMessage(CommsFW::TWorkerId aPeerId, TWorkerIntroductionMsg& aIntroMsg) = 0; |
|
263 |
|
264 IMPORT_C CCommonWorkerThread(); |
|
265 IMPORT_C static void DeleteHBufC8(TAny* aHBufC); |
|
266 |
|
267 IMPORT_C void DetermineRoleL(HBufC8* aIniData, TBool& aIsDealer, TBool& aIsPlayer, TPlayerRole &aPlayerRole); |
|
268 virtual void DoDeterminePlayerRoleL(HBufC8* aIniData, TPlayerRole &aPlayerRole)=0; |
|
269 |
|
270 void ProcessIniDataL(); |
|
271 IMPORT_C TInt DecodePeerId(const CommsFW::TCFSubModuleAddress* aSubModule1, const CommsFW::TCFSubModuleAddress* aSubModule2, CommsFW::TWorkerId& aPeerId); |
|
272 IMPORT_C void MaybeCompleteUnbinding(CommsFW::TWorkerId aWorker); |
|
273 |
|
274 protected: |
|
275 /** This is the handler used for bi-directional communication with the Root Server. */ |
|
276 CWorkerRootServChannelHandler* iChannelHandler; |
|
277 |
|
278 CWorkerRegister* iWorkerRegister; |
|
279 CommsFW::CCommsTransport* iTransport; |
|
280 |
|
281 /** |
|
282 Indentification of this thread. No other instance must have the same id. |
|
283 @see TWorkerThreadInfo |
|
284 */ |
|
285 CommsFW::TWorkerId iWorkerId; |
|
286 |
|
287 CCommonDealer* iDealer; |
|
288 CCommonPlayer* iPlayer; |
|
289 CCommonPitBoss* iPitBoss; |
|
290 |
|
291 TBool iDefaultOptimalDealer; |
|
292 |
|
293 |
|
294 /** Set when a CommsFW::TCFShutdownMsg is received from the Root Server. */ |
|
295 TBool iWorkerShuttingDown; |
|
296 |
|
297 /** |
|
298 Set by the Dealer instance to signal to the Worker Thread that it has |
|
299 finished with the shutdown bookkeeping and is ready to be deleted. |
|
300 */ |
|
301 TBool iDealerShutdownComplete; |
|
302 |
|
303 /** |
|
304 Set by the Player instance to signal to the Worker Thread that it has |
|
305 finished with the shutdown bookkeeping and is ready to be deleted. |
|
306 */ |
|
307 TBool iPlayerShutdownComplete; |
|
308 |
|
309 /** |
|
310 If the value of this TInt is larger than 0 any unbind requests will not be served, |
|
311 but postponed until iProlongBindingLife is 0. This is to ensure that if e.g. a |
|
312 TWorkerMsg::ECleanupDeadPeer or TPlayerMsg::ESessionClose is received they will be fully |
|
313 served before completing any unbind and thus deleting channel handlers. |
|
314 */ |
|
315 TInt iProlongBindingLife; |
|
316 |
|
317 CShutdownWatchDog* iShutdownWatchDog; |
|
318 Messages::CGlobals* iGlobals; |
|
319 |
|
320 public: |
|
321 #ifdef _DEBUG |
|
322 RAllocator::TAllocFail AllocFailType() const |
|
323 { |
|
324 return iFailType; |
|
325 } |
|
326 TInt AllocFailRate() const |
|
327 { |
|
328 return iFailRate; |
|
329 } |
|
330 #endif |
|
331 |
|
332 //These must not be conditional (BC) |
|
333 private: |
|
334 RAllocator::TAllocFail iFailType; |
|
335 TInt iFailRate; |
|
336 }; |
|
337 |
|
338 NONSHARABLE_CLASS(CShutdownWatchDog) : public CPeriodic |
|
339 /** |
|
340 @internalComponent |
|
341 */ |
|
342 { |
|
343 public: |
|
344 IMPORT_C void Shutdown(TBool aImmediate); |
|
345 IMPORT_C static CShutdownWatchDog* NewL(CCommonWorkerThread* aWorker, const TCallBack& aShutDownCb); |
|
346 |
|
347 private: |
|
348 CShutdownWatchDog(CCommonWorkerThread* aWorker, const TCallBack& aShutDownCb); |
|
349 static TInt TryShutdown(TAny* aSelf); |
|
350 |
|
351 private: |
|
352 TBool iImmediate; |
|
353 CCommonWorkerThread* iWorker; |
|
354 TCallBack iShutDownCb; |
|
355 }; |
|
356 |
|
357 } //namespace Den |
|
358 |
|
359 #endif |
|
360 //SYMBIAN_DEN_THREAD_H |
|
361 |
|
362 |