diff -r 000000000000 -r 5752a19fdefe imaging/imagingfws/src/GenThreadRelay.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imaging/imagingfws/src/GenThreadRelay.cpp Wed Aug 25 12:29:52 2010 +0300 @@ -0,0 +1,536 @@ +// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "ImageClientMain.h" +#include "GenThreadRelay.h" +#include + +_LIT(KSubThreadName,"ICLThread"); + +// +// CThreadRelay +// +/** + * Constructor for this class. + * + */ +CThreadRelay::CThreadRelay() + { + } + +/** + * Construct for client side threaded relay. Create a thread and wait for the thread + * to start up or panic. If the thread is successfully created start an undertaker + * that listens for panics in the thread. + * + * @param "CSubThreadRelay* (*aFactoryFunctionL)(TThreadId aMainThreadId, TAny* aCodecParam)" + * A Facory function that will create a CSubThread derived object. + * @param "TAny* aCodecParam" + * Parameters to be used during the threaded relay's construction. + * + */ +void CThreadRelay::ConstructL(CSubThreadRelay* (*aFactoryFunctionL)(TThreadId aMainThreadId, TAny* aCodecParam), TAny* aCodecParam) + { + //Get a pointer to this thread's heap + RHeap& thisHeap = User::Heap(); + + //Parameters to send to the sub thread + TThreadRelayParam param; + + //Add the parameters for the codec + param.iCodecParam = aCodecParam; + + //Add the factory function to create a CSubThreadDecoderRelay derived object + param.iFactoryFunctionL = aFactoryFunctionL; + + //The sub thread must return a pointer for us to allow direct calls + param.iSubThreadRelay = &iSubRelay; + + //Get the id of this thread + RThread thisThread; + TThreadId thisThreadId = thisThread.Id(); + param.iMainThreadId = thisThreadId; + + //Get a request to signal us after setup is complete + TRequestStatus setupComplete = KRequestPending; + param.iSetupComplete = &setupComplete; + + //current time and the "this" pointer for a unique key + _LIT(KFormatString,"%S.%020Lu.%08X"); + TName threadName; + + TTime now; + now.HomeTime(); + + threadName.Format(KFormatString, &KSubThreadName, now.Int64(), reinterpret_cast(this)); + + //Create a new thread for CSubThreadRelay using the same heap as this thread + TInt result = iSubThread.Create(threadName, + ThreadFunction, + KSubThreadStackSize, + &thisHeap, + ¶m); + if(result != KErrNone) + User::Leave(result); + + //Run the thread under a lower priority + iSubThread.SetPriority(KSubThreadPriority); + + //Wait for thread startup to complete + TRequestStatus threadStatus = KRequestPending; + iSubThread.Logon(threadStatus); + + //Start the sub thread + iSubThread.Resume(); + + User::WaitForRequest(threadStatus, setupComplete); + + if(threadStatus!=KRequestPending) + { + //Thread creation failed + TExitType type = iSubThread.ExitType(); + TInt reason = iSubThread.ExitReason(); + if(type==EExitKill) + User::Leave(reason); + else + { + ASSERT(type==EExitPanic); + TExitCategoryName category = iSubThread.ExitCategory(); + User::Panic(category,reason); + } + } + + // Thread creation was successfull + TInt error = iSubThread.LogonCancel(threadStatus); + if(error != KErrNone) + User::Leave(error); // There is no outstanding request + + User::WaitForRequest(threadStatus); //Eat the signal + + ASSERT(iSubRelay!=NULL); + iSubRelay->SetSubThread(&iSubThread); + + iThreadCreated = ETrue; + User::LeaveIfError(setupComplete.Int()); + + //Create a listener that will monitor the thread + iSubThreadUndertaker = CSubThreadUndertaker::NewL(iSubThread); + } + + +/** + * Destructor for this class. Calls the shutdown function for the thread. + * + */ +CThreadRelay::~CThreadRelay() + { + Shutdown(); + } + +/** + * Terminate the thread. Since the WaitForRequest() suspend the thread, the undertaker + * is terminated and logon to the thread locally. Send a shutdown message to the thread + * and wait for it to terminate. + * + */ +void CThreadRelay::Shutdown() + { + if(iThreadCreated) + { + ASSERT(iSubRelay!=NULL); + TRequestStatus functionRequest = KRequestPending; + TRequestStatus threadRequest = KRequestPending; + + /*While a function call is in progress this thread is suspended + *and the undertaker will not catch panics, listen for these here + */ + iSubThread.Logon(threadRequest); + + iSubRelay->RunFunctionInThread(functionRequest, KTerminationFunction, NULL); + TRequestStatus* functionCallRequest = iSubRelay->Status(); + iSubThread.RequestComplete(functionCallRequest, KErrNone); + User::WaitForRequest(functionRequest); //At this stage the thread termination signal has been completed + User::WaitForRequest(threadRequest); //Eat the thread termination signal + + iThreadCreated = EFalse; + } + + if(iSubThreadUndertaker) + { + iSubThreadUndertaker->Cancel(); + delete iSubThreadUndertaker; iSubThreadUndertaker = NULL; + } + + iSubThread.Close(); + } + +/** + * Request a function to be executed in the codec thread. Wait for the function to + * complete or a panic, since the WaitForRequest() suspend the thread(including the + * undertaker). + * + * @param "TInt aFunctionCode" + * The number of the function to execute in the codec thread. + * @param "TAny* aParameters" + * Parameters for function to be executed in the codec thread. + * @return "TInt" + * The leave code of the function in the sub thread. + */ +TInt CThreadRelay::RunFunction(TInt aFunctionCode, TAny* aParameters) + { + ASSERT(iSubRelay!=NULL); + TRequestStatus functionRequest = KRequestPending; + TRequestStatus threadRequest = KRequestPending; + + /*While a function call is in progress this thread is suspended + *and the undertaker will not catch panics, listen for these here + */ + iSubThread.Logon(threadRequest); + + iSubRelay->RunFunctionInThread(functionRequest, aFunctionCode, aParameters); + TRequestStatus* functionCallRequest = iSubRelay->Status(); + iSubThread.RequestComplete(functionCallRequest, KErrNone); + User::WaitForRequest(threadRequest, functionRequest); + + if(threadRequest!=KRequestPending) + { + TInt reason = iSubThread.ExitReason(); + TExitCategoryName category = iSubThread.ExitCategory(); + User::Panic(category,reason); + } + + // Thread is still alive and well + iSubThread.LogonCancel(threadRequest); + User::WaitForRequest(threadRequest); //Eat the signal + + ASSERT(functionRequest!=KRequestPending); + + return functionRequest.Int(); + } + + +/** + * Return a pointer to the sub thread relay object. + * + * @return "CSubThreadRelay*" + * A pointer to the sub thread relay object. + */ +CSubThreadRelay* CThreadRelay::SubThreadRelay() + { + return iSubRelay; + } + +/** + * Return a pointer to the sub thread. + * + * @return "RThread*" + * A pointer to the sub thread. + */ +const RThread* CThreadRelay::SubThread() const + { + return &iSubThread; + } + + +/** + * Change the sub thread's priority. + * + * @param "TThreadPriority aPriority" + * The new priority for the sub thread. + */ +void CThreadRelay::SetPriority(TThreadPriority aPriority) const + { + iSubThread.SetPriority(aPriority); + } + +/** + * Main thread entry point for the codec thread. + * Create a cleanup stack for the thread and process the codec + * inside a trap for cleanup behaviour. + * + * @param "TAny* aPtr" + * Parameters to be used for creating the thread. + * @return "TInt" + * The error code for thread termination. + */ +TInt CThreadRelay::ThreadFunction(TAny* aPtr) + { + TInt error = KErrNone; + + // Create a cleanup stack for the thread + CTrapCleanup* cleanupStack = CTrapCleanup::New(); + if(cleanupStack) + { + //Connnect to the bitmap server + error = RFbsSession::Connect(); + + if(error==KErrNone) + { + //Run the plugin in a trap + TRAP(error, ThreadTrapFunctionL(aPtr)); + RFbsSession::Disconnect(); + } + } + else + error = KErrNoMemory; + + delete cleanupStack; + + return error; + } + +/** + * Function for codec thread execution. Create an active scheduler for the thread + * and start the function call listener. If the thread is successfully created signal + * the main thread that the thread creation was successfull. + * + * @param "TAny* aPtr" + * A pointer to a TThreadRelayParam object containing the startup parameters + * for the thread. + */ +void CThreadRelay::ThreadTrapFunctionL(TAny* aPtr) + { + //Create an active scheduler for the thread + CActiveScheduler* scheduler = new (ELeave) CActiveScheduler; + CleanupStack::PushL(scheduler); + CActiveScheduler::Install( scheduler ); + + //Call a Factory function to create a CSubThreadRelay derived object + TThreadRelayParam* threadRelayParam; + threadRelayParam = STATIC_CAST(TThreadRelayParam*, aPtr); + + //A factory function that will create a CSubThreadRelay derived object + CSubThreadRelay* (*FactoryFunctionL) (TThreadId aMainThreadId, TAny* aCodecParam); + FactoryFunctionL = threadRelayParam->iFactoryFunctionL; + + CSubThreadRelay* subThreadRelay; + //Call the factory function + subThreadRelay = FactoryFunctionL(threadRelayParam->iMainThreadId, threadRelayParam->iCodecParam); + CleanupStack::PushL(subThreadRelay); + + //Send a pointer to the sub thread relay back to the main thread + *threadRelayParam->iSubThreadRelay = subThreadRelay; + + subThreadRelay->Prime(); + + // Send a signal to the main thread that the setup was completed + subThreadRelay->SignalSetupComplete(threadRelayParam->iSetupComplete); + + CActiveScheduler::Start(); + + CleanupStack::PopAndDestroy(2,scheduler); //subThreadRelay, scheduler + REComSession::FinalClose(); + } + +// +// CSubThreadRelay +// +/** + * Open a connection to the main (caller) thread. + * + */ +void CSubThreadRelay::ConstructL(TThreadId aMainThreadId) + { + User::LeaveIfError(iMainThread.Open(aMainThreadId)); + } + +/** + * Constructor for this class. + * Add the function call listener to the active scheduler. + * + */ +CSubThreadRelay::CSubThreadRelay(): + CActive(EPriorityStandard) + { + CActiveScheduler::Add(this); + } + +/** + * Destructor for this class. + * Close the connection to the main thread. + * + */ +CSubThreadRelay::~CSubThreadRelay() + { + iMainThread.Close(); + } + +/** + * Cancel the function call listener. + * + */ +void CSubThreadRelay::DoCancel() + { + } + +/** + * Send a signal to the main thread to indicate that the thread startup + * was successfull. + * + */ +void CSubThreadRelay::SignalSetupComplete(TRequestStatus* aSetupComplete) + { + iMainThread.RequestComplete(aSetupComplete, KErrNone); + } + +/** + * Prime the function call listener. + * + */ +void CSubThreadRelay::Prime() + { + ASSERT(IsActive() == EFalse); + iStatus = KRequestPending; + SetActive(); + } + +/** + * Execute a function in the sub thread. Signal the leave result of the function + * to the main thread. If the termination function is called stop the active + * scheduler for the sub thread. (This will cause the thread to terminate) + * + */ +void CSubThreadRelay::RunL() + { + ASSERT(iStatus == KErrNone); + + TInt error = KErrNone; + //Thread termination function called + if(iFunctionCode == KTerminationFunction) + CActiveScheduler::Stop(); + else + { + Prime(); + TRAP(error, RunFunctionL(iFunctionCode, iFunctionParams)); + } + TRequestStatus *status = iCallingStatus; + iMainThread.RequestComplete(status, error); + } + +/** + * Save the function number and parameters for an outstanding function call in the + * codec thread. + * + * @param "TRequestStatus& aCallingStatus" + * Request to signal the main thread when the function call has completed. + * @param "TInt aFunctionCode" + * The function number to execute. + * @param "TAny* aParameters" + * Parameters to the function to execute. + */ +void CSubThreadRelay::RunFunctionInThread(TRequestStatus& aCallingStatus, TInt aFunctionCode, TAny* aParameters) + { + iCallingStatus = &aCallingStatus; + iFunctionCode = aFunctionCode; + iFunctionParams = aParameters; + } + +/** + * Store a pointer to the codec thread object. + * + * @param "RThread* aSubThread" + * A pointer to the codec thread object. + */ +void CSubThreadRelay::SetSubThread(RThread* aSubThread) + { + iSubThread = aSubThread; + } + +/** + * Return a pointer to the function call listener's request status. + * Signal this from the main thread to request a function to be executed + * in the thread after a call to RunFunctionInThread(). + * + * @return "TRequestStatus*" + * Request to signal the start of execution of a function in the thread. + */ +TRequestStatus* CSubThreadRelay::Status() + { + return &iStatus; + } + +// +//CSubThreadUndertaker +// +/** + * Factory function for the class. + * + * @param "RThread& aSubThread" + * A thread to monitor for panics + */ +CSubThreadUndertaker* CSubThreadUndertaker::NewL(RThread& aSubThread) + { + CSubThreadUndertaker* self; + self = new (ELeave) CSubThreadUndertaker(&aSubThread); + return self; + } + +/** + * Constructor for the class. + * Add the object to the active scheduler, activate and logon to the + * thread to monitor for panics + * + * @param "RThread* aSubThread" + * A thread to monitor for panics + */ +CSubThreadUndertaker::CSubThreadUndertaker(RThread* aSubThread) : + CActive(CActive::EPriorityIdle), + iSubThread(aSubThread) + { + //Add ourself to the active scheduler + CActiveScheduler::Add(this); + + iSubThread = aSubThread; + + ASSERT(IsActive()==EFalse); + iStatus = KRequestPending; + SetActive(); + + //Logon to the thread so we will receive signals + iSubThread->Logon(iStatus); + } + +/** + * Destructor for this class. + * Make sure that the undertaker was cancelled before deleted. + */ +CSubThreadUndertaker::~CSubThreadUndertaker() + { + Cancel(); + } + +/** + * This function is triggered when the thread being monitored terminates. + * If the thread being monitored panic, panic this thread. + * + */ +void CSubThreadUndertaker::RunL() + { + ASSERT(iSubThread != NULL); + //If we got here the thread has exited + TInt reason = iSubThread->ExitReason(); + TExitCategoryName category = iSubThread->ExitCategory(); + User::Panic(category, reason); + } + +/** + * Stop monitoring the thread for panics. This function is executed by + * calling Cancel() and has to be done before the object is deleted. + * + */ +void CSubThreadUndertaker::DoCancel() + { + iSubThread->LogonCancel(iStatus); + }