--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/accessoryservices/remotecontrolfw/common/utils.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -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
+
+