imagingandcamerafws/imagingfws/src/GenThreadRelay.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagingandcamerafws/imagingfws/src/GenThreadRelay.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -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,
+		&param);
+	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);
+	}