|
1 // Copyright (c) 2001-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 #include "ImageClientMain.h" |
|
17 #include "GenThreadRelay.h" |
|
18 #include <ecom/ecom.h> |
|
19 |
|
20 _LIT(KSubThreadName,"ICLThread"); |
|
21 |
|
22 // |
|
23 // CThreadRelay |
|
24 // |
|
25 /** |
|
26 * Constructor for this class. |
|
27 * |
|
28 */ |
|
29 CThreadRelay::CThreadRelay() |
|
30 { |
|
31 } |
|
32 |
|
33 /** |
|
34 * Construct for client side threaded relay. Create a thread and wait for the thread |
|
35 * to start up or panic. If the thread is successfully created start an undertaker |
|
36 * that listens for panics in the thread. |
|
37 * |
|
38 * @param "CSubThreadRelay* (*aFactoryFunctionL)(TThreadId aMainThreadId, TAny* aCodecParam)" |
|
39 * A Facory function that will create a CSubThread derived object. |
|
40 * @param "TAny* aCodecParam" |
|
41 * Parameters to be used during the threaded relay's construction. |
|
42 * |
|
43 */ |
|
44 void CThreadRelay::ConstructL(CSubThreadRelay* (*aFactoryFunctionL)(TThreadId aMainThreadId, TAny* aCodecParam), TAny* aCodecParam) |
|
45 { |
|
46 //Get a pointer to this thread's heap |
|
47 RHeap& thisHeap = User::Heap(); |
|
48 |
|
49 //Parameters to send to the sub thread |
|
50 TThreadRelayParam param; |
|
51 |
|
52 //Add the parameters for the codec |
|
53 param.iCodecParam = aCodecParam; |
|
54 |
|
55 //Add the factory function to create a CSubThreadDecoderRelay derived object |
|
56 param.iFactoryFunctionL = aFactoryFunctionL; |
|
57 |
|
58 //The sub thread must return a pointer for us to allow direct calls |
|
59 param.iSubThreadRelay = &iSubRelay; |
|
60 |
|
61 //Get the id of this thread |
|
62 RThread thisThread; |
|
63 TThreadId thisThreadId = thisThread.Id(); |
|
64 param.iMainThreadId = thisThreadId; |
|
65 |
|
66 //Get a request to signal us after setup is complete |
|
67 TRequestStatus setupComplete = KRequestPending; |
|
68 param.iSetupComplete = &setupComplete; |
|
69 |
|
70 //current time and the "this" pointer for a unique key |
|
71 _LIT(KFormatString,"%S.%020Lu.%08X"); |
|
72 TName threadName; |
|
73 |
|
74 TTime now; |
|
75 now.HomeTime(); |
|
76 |
|
77 threadName.Format(KFormatString, &KSubThreadName, now.Int64(), reinterpret_cast<TUint>(this)); |
|
78 |
|
79 //Create a new thread for CSubThreadRelay using the same heap as this thread |
|
80 TInt result = iSubThread.Create(threadName, |
|
81 ThreadFunction, |
|
82 KSubThreadStackSize, |
|
83 &thisHeap, |
|
84 ¶m); |
|
85 if(result != KErrNone) |
|
86 User::Leave(result); |
|
87 |
|
88 //Run the thread under a lower priority |
|
89 iSubThread.SetPriority(KSubThreadPriority); |
|
90 |
|
91 //Wait for thread startup to complete |
|
92 TRequestStatus threadStatus = KRequestPending; |
|
93 iSubThread.Logon(threadStatus); |
|
94 |
|
95 //Start the sub thread |
|
96 iSubThread.Resume(); |
|
97 |
|
98 User::WaitForRequest(threadStatus, setupComplete); |
|
99 |
|
100 if(threadStatus!=KRequestPending) |
|
101 { |
|
102 //Thread creation failed |
|
103 TExitType type = iSubThread.ExitType(); |
|
104 TInt reason = iSubThread.ExitReason(); |
|
105 if(type==EExitKill) |
|
106 User::Leave(reason); |
|
107 else |
|
108 { |
|
109 ASSERT(type==EExitPanic); |
|
110 TExitCategoryName category = iSubThread.ExitCategory(); |
|
111 User::Panic(category,reason); |
|
112 } |
|
113 } |
|
114 |
|
115 // Thread creation was successfull |
|
116 TInt error = iSubThread.LogonCancel(threadStatus); |
|
117 if(error != KErrNone) |
|
118 User::Leave(error); // There is no outstanding request |
|
119 |
|
120 User::WaitForRequest(threadStatus); //Eat the signal |
|
121 |
|
122 ASSERT(iSubRelay!=NULL); |
|
123 iSubRelay->SetSubThread(&iSubThread); |
|
124 |
|
125 iThreadCreated = ETrue; |
|
126 User::LeaveIfError(setupComplete.Int()); |
|
127 |
|
128 //Create a listener that will monitor the thread |
|
129 iSubThreadUndertaker = CSubThreadUndertaker::NewL(iSubThread); |
|
130 } |
|
131 |
|
132 |
|
133 /** |
|
134 * Destructor for this class. Calls the shutdown function for the thread. |
|
135 * |
|
136 */ |
|
137 CThreadRelay::~CThreadRelay() |
|
138 { |
|
139 Shutdown(); |
|
140 } |
|
141 |
|
142 /** |
|
143 * Terminate the thread. Since the WaitForRequest() suspend the thread, the undertaker |
|
144 * is terminated and logon to the thread locally. Send a shutdown message to the thread |
|
145 * and wait for it to terminate. |
|
146 * |
|
147 */ |
|
148 void CThreadRelay::Shutdown() |
|
149 { |
|
150 if(iThreadCreated) |
|
151 { |
|
152 ASSERT(iSubRelay!=NULL); |
|
153 TRequestStatus functionRequest = KRequestPending; |
|
154 TRequestStatus threadRequest = KRequestPending; |
|
155 |
|
156 /*While a function call is in progress this thread is suspended |
|
157 *and the undertaker will not catch panics, listen for these here |
|
158 */ |
|
159 iSubThread.Logon(threadRequest); |
|
160 |
|
161 iSubRelay->RunFunctionInThread(functionRequest, KTerminationFunction, NULL); |
|
162 TRequestStatus* functionCallRequest = iSubRelay->Status(); |
|
163 iSubThread.RequestComplete(functionCallRequest, KErrNone); |
|
164 User::WaitForRequest(functionRequest); //At this stage the thread termination signal has been completed |
|
165 User::WaitForRequest(threadRequest); //Eat the thread termination signal |
|
166 |
|
167 iThreadCreated = EFalse; |
|
168 } |
|
169 |
|
170 if(iSubThreadUndertaker) |
|
171 { |
|
172 iSubThreadUndertaker->Cancel(); |
|
173 delete iSubThreadUndertaker; iSubThreadUndertaker = NULL; |
|
174 } |
|
175 |
|
176 iSubThread.Close(); |
|
177 } |
|
178 |
|
179 /** |
|
180 * Request a function to be executed in the codec thread. Wait for the function to |
|
181 * complete or a panic, since the WaitForRequest() suspend the thread(including the |
|
182 * undertaker). |
|
183 * |
|
184 * @param "TInt aFunctionCode" |
|
185 * The number of the function to execute in the codec thread. |
|
186 * @param "TAny* aParameters" |
|
187 * Parameters for function to be executed in the codec thread. |
|
188 * @return "TInt" |
|
189 * The leave code of the function in the sub thread. |
|
190 */ |
|
191 TInt CThreadRelay::RunFunction(TInt aFunctionCode, TAny* aParameters) |
|
192 { |
|
193 ASSERT(iSubRelay!=NULL); |
|
194 TRequestStatus functionRequest = KRequestPending; |
|
195 TRequestStatus threadRequest = KRequestPending; |
|
196 |
|
197 /*While a function call is in progress this thread is suspended |
|
198 *and the undertaker will not catch panics, listen for these here |
|
199 */ |
|
200 iSubThread.Logon(threadRequest); |
|
201 |
|
202 iSubRelay->RunFunctionInThread(functionRequest, aFunctionCode, aParameters); |
|
203 TRequestStatus* functionCallRequest = iSubRelay->Status(); |
|
204 iSubThread.RequestComplete(functionCallRequest, KErrNone); |
|
205 User::WaitForRequest(threadRequest, functionRequest); |
|
206 |
|
207 if(threadRequest!=KRequestPending) |
|
208 { |
|
209 TInt reason = iSubThread.ExitReason(); |
|
210 TExitCategoryName category = iSubThread.ExitCategory(); |
|
211 User::Panic(category,reason); |
|
212 } |
|
213 |
|
214 // Thread is still alive and well |
|
215 iSubThread.LogonCancel(threadRequest); |
|
216 User::WaitForRequest(threadRequest); //Eat the signal |
|
217 |
|
218 ASSERT(functionRequest!=KRequestPending); |
|
219 |
|
220 return functionRequest.Int(); |
|
221 } |
|
222 |
|
223 |
|
224 /** |
|
225 * Return a pointer to the sub thread relay object. |
|
226 * |
|
227 * @return "CSubThreadRelay*" |
|
228 * A pointer to the sub thread relay object. |
|
229 */ |
|
230 CSubThreadRelay* CThreadRelay::SubThreadRelay() |
|
231 { |
|
232 return iSubRelay; |
|
233 } |
|
234 |
|
235 /** |
|
236 * Return a pointer to the sub thread. |
|
237 * |
|
238 * @return "RThread*" |
|
239 * A pointer to the sub thread. |
|
240 */ |
|
241 const RThread* CThreadRelay::SubThread() const |
|
242 { |
|
243 return &iSubThread; |
|
244 } |
|
245 |
|
246 |
|
247 /** |
|
248 * Change the sub thread's priority. |
|
249 * |
|
250 * @param "TThreadPriority aPriority" |
|
251 * The new priority for the sub thread. |
|
252 */ |
|
253 void CThreadRelay::SetPriority(TThreadPriority aPriority) const |
|
254 { |
|
255 iSubThread.SetPriority(aPriority); |
|
256 } |
|
257 |
|
258 /** |
|
259 * Main thread entry point for the codec thread. |
|
260 * Create a cleanup stack for the thread and process the codec |
|
261 * inside a trap for cleanup behaviour. |
|
262 * |
|
263 * @param "TAny* aPtr" |
|
264 * Parameters to be used for creating the thread. |
|
265 * @return "TInt" |
|
266 * The error code for thread termination. |
|
267 */ |
|
268 TInt CThreadRelay::ThreadFunction(TAny* aPtr) |
|
269 { |
|
270 TInt error = KErrNone; |
|
271 |
|
272 // Create a cleanup stack for the thread |
|
273 CTrapCleanup* cleanupStack = CTrapCleanup::New(); |
|
274 if(cleanupStack) |
|
275 { |
|
276 //Connnect to the bitmap server |
|
277 error = RFbsSession::Connect(); |
|
278 |
|
279 if(error==KErrNone) |
|
280 { |
|
281 //Run the plugin in a trap |
|
282 TRAP(error, ThreadTrapFunctionL(aPtr)); |
|
283 RFbsSession::Disconnect(); |
|
284 } |
|
285 } |
|
286 else |
|
287 error = KErrNoMemory; |
|
288 |
|
289 delete cleanupStack; |
|
290 |
|
291 return error; |
|
292 } |
|
293 |
|
294 /** |
|
295 * Function for codec thread execution. Create an active scheduler for the thread |
|
296 * and start the function call listener. If the thread is successfully created signal |
|
297 * the main thread that the thread creation was successfull. |
|
298 * |
|
299 * @param "TAny* aPtr" |
|
300 * A pointer to a TThreadRelayParam object containing the startup parameters |
|
301 * for the thread. |
|
302 */ |
|
303 void CThreadRelay::ThreadTrapFunctionL(TAny* aPtr) |
|
304 { |
|
305 //Create an active scheduler for the thread |
|
306 CActiveScheduler* scheduler = new (ELeave) CActiveScheduler; |
|
307 CleanupStack::PushL(scheduler); |
|
308 CActiveScheduler::Install( scheduler ); |
|
309 |
|
310 //Call a Factory function to create a CSubThreadRelay derived object |
|
311 TThreadRelayParam* threadRelayParam; |
|
312 threadRelayParam = STATIC_CAST(TThreadRelayParam*, aPtr); |
|
313 |
|
314 //A factory function that will create a CSubThreadRelay derived object |
|
315 CSubThreadRelay* (*FactoryFunctionL) (TThreadId aMainThreadId, TAny* aCodecParam); |
|
316 FactoryFunctionL = threadRelayParam->iFactoryFunctionL; |
|
317 |
|
318 CSubThreadRelay* subThreadRelay; |
|
319 //Call the factory function |
|
320 subThreadRelay = FactoryFunctionL(threadRelayParam->iMainThreadId, threadRelayParam->iCodecParam); |
|
321 CleanupStack::PushL(subThreadRelay); |
|
322 |
|
323 //Send a pointer to the sub thread relay back to the main thread |
|
324 *threadRelayParam->iSubThreadRelay = subThreadRelay; |
|
325 |
|
326 subThreadRelay->Prime(); |
|
327 |
|
328 // Send a signal to the main thread that the setup was completed |
|
329 subThreadRelay->SignalSetupComplete(threadRelayParam->iSetupComplete); |
|
330 |
|
331 CActiveScheduler::Start(); |
|
332 |
|
333 CleanupStack::PopAndDestroy(2,scheduler); //subThreadRelay, scheduler |
|
334 REComSession::FinalClose(); |
|
335 } |
|
336 |
|
337 // |
|
338 // CSubThreadRelay |
|
339 // |
|
340 /** |
|
341 * Open a connection to the main (caller) thread. |
|
342 * |
|
343 */ |
|
344 void CSubThreadRelay::ConstructL(TThreadId aMainThreadId) |
|
345 { |
|
346 User::LeaveIfError(iMainThread.Open(aMainThreadId)); |
|
347 } |
|
348 |
|
349 /** |
|
350 * Constructor for this class. |
|
351 * Add the function call listener to the active scheduler. |
|
352 * |
|
353 */ |
|
354 CSubThreadRelay::CSubThreadRelay(): |
|
355 CActive(EPriorityStandard) |
|
356 { |
|
357 CActiveScheduler::Add(this); |
|
358 } |
|
359 |
|
360 /** |
|
361 * Destructor for this class. |
|
362 * Close the connection to the main thread. |
|
363 * |
|
364 */ |
|
365 CSubThreadRelay::~CSubThreadRelay() |
|
366 { |
|
367 iMainThread.Close(); |
|
368 } |
|
369 |
|
370 /** |
|
371 * Cancel the function call listener. |
|
372 * |
|
373 */ |
|
374 void CSubThreadRelay::DoCancel() |
|
375 { |
|
376 } |
|
377 |
|
378 /** |
|
379 * Send a signal to the main thread to indicate that the thread startup |
|
380 * was successfull. |
|
381 * |
|
382 */ |
|
383 void CSubThreadRelay::SignalSetupComplete(TRequestStatus* aSetupComplete) |
|
384 { |
|
385 iMainThread.RequestComplete(aSetupComplete, KErrNone); |
|
386 } |
|
387 |
|
388 /** |
|
389 * Prime the function call listener. |
|
390 * |
|
391 */ |
|
392 void CSubThreadRelay::Prime() |
|
393 { |
|
394 ASSERT(IsActive() == EFalse); |
|
395 iStatus = KRequestPending; |
|
396 SetActive(); |
|
397 } |
|
398 |
|
399 /** |
|
400 * Execute a function in the sub thread. Signal the leave result of the function |
|
401 * to the main thread. If the termination function is called stop the active |
|
402 * scheduler for the sub thread. (This will cause the thread to terminate) |
|
403 * |
|
404 */ |
|
405 void CSubThreadRelay::RunL() |
|
406 { |
|
407 ASSERT(iStatus == KErrNone); |
|
408 |
|
409 TInt error = KErrNone; |
|
410 //Thread termination function called |
|
411 if(iFunctionCode == KTerminationFunction) |
|
412 CActiveScheduler::Stop(); |
|
413 else |
|
414 { |
|
415 Prime(); |
|
416 TRAP(error, RunFunctionL(iFunctionCode, iFunctionParams)); |
|
417 } |
|
418 TRequestStatus *status = iCallingStatus; |
|
419 iMainThread.RequestComplete(status, error); |
|
420 } |
|
421 |
|
422 /** |
|
423 * Save the function number and parameters for an outstanding function call in the |
|
424 * codec thread. |
|
425 * |
|
426 * @param "TRequestStatus& aCallingStatus" |
|
427 * Request to signal the main thread when the function call has completed. |
|
428 * @param "TInt aFunctionCode" |
|
429 * The function number to execute. |
|
430 * @param "TAny* aParameters" |
|
431 * Parameters to the function to execute. |
|
432 */ |
|
433 void CSubThreadRelay::RunFunctionInThread(TRequestStatus& aCallingStatus, TInt aFunctionCode, TAny* aParameters) |
|
434 { |
|
435 iCallingStatus = &aCallingStatus; |
|
436 iFunctionCode = aFunctionCode; |
|
437 iFunctionParams = aParameters; |
|
438 } |
|
439 |
|
440 /** |
|
441 * Store a pointer to the codec thread object. |
|
442 * |
|
443 * @param "RThread* aSubThread" |
|
444 * A pointer to the codec thread object. |
|
445 */ |
|
446 void CSubThreadRelay::SetSubThread(RThread* aSubThread) |
|
447 { |
|
448 iSubThread = aSubThread; |
|
449 } |
|
450 |
|
451 /** |
|
452 * Return a pointer to the function call listener's request status. |
|
453 * Signal this from the main thread to request a function to be executed |
|
454 * in the thread after a call to RunFunctionInThread(). |
|
455 * |
|
456 * @return "TRequestStatus*" |
|
457 * Request to signal the start of execution of a function in the thread. |
|
458 */ |
|
459 TRequestStatus* CSubThreadRelay::Status() |
|
460 { |
|
461 return &iStatus; |
|
462 } |
|
463 |
|
464 // |
|
465 //CSubThreadUndertaker |
|
466 // |
|
467 /** |
|
468 * Factory function for the class. |
|
469 * |
|
470 * @param "RThread& aSubThread" |
|
471 * A thread to monitor for panics |
|
472 */ |
|
473 CSubThreadUndertaker* CSubThreadUndertaker::NewL(RThread& aSubThread) |
|
474 { |
|
475 CSubThreadUndertaker* self; |
|
476 self = new (ELeave) CSubThreadUndertaker(&aSubThread); |
|
477 return self; |
|
478 } |
|
479 |
|
480 /** |
|
481 * Constructor for the class. |
|
482 * Add the object to the active scheduler, activate and logon to the |
|
483 * thread to monitor for panics |
|
484 * |
|
485 * @param "RThread* aSubThread" |
|
486 * A thread to monitor for panics |
|
487 */ |
|
488 CSubThreadUndertaker::CSubThreadUndertaker(RThread* aSubThread) : |
|
489 CActive(CActive::EPriorityIdle), |
|
490 iSubThread(aSubThread) |
|
491 { |
|
492 //Add ourself to the active scheduler |
|
493 CActiveScheduler::Add(this); |
|
494 |
|
495 iSubThread = aSubThread; |
|
496 |
|
497 ASSERT(IsActive()==EFalse); |
|
498 iStatus = KRequestPending; |
|
499 SetActive(); |
|
500 |
|
501 //Logon to the thread so we will receive signals |
|
502 iSubThread->Logon(iStatus); |
|
503 } |
|
504 |
|
505 /** |
|
506 * Destructor for this class. |
|
507 * Make sure that the undertaker was cancelled before deleted. |
|
508 */ |
|
509 CSubThreadUndertaker::~CSubThreadUndertaker() |
|
510 { |
|
511 Cancel(); |
|
512 } |
|
513 |
|
514 /** |
|
515 * This function is triggered when the thread being monitored terminates. |
|
516 * If the thread being monitored panic, panic this thread. |
|
517 * |
|
518 */ |
|
519 void CSubThreadUndertaker::RunL() |
|
520 { |
|
521 ASSERT(iSubThread != NULL); |
|
522 //If we got here the thread has exited |
|
523 TInt reason = iSubThread->ExitReason(); |
|
524 TExitCategoryName category = iSubThread->ExitCategory(); |
|
525 User::Panic(category, reason); |
|
526 } |
|
527 |
|
528 /** |
|
529 * Stop monitoring the thread for panics. This function is executed by |
|
530 * calling Cancel() and has to be done before the object is deleted. |
|
531 * |
|
532 */ |
|
533 void CSubThreadUndertaker::DoCancel() |
|
534 { |
|
535 iSubThread->LogonCancel(iStatus); |
|
536 } |