imaging/imagingfws/src/GenThreadRelay.cpp
changeset 0 5752a19fdefe
equal deleted inserted replaced
-1:000000000000 0:5752a19fdefe
       
     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 		&param);
       
    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 	}