remotecontrol/remotecontrolfw/common/utils.cpp
changeset 51 20ac952a623c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remotecontrol/remotecontrolfw/common/utils.cpp	Wed Oct 13 16:20:29 2010 +0300
@@ -0,0 +1,464 @@
+// Copyright (c) 2004-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "utils.h"
+#include <e32msgqueue.h>
+#include <bluetooth/logger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCON_UTILS);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("RCFUtils");
+#endif
+
+/**
+Function passed in as a parameter to TCleanupItem constructor to reset and 
+destroy the received aPtr.
+@param aPtr A pointer to the object that is to be cleaned up
+*/
+void ResetAndDestroy(TAny* aPtr)
+	{
+	ASSERT_DEBUG(aPtr);
+	reinterpret_cast<RImplInfoPtrArray*>(aPtr)->ResetAndDestroy();
+	}
+
+/**
+Function that creates a cleanup item for aArray and specifies the cleanup 
+function as ResetAndDestroy. When the item is removed from the cleanup stack 
+the function ResetAndDestroy will be called on aArray.
+@param aArray The array to be destroyed.
+*/
+void CleanupResetAndDestroyPushL(RImplInfoPtrArray& aArray)
+	{		
+	TCleanupItem item(ResetAndDestroy, &aArray);
+	CleanupStack::PushL(item);
+	}
+
+void SwitchHeap(TAny* aPtr)
+	{
+	ASSERT_DEBUG(aPtr);
+	User::SwitchHeap(reinterpret_cast<RHeap*>(aPtr));
+	}
+
+void CleanupSwitchHeapPushL(RHeap& aHeap)
+	{
+	TCleanupItem item(SwitchHeap, &aHeap);
+	CleanupStack::PushL(item);
+	}
+
+
+RNestableLock::RNestableLock()
+	: iThreadId(KInvalidThreadId)
+	, iRefCount(0)
+	{
+	LOG_FUNC
+	}
+
+TInt RNestableLock::CreateLocal()
+	{
+	TInt err = iLock.CreateLocal();
+	if(err == KErrNone)
+		{
+		err = iMetaLock.CreateLocal();
+		}
+	if(err != KErrNone)
+		{
+		Close();
+		}
+	return err;
+	}
+
+void RNestableLock::Close()
+	{
+	LOG_FUNC
+	iLock.Close();
+	iMetaLock.Close();
+	iRefCount = 0;
+	iThreadId = TThreadId(KInvalidThreadId);
+	}
+
+void RNestableLock::Wait()
+	{
+	iMetaLock.Wait();
+	TThreadId currentThreadId = RThread().Id();
+	if(iThreadId == TThreadId(KInvalidThreadId) || currentThreadId != iThreadId)
+		{
+		iMetaLock.Signal();
+		iLock.Wait();
+		iMetaLock.Wait();
+		iThreadId = currentThreadId;
+		}
+	++iRefCount;
+	iMetaLock.Signal();
+	}
+
+void RNestableLock::Signal()
+	{
+	iMetaLock.Wait();
+	// Assert if current thread is stored current thread?
+	if(--iRefCount == 0)
+		{
+		iLock.Signal();
+		iThreadId = TThreadId(KInvalidThreadId);
+		}
+	iMetaLock.Signal();
+	}
+
+
+
+
+NONSHARABLE_CLASS(CSpecificThreadCallBackBody)
+	: public CActive
+	{
+public:
+	static CSpecificThreadCallBackBody* NewL(const TCallBack& aCallBack, TInt aPriority);
+	~CSpecificThreadCallBackBody();
+	
+	TInt Start();
+	TInt CallBack();
+	void HandleCancel();
+	
+private:
+	CSpecificThreadCallBackBody(const TCallBack& aCallBack, TInt aPriority);
+	void ConstructL();
+	
+	TInt AsyncMessage(TInt aParam);
+	
+private: // from CActive
+	void RunL();
+	void DoCancel();
+	
+private:
+	TCallBack		iCallBack;
+	
+	RThread			iLocalThread;
+	
+	RMsgQueue<TInt>	iInbound;
+	RMsgQueue<TInt>	iOutbound;
+	};
+
+
+RSpecificThreadCallBack::RSpecificThreadCallBack()
+	: iBody(NULL)
+	{
+	LOG_FUNC
+	}
+
+TInt RSpecificThreadCallBack::Create(const TCallBack& aCallBack, TInt aPriority)
+	{
+	TRAPD(err, iBody = CSpecificThreadCallBackBody::NewL(aCallBack, aPriority));
+	return err;
+	}
+
+void RSpecificThreadCallBack::Close()
+	{
+	LOG_FUNC
+	delete iBody;
+	iBody = NULL;
+	}
+
+TInt RSpecificThreadCallBack::Start()
+	{
+	ASSERT_DEBUG(iBody);
+	return iBody->Start();
+	}
+
+TInt RSpecificThreadCallBack::CallBack()
+	{
+	ASSERT_DEBUG(iBody);
+	return iBody->CallBack();
+	}
+
+void RSpecificThreadCallBack::Cancel()
+	{
+	ASSERT_DEBUG(iBody);
+	return iBody->HandleCancel();
+	}
+
+
+
+
+
+
+
+
+CSpecificThreadCallBackBody* CSpecificThreadCallBackBody::NewL(const TCallBack& aCallBack, TInt aPriority)
+	{
+	LOG_STATIC_FUNC
+	CSpecificThreadCallBackBody* self = new(ELeave) CSpecificThreadCallBackBody(aCallBack, aPriority);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CSpecificThreadCallBackBody::CSpecificThreadCallBackBody(const TCallBack& aCallBack, TInt aPriority)
+	: CActive(aPriority)
+	, iCallBack(aCallBack)
+	{
+	LOG_FUNC
+	}
+
+void CSpecificThreadCallBackBody::ConstructL()
+	{
+	User::LeaveIfError(iInbound.CreateLocal(1));
+	User::LeaveIfError(iOutbound.CreateLocal(1));
+	}
+
+CSpecificThreadCallBackBody::~CSpecificThreadCallBackBody()
+	{
+	LOG_FUNC
+	HandleCancel();
+	iInbound.Close();
+	iOutbound.Close();
+	iLocalThread.Close();
+	}
+
+TInt CSpecificThreadCallBackBody::Start()
+	{
+	TInt err = KErrNone;
+	if(!IsAdded())
+		{
+		err = iLocalThread.Duplicate(RThread());
+		if(err == KErrNone)
+			{
+			CActiveScheduler::Add(this);
+			iInbound.NotifyDataAvailable(iStatus);
+			SetActive();
+			}
+		}
+	return err;
+	}
+
+TInt CSpecificThreadCallBackBody::CallBack()
+	{
+	TInt err = KErrUnknown;
+	if(iLocalThread.Id() == RThread().Id())
+		{
+		// Simple synchronous case.
+		err = iCallBack.CallBack();
+		}
+	else
+		{
+		RThread thisThread;
+		err = thisThread.Duplicate(RThread());
+		if(err == KErrNone)
+			{
+			err = AsyncMessage(thisThread.Handle());
+			}
+		}
+	return err;
+	}
+	
+TInt CSpecificThreadCallBackBody::AsyncMessage(TInt aParam)
+	{
+	TInt err = KErrNone;
+	TRequestStatus logonStatus;
+	iLocalThread.Logon(logonStatus);
+	if(logonStatus == KErrNoMemory)
+		{
+		// This seems kludgy, but I think it is the most reliable way.
+		User::WaitForRequest(logonStatus); // Ensure the all requests are correct...
+		err = KErrNoMemory;
+		}
+	else
+		{
+		iInbound.SendBlocking(aParam);
+		TRequestStatus status;
+		iOutbound.NotifyDataAvailable(status);
+		User::WaitForRequest(status, logonStatus);
+		if(status == KRequestPending)
+			{
+			// Remote thread is dead
+			iOutbound.CancelDataAvailable();
+			User::WaitForRequest(status);
+			err = KErrDied;
+			}
+		else
+			{
+			// Success (the thread may have subsequently died, but we are only concerned with this call).
+			iLocalThread.LogonCancel(logonStatus);
+			User::WaitForRequest(logonStatus);
+			err = status.Int();
+			if(err == KErrNone)
+				{
+				iOutbound.ReceiveBlocking(err);
+				}
+			}
+		}
+	return err;
+	}
+
+
+void CSpecificThreadCallBackBody::RunL()
+	{
+	TInt threadHandle;
+	iInbound.ReceiveBlocking(threadHandle);
+	if(threadHandle == 0)
+		{
+		// 0 is a cancel message
+		// therefore don't do anything
+		iOutbound.SendBlocking(KErrNone);
+		}
+	else
+		{
+		RThread remoteThread;
+		remoteThread.SetHandleNC(threadHandle);
+		
+		TInt result = iCallBack.CallBack();
+		
+		// There doesn't seem to be a safe way of handling when the other thread
+		// dies......
+		iOutbound.SendBlocking(result);
+		
+		remoteThread.Close();
+		
+		iInbound.NotifyDataAvailable(iStatus);
+		SetActive();
+		}
+	}
+
+void CSpecificThreadCallBackBody::DoCancel()
+	{
+	if(RThread().Id() == iLocalThread.Id())
+		{
+		iInbound.CancelDataAvailable();
+		}
+	else
+		{
+		// other thread cancelling - so just complete the
+		// request
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, KErrCancel);
+		}
+	}
+
+void CSpecificThreadCallBackBody::HandleCancel()
+	{
+	if(IsAdded())
+		{
+		if(RThread().Id() == iLocalThread.Id())
+			{
+			Cancel(); // synchronous cancel is fine in same thread...
+			}
+		else
+			{
+			// In a different thread - this is more interesting...
+			TInt err = AsyncMessage(0); // 0 is special as it means cancel.
+			if(err == KErrDied && IsActive())
+				{
+				// Remote thread has already died so we need to tidy up the
+				// active object ourselves.
+				Cancel();
+				}
+			}
+		}
+	// else shouldn't be active...
+	}
+
+
+#ifdef _DEBUG
+_LIT(KCountSizeWriteStreamPanic, "CountStream");
+#endif // _DEBUG
+#define ASSERT_NOT_CALLED __ASSERT_DEBUG(EFalse, User::Panic(KCountSizeWriteStreamPanic, 0));
+
+RCountSizeWriteStream::RCountSizeWriteStream()
+	: RWriteStream()
+	, iSize(0)
+	{
+	Attach(this);
+	}
+
+TInt RCountSizeWriteStream::Size() const
+	{
+	return iSize;
+	}
+
+void RCountSizeWriteStream::Reset()
+	{
+	iSize = 0;
+	}
+
+void RCountSizeWriteStream::DoRelease()
+	{
+	// No resources to free - Nothing to do
+	}
+
+void RCountSizeWriteStream::DoSynchL()
+	{
+	// No buffering - Nothing to do
+	}
+
+TInt RCountSizeWriteStream::DoReadL(TAny* /*aPtr*/,TInt /*aMaxLength*/)
+	{
+	LOG_FUNC
+	ASSERT_NOT_CALLED;
+	User::Leave(KErrNotSupported);
+	return 0;
+	}
+
+TInt RCountSizeWriteStream::DoReadL(TDes8& /*aDes*/,TInt /*aMaxLength*/,TRequestStatus& /*aStatus*/)
+	{
+	LOG_FUNC
+	ASSERT_NOT_CALLED;
+	User::Leave(KErrNotSupported);
+	return 0;
+	}
+
+TStreamTransfer RCountSizeWriteStream::DoReadL(MStreamInput& /*anInput*/,TStreamTransfer /*aTransfer*/)
+	{
+	LOG_FUNC
+	ASSERT_NOT_CALLED;
+	User::Leave(KErrNotSupported);
+	return 0;
+	}
+
+void RCountSizeWriteStream::DoWriteL(const TAny* /*aPtr*/,TInt aLength)
+	{
+	iSize += aLength;
+	}
+
+TInt RCountSizeWriteStream::DoWriteL(const TDesC8& /*aDes*/,TInt aMaxLength,TRequestStatus& aStatus)
+	{
+	iSize += aMaxLength;
+	TRequestStatus* stat = &aStatus;
+	User::RequestComplete(stat, KErrNone);
+	return aMaxLength;
+	}
+
+TStreamTransfer RCountSizeWriteStream::DoWriteL(MStreamOutput& /*anOutput*/,TStreamTransfer /*aTransfer*/)
+	{
+	ASSERT_NOT_CALLED;
+	User::Leave(KErrNotSupported);
+	return 0;
+	}
+
+TStreamPos RCountSizeWriteStream::DoSeekL(TMark /*aMark*/,TStreamLocation /*aLocation*/,TInt /*anOffset*/)
+	{
+	ASSERT_NOT_CALLED;
+	User::Leave(KErrNotSupported);
+	return 0;
+	}
+
+#undef ASSERT_NOT_CALLED
+
+