--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imagingandcamerafws/imagingfws/src/GenThreadRelay.cpp Wed Sep 01 12:38:50 2010 +0100
@@ -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 <ecom/ecom.h>
+
+_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<TUint>(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);
+ }