mmlibs/mmfw/src/server/BaseClasses/mmfsubthreadbase.cpp
changeset 0 b8ed18f6c07b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/src/server/BaseClasses/mmfsubthreadbase.cpp	Thu Oct 07 22:34:12 2010 +0100
@@ -0,0 +1,331 @@
+// Copyright (c) 2002-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 <mmf/server/mmfsubthreadbase.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <mmf/server/mmfsubthreadbaseimpl.h>
+#endif
+
+
+EXPORT_C void RMMFSubThreadBase::ReceiveEvents(TMMFEventPckg& aEventPckg, TRequestStatus& aStatus)
+	{
+	SendReceiveResult(EMMFSubThreadReceiveEvents, aEventPckg, aStatus);
+	}
+
+EXPORT_C TInt RMMFSubThreadBase::CancelReceiveEvents()
+	{
+	return SendReceive(EMMFSubThreadCancelReceiveEvents);
+	}
+
+EXPORT_C void RMMFSubThreadBase::Shutdown()
+	{
+	if (iSubThread.Handle() != KNullHandle)
+		{
+		// check that the subthread has yet to terminate
+		if (iLogonStatus == KRequestPending)
+			{	
+			//close the subthread and wait for its exit.
+			//signal to the subthread to close down.			
+			TInt shutdownError = SendReceive(EMMFSubThreadShutdown);
+			if (shutdownError != KErrNone)
+				{
+				iSubThread.LogonCancel(iLogonStatus);
+				}
+			else
+				{
+				RTimer timer;
+				TInt err = timer.CreateLocal();
+				//if we managed to create the timer, wait for both the death and the timeout to minimise the risk of deadlock
+				if (!err)
+					{
+					TRequestStatus timeout;
+					timer.After(timeout, iShutdownTimeout);
+					User::WaitForRequest(iLogonStatus, timeout);
+					if (iLogonStatus == KRequestPending)
+						{
+						//we have timed out.  Panic the thread in debug mode, kill it in release mode.
+						iSubThread.LogonCancel(iLogonStatus);
+						User::WaitForRequest(iLogonStatus);
+					#ifdef _DEBUG	
+						Panic(EMMFSubThreadPanicTimedOut);
+					#else
+						iSubThread.Kill(KErrDied);
+					#endif
+						}
+					else
+						{
+						//subthread has exited. Cancel the timer.
+						timer.Cancel();
+						User::WaitForRequest(timeout);
+						}
+					}
+				else
+					{
+					//we have no timer so we'll just have to risk the deadlock
+					User::WaitForRequest(iLogonStatus);
+					}
+				timer.Close();
+				}
+			}
+		//close the handle to the subthread
+		iSubThread.Close();
+		}
+	// close our parent
+	RHandleBase::Close(); 
+	}
+	
+void RMMFSubThreadBase::Panic(TMMFSubThreadPanicCode aPanicCode)
+	{
+	_LIT(KMMFSubThreadPanicCategory, "MMFSubThread");
+	iSubThread.Panic(KMMFSubThreadPanicCategory, aPanicCode);
+	}
+
+TInt RMMFSubThreadBase::DoCreateSubThread(const TDesC& aName, TThreadFunction aFunction, TBool aUseNewHeap)
+	{
+	TInt error = KErrNone;
+
+	if (aUseNewHeap)
+		{
+		error = iSubThread.Create(aName, aFunction,
+			KDefaultStackSize, KMinHeapSize, KMMFSubThreadMaxHeapSize, 
+			NULL, EOwnerThread);
+		}
+	else
+		{
+		error = iSubThread.Create(aName, aFunction,
+			KDefaultStackSize, &User::Heap(), 
+			NULL, EOwnerThread);
+		}
+
+	if (error)
+		{
+		return error;
+		}
+	
+	TRequestStatus rendezvous;
+	iSubThread.Rendezvous(rendezvous);
+	
+	if (rendezvous != KRequestPending)
+		{
+		iSubThread.Kill(0);
+		}
+	else
+		{
+		iLogonStatus = KRequestPending;
+		iSubThread.Logon(iLogonStatus);
+		if (iLogonStatus != KRequestPending)
+			{
+			// Failed to log on
+			iSubThread.RendezvousCancel(rendezvous);
+			User::WaitForRequest(rendezvous);
+			iSubThread.Kill(0);
+			iSubThread.Close();
+			return iLogonStatus.Int();
+			}
+		else
+			{
+			iSubThread.Resume();		
+			}
+		}
+	User::WaitForRequest(rendezvous); // wait for start or death
+	
+	if (rendezvous != KErrNone)
+		{
+		iSubThread.LogonCancel(iLogonStatus);
+		User::WaitForRequest(iLogonStatus);
+		iSubThread.Close();
+		return rendezvous.Int();
+		}
+		
+	return KErrNone;	
+	}
+
+CMMFSubThreadShutdown* CMMFSubThreadShutdown::NewL() 
+	{
+	CMMFSubThreadShutdown* s = new(ELeave) CMMFSubThreadShutdown();
+	CleanupStack::PushL(s);
+	s->ConstructL();
+	CleanupStack::Pop();
+	return s;
+	}
+
+CMMFSubThreadShutdown::CMMFSubThreadShutdown() : 
+	CTimer(EPriorityLow)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CMMFSubThreadShutdown::ConstructL()
+	{
+	CTimer::ConstructL();
+	}
+
+void CMMFSubThreadShutdown::Start()
+	{
+	After(EMMFSubThreadShutdownDelay);
+	}
+
+void CMMFSubThreadShutdown::RunL()
+	{
+	ShutdownNow();
+	}
+
+void CMMFSubThreadShutdown::ShutdownNow()
+	{
+	CActiveScheduler::Stop();
+	}
+
+
+
+
+CMMFSubThreadServer::CMMFSubThreadServer(TInt aPriority) :
+	CMmfIpcServer(aPriority)
+	{
+	}
+
+void CMMFSubThreadServer::ConstructL()
+	{
+	StartL(RThread().Name());
+	iShutdownTimer = CMMFSubThreadShutdown::NewL();
+	iShutdownTimer->Start();
+	}
+
+CMMFSubThreadServer::~CMMFSubThreadServer()
+	{
+	delete iShutdownTimer;
+	}
+
+void CMMFSubThreadServer::SessionCreated()
+	{
+	//stop the shutdown timer
+	iShutdownTimer->Cancel();
+	}
+
+void CMMFSubThreadServer::ShutdownNow()
+	{
+	iShutdownTimer->ShutdownNow();
+	}
+
+TInt CMMFSubThreadServer::RunError(TInt aError)
+	{
+	//signal the client
+	Message().Complete(aError);
+	ReStart();
+	return KErrNone;
+	}
+
+
+
+
+
+CMMFSubThreadEventReceiver* CMMFSubThreadEventReceiver::NewL(const RMmfIpcMessage& aMessage)
+	{
+	return new(ELeave) CMMFSubThreadEventReceiver(aMessage);
+	}
+
+CMMFSubThreadEventReceiver::~CMMFSubThreadEventReceiver()
+	{
+	if (iNeedToCompleteMessage)
+		iMessage.Complete(KErrDied);
+	}
+
+void CMMFSubThreadEventReceiver::SendEvent(const TMMFEvent& aEvent)
+	{
+	TMMFEventPckg eventpckg(aEvent);
+	TRAPD(err, MmfMessageUtil::WriteL(iMessage, 0, eventpckg));
+	iMessage.Complete(err);
+	iNeedToCompleteMessage = EFalse;
+	}
+
+CMMFSubThreadEventReceiver::CMMFSubThreadEventReceiver(const RMmfIpcMessage& aMessage) : 
+	iMessage(aMessage)
+	{
+	iNeedToCompleteMessage = ETrue;
+	}
+
+
+
+
+
+
+void CMMFSubThreadSession::CreateL(const CMmfIpcServer& aServer)
+	{
+	CMmfIpcSession::CreateL(aServer);
+	iServer = STATIC_CAST(CMMFSubThreadServer*, (CONST_CAST(CMmfIpcServer*, &aServer)));
+	iServer->SessionCreated();
+	}
+
+
+CMMFSubThreadSession::~CMMFSubThreadSession()
+	{
+	delete iEventReceiver;
+	iEvents.Close();
+	}
+
+
+TBool CMMFSubThreadSession::ReceiveEventsL(const RMmfIpcMessage& aMessage)
+	{
+	if (iEventReceiver)
+		User::Leave(KErrAlreadyExists);
+	iEventReceiver = CMMFSubThreadEventReceiver::NewL(aMessage);
+	//send the next cached event (if any) to the client
+	if (iEvents.Count() > 0)
+		{
+		TMMFEvent& event = iEvents[0];
+		iEventReceiver->SendEvent(event);
+		delete iEventReceiver;
+		iEventReceiver=NULL;
+		iEvents.Remove(0);
+		}
+	return EFalse;
+	}
+
+TBool CMMFSubThreadSession::CancelReceiveEvents()
+	{
+	delete iEventReceiver;
+	iEventReceiver = NULL;
+	return ETrue;
+	}
+
+TBool CMMFSubThreadSession::ShutDown()
+	{
+	iServer->ShutdownNow();
+	return ETrue;
+	}
+
+TInt CMMFSubThreadSession::SendEventToClient(const TMMFEvent& aEvent)
+	{
+	TInt error = KErrNone;
+	if (iEventReceiver)
+		{
+		//send event to client now
+		iEventReceiver->SendEvent(aEvent);
+		delete iEventReceiver;
+		iEventReceiver=NULL;
+		error = KErrNone;
+		}
+	else
+		{
+		//queue the request for later
+		TMMFEvent event(aEvent);
+		//if we've exceeded the max number of cached messages, delete the first and append this one to the end
+		if (iEvents.Count() >= KMMFSubThreadMaxCachedMessages)
+			iEvents.Remove(0);
+		error = iEvents.Append(event);
+		}
+	return error;
+	}
+
+