diff -r 22de2e391156 -r 20ac952a623c remotecontrol/remotecontrolfw/common/utils.cpp --- /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 +#include + +#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(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(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 iInbound; + RMsgQueue 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 + +