remotecontrol/remotecontrolfw/common/utils.cpp
changeset 51 20ac952a623c
equal deleted inserted replaced
48:22de2e391156 51:20ac952a623c
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include "utils.h"
       
    22 #include <e32msgqueue.h>
       
    23 #include <bluetooth/logger.h>
       
    24 
       
    25 #ifdef __FLOG_ACTIVE
       
    26 _LIT8(KLogComponent, LOG_COMPONENT_REMCON_UTILS);
       
    27 #endif
       
    28 
       
    29 #ifdef _DEBUG
       
    30 PANICCATEGORY("RCFUtils");
       
    31 #endif
       
    32 
       
    33 /**
       
    34 Function passed in as a parameter to TCleanupItem constructor to reset and 
       
    35 destroy the received aPtr.
       
    36 @param aPtr A pointer to the object that is to be cleaned up
       
    37 */
       
    38 void ResetAndDestroy(TAny* aPtr)
       
    39 	{
       
    40 	ASSERT_DEBUG(aPtr);
       
    41 	reinterpret_cast<RImplInfoPtrArray*>(aPtr)->ResetAndDestroy();
       
    42 	}
       
    43 
       
    44 /**
       
    45 Function that creates a cleanup item for aArray and specifies the cleanup 
       
    46 function as ResetAndDestroy. When the item is removed from the cleanup stack 
       
    47 the function ResetAndDestroy will be called on aArray.
       
    48 @param aArray The array to be destroyed.
       
    49 */
       
    50 void CleanupResetAndDestroyPushL(RImplInfoPtrArray& aArray)
       
    51 	{		
       
    52 	TCleanupItem item(ResetAndDestroy, &aArray);
       
    53 	CleanupStack::PushL(item);
       
    54 	}
       
    55 
       
    56 void SwitchHeap(TAny* aPtr)
       
    57 	{
       
    58 	ASSERT_DEBUG(aPtr);
       
    59 	User::SwitchHeap(reinterpret_cast<RHeap*>(aPtr));
       
    60 	}
       
    61 
       
    62 void CleanupSwitchHeapPushL(RHeap& aHeap)
       
    63 	{
       
    64 	TCleanupItem item(SwitchHeap, &aHeap);
       
    65 	CleanupStack::PushL(item);
       
    66 	}
       
    67 
       
    68 
       
    69 RNestableLock::RNestableLock()
       
    70 	: iThreadId(KInvalidThreadId)
       
    71 	, iRefCount(0)
       
    72 	{
       
    73 	LOG_FUNC
       
    74 	}
       
    75 
       
    76 TInt RNestableLock::CreateLocal()
       
    77 	{
       
    78 	TInt err = iLock.CreateLocal();
       
    79 	if(err == KErrNone)
       
    80 		{
       
    81 		err = iMetaLock.CreateLocal();
       
    82 		}
       
    83 	if(err != KErrNone)
       
    84 		{
       
    85 		Close();
       
    86 		}
       
    87 	return err;
       
    88 	}
       
    89 
       
    90 void RNestableLock::Close()
       
    91 	{
       
    92 	LOG_FUNC
       
    93 	iLock.Close();
       
    94 	iMetaLock.Close();
       
    95 	iRefCount = 0;
       
    96 	iThreadId = TThreadId(KInvalidThreadId);
       
    97 	}
       
    98 
       
    99 void RNestableLock::Wait()
       
   100 	{
       
   101 	iMetaLock.Wait();
       
   102 	TThreadId currentThreadId = RThread().Id();
       
   103 	if(iThreadId == TThreadId(KInvalidThreadId) || currentThreadId != iThreadId)
       
   104 		{
       
   105 		iMetaLock.Signal();
       
   106 		iLock.Wait();
       
   107 		iMetaLock.Wait();
       
   108 		iThreadId = currentThreadId;
       
   109 		}
       
   110 	++iRefCount;
       
   111 	iMetaLock.Signal();
       
   112 	}
       
   113 
       
   114 void RNestableLock::Signal()
       
   115 	{
       
   116 	iMetaLock.Wait();
       
   117 	// Assert if current thread is stored current thread?
       
   118 	if(--iRefCount == 0)
       
   119 		{
       
   120 		iLock.Signal();
       
   121 		iThreadId = TThreadId(KInvalidThreadId);
       
   122 		}
       
   123 	iMetaLock.Signal();
       
   124 	}
       
   125 
       
   126 
       
   127 
       
   128 
       
   129 NONSHARABLE_CLASS(CSpecificThreadCallBackBody)
       
   130 	: public CActive
       
   131 	{
       
   132 public:
       
   133 	static CSpecificThreadCallBackBody* NewL(const TCallBack& aCallBack, TInt aPriority);
       
   134 	~CSpecificThreadCallBackBody();
       
   135 	
       
   136 	TInt Start();
       
   137 	TInt CallBack();
       
   138 	void HandleCancel();
       
   139 	
       
   140 private:
       
   141 	CSpecificThreadCallBackBody(const TCallBack& aCallBack, TInt aPriority);
       
   142 	void ConstructL();
       
   143 	
       
   144 	TInt AsyncMessage(TInt aParam);
       
   145 	
       
   146 private: // from CActive
       
   147 	void RunL();
       
   148 	void DoCancel();
       
   149 	
       
   150 private:
       
   151 	TCallBack		iCallBack;
       
   152 	
       
   153 	RThread			iLocalThread;
       
   154 	
       
   155 	RMsgQueue<TInt>	iInbound;
       
   156 	RMsgQueue<TInt>	iOutbound;
       
   157 	};
       
   158 
       
   159 
       
   160 RSpecificThreadCallBack::RSpecificThreadCallBack()
       
   161 	: iBody(NULL)
       
   162 	{
       
   163 	LOG_FUNC
       
   164 	}
       
   165 
       
   166 TInt RSpecificThreadCallBack::Create(const TCallBack& aCallBack, TInt aPriority)
       
   167 	{
       
   168 	TRAPD(err, iBody = CSpecificThreadCallBackBody::NewL(aCallBack, aPriority));
       
   169 	return err;
       
   170 	}
       
   171 
       
   172 void RSpecificThreadCallBack::Close()
       
   173 	{
       
   174 	LOG_FUNC
       
   175 	delete iBody;
       
   176 	iBody = NULL;
       
   177 	}
       
   178 
       
   179 TInt RSpecificThreadCallBack::Start()
       
   180 	{
       
   181 	ASSERT_DEBUG(iBody);
       
   182 	return iBody->Start();
       
   183 	}
       
   184 
       
   185 TInt RSpecificThreadCallBack::CallBack()
       
   186 	{
       
   187 	ASSERT_DEBUG(iBody);
       
   188 	return iBody->CallBack();
       
   189 	}
       
   190 
       
   191 void RSpecificThreadCallBack::Cancel()
       
   192 	{
       
   193 	ASSERT_DEBUG(iBody);
       
   194 	return iBody->HandleCancel();
       
   195 	}
       
   196 
       
   197 
       
   198 
       
   199 
       
   200 
       
   201 
       
   202 
       
   203 
       
   204 CSpecificThreadCallBackBody* CSpecificThreadCallBackBody::NewL(const TCallBack& aCallBack, TInt aPriority)
       
   205 	{
       
   206 	LOG_STATIC_FUNC
       
   207 	CSpecificThreadCallBackBody* self = new(ELeave) CSpecificThreadCallBackBody(aCallBack, aPriority);
       
   208 	CleanupStack::PushL(self);
       
   209 	self->ConstructL();
       
   210 	CleanupStack::Pop(self);
       
   211 	return self;
       
   212 	}
       
   213 
       
   214 CSpecificThreadCallBackBody::CSpecificThreadCallBackBody(const TCallBack& aCallBack, TInt aPriority)
       
   215 	: CActive(aPriority)
       
   216 	, iCallBack(aCallBack)
       
   217 	{
       
   218 	LOG_FUNC
       
   219 	}
       
   220 
       
   221 void CSpecificThreadCallBackBody::ConstructL()
       
   222 	{
       
   223 	User::LeaveIfError(iInbound.CreateLocal(1));
       
   224 	User::LeaveIfError(iOutbound.CreateLocal(1));
       
   225 	}
       
   226 
       
   227 CSpecificThreadCallBackBody::~CSpecificThreadCallBackBody()
       
   228 	{
       
   229 	LOG_FUNC
       
   230 	HandleCancel();
       
   231 	iInbound.Close();
       
   232 	iOutbound.Close();
       
   233 	iLocalThread.Close();
       
   234 	}
       
   235 
       
   236 TInt CSpecificThreadCallBackBody::Start()
       
   237 	{
       
   238 	TInt err = KErrNone;
       
   239 	if(!IsAdded())
       
   240 		{
       
   241 		err = iLocalThread.Duplicate(RThread());
       
   242 		if(err == KErrNone)
       
   243 			{
       
   244 			CActiveScheduler::Add(this);
       
   245 			iInbound.NotifyDataAvailable(iStatus);
       
   246 			SetActive();
       
   247 			}
       
   248 		}
       
   249 	return err;
       
   250 	}
       
   251 
       
   252 TInt CSpecificThreadCallBackBody::CallBack()
       
   253 	{
       
   254 	TInt err = KErrUnknown;
       
   255 	if(iLocalThread.Id() == RThread().Id())
       
   256 		{
       
   257 		// Simple synchronous case.
       
   258 		err = iCallBack.CallBack();
       
   259 		}
       
   260 	else
       
   261 		{
       
   262 		RThread thisThread;
       
   263 		err = thisThread.Duplicate(RThread());
       
   264 		if(err == KErrNone)
       
   265 			{
       
   266 			err = AsyncMessage(thisThread.Handle());
       
   267 			}
       
   268 		}
       
   269 	return err;
       
   270 	}
       
   271 	
       
   272 TInt CSpecificThreadCallBackBody::AsyncMessage(TInt aParam)
       
   273 	{
       
   274 	TInt err = KErrNone;
       
   275 	TRequestStatus logonStatus;
       
   276 	iLocalThread.Logon(logonStatus);
       
   277 	if(logonStatus == KErrNoMemory)
       
   278 		{
       
   279 		// This seems kludgy, but I think it is the most reliable way.
       
   280 		User::WaitForRequest(logonStatus); // Ensure the all requests are correct...
       
   281 		err = KErrNoMemory;
       
   282 		}
       
   283 	else
       
   284 		{
       
   285 		iInbound.SendBlocking(aParam);
       
   286 		TRequestStatus status;
       
   287 		iOutbound.NotifyDataAvailable(status);
       
   288 		User::WaitForRequest(status, logonStatus);
       
   289 		if(status == KRequestPending)
       
   290 			{
       
   291 			// Remote thread is dead
       
   292 			iOutbound.CancelDataAvailable();
       
   293 			User::WaitForRequest(status);
       
   294 			err = KErrDied;
       
   295 			}
       
   296 		else
       
   297 			{
       
   298 			// Success (the thread may have subsequently died, but we are only concerned with this call).
       
   299 			iLocalThread.LogonCancel(logonStatus);
       
   300 			User::WaitForRequest(logonStatus);
       
   301 			err = status.Int();
       
   302 			if(err == KErrNone)
       
   303 				{
       
   304 				iOutbound.ReceiveBlocking(err);
       
   305 				}
       
   306 			}
       
   307 		}
       
   308 	return err;
       
   309 	}
       
   310 
       
   311 
       
   312 void CSpecificThreadCallBackBody::RunL()
       
   313 	{
       
   314 	TInt threadHandle;
       
   315 	iInbound.ReceiveBlocking(threadHandle);
       
   316 	if(threadHandle == 0)
       
   317 		{
       
   318 		// 0 is a cancel message
       
   319 		// therefore don't do anything
       
   320 		iOutbound.SendBlocking(KErrNone);
       
   321 		}
       
   322 	else
       
   323 		{
       
   324 		RThread remoteThread;
       
   325 		remoteThread.SetHandleNC(threadHandle);
       
   326 		
       
   327 		TInt result = iCallBack.CallBack();
       
   328 		
       
   329 		// There doesn't seem to be a safe way of handling when the other thread
       
   330 		// dies......
       
   331 		iOutbound.SendBlocking(result);
       
   332 		
       
   333 		remoteThread.Close();
       
   334 		
       
   335 		iInbound.NotifyDataAvailable(iStatus);
       
   336 		SetActive();
       
   337 		}
       
   338 	}
       
   339 
       
   340 void CSpecificThreadCallBackBody::DoCancel()
       
   341 	{
       
   342 	if(RThread().Id() == iLocalThread.Id())
       
   343 		{
       
   344 		iInbound.CancelDataAvailable();
       
   345 		}
       
   346 	else
       
   347 		{
       
   348 		// other thread cancelling - so just complete the
       
   349 		// request
       
   350 		TRequestStatus* status = &iStatus;
       
   351 		User::RequestComplete(status, KErrCancel);
       
   352 		}
       
   353 	}
       
   354 
       
   355 void CSpecificThreadCallBackBody::HandleCancel()
       
   356 	{
       
   357 	if(IsAdded())
       
   358 		{
       
   359 		if(RThread().Id() == iLocalThread.Id())
       
   360 			{
       
   361 			Cancel(); // synchronous cancel is fine in same thread...
       
   362 			}
       
   363 		else
       
   364 			{
       
   365 			// In a different thread - this is more interesting...
       
   366 			TInt err = AsyncMessage(0); // 0 is special as it means cancel.
       
   367 			if(err == KErrDied && IsActive())
       
   368 				{
       
   369 				// Remote thread has already died so we need to tidy up the
       
   370 				// active object ourselves.
       
   371 				Cancel();
       
   372 				}
       
   373 			}
       
   374 		}
       
   375 	// else shouldn't be active...
       
   376 	}
       
   377 
       
   378 
       
   379 #ifdef _DEBUG
       
   380 _LIT(KCountSizeWriteStreamPanic, "CountStream");
       
   381 #endif // _DEBUG
       
   382 #define ASSERT_NOT_CALLED __ASSERT_DEBUG(EFalse, User::Panic(KCountSizeWriteStreamPanic, 0));
       
   383 
       
   384 RCountSizeWriteStream::RCountSizeWriteStream()
       
   385 	: RWriteStream()
       
   386 	, iSize(0)
       
   387 	{
       
   388 	Attach(this);
       
   389 	}
       
   390 
       
   391 TInt RCountSizeWriteStream::Size() const
       
   392 	{
       
   393 	return iSize;
       
   394 	}
       
   395 
       
   396 void RCountSizeWriteStream::Reset()
       
   397 	{
       
   398 	iSize = 0;
       
   399 	}
       
   400 
       
   401 void RCountSizeWriteStream::DoRelease()
       
   402 	{
       
   403 	// No resources to free - Nothing to do
       
   404 	}
       
   405 
       
   406 void RCountSizeWriteStream::DoSynchL()
       
   407 	{
       
   408 	// No buffering - Nothing to do
       
   409 	}
       
   410 
       
   411 TInt RCountSizeWriteStream::DoReadL(TAny* /*aPtr*/,TInt /*aMaxLength*/)
       
   412 	{
       
   413 	LOG_FUNC
       
   414 	ASSERT_NOT_CALLED;
       
   415 	User::Leave(KErrNotSupported);
       
   416 	return 0;
       
   417 	}
       
   418 
       
   419 TInt RCountSizeWriteStream::DoReadL(TDes8& /*aDes*/,TInt /*aMaxLength*/,TRequestStatus& /*aStatus*/)
       
   420 	{
       
   421 	LOG_FUNC
       
   422 	ASSERT_NOT_CALLED;
       
   423 	User::Leave(KErrNotSupported);
       
   424 	return 0;
       
   425 	}
       
   426 
       
   427 TStreamTransfer RCountSizeWriteStream::DoReadL(MStreamInput& /*anInput*/,TStreamTransfer /*aTransfer*/)
       
   428 	{
       
   429 	LOG_FUNC
       
   430 	ASSERT_NOT_CALLED;
       
   431 	User::Leave(KErrNotSupported);
       
   432 	return 0;
       
   433 	}
       
   434 
       
   435 void RCountSizeWriteStream::DoWriteL(const TAny* /*aPtr*/,TInt aLength)
       
   436 	{
       
   437 	iSize += aLength;
       
   438 	}
       
   439 
       
   440 TInt RCountSizeWriteStream::DoWriteL(const TDesC8& /*aDes*/,TInt aMaxLength,TRequestStatus& aStatus)
       
   441 	{
       
   442 	iSize += aMaxLength;
       
   443 	TRequestStatus* stat = &aStatus;
       
   444 	User::RequestComplete(stat, KErrNone);
       
   445 	return aMaxLength;
       
   446 	}
       
   447 
       
   448 TStreamTransfer RCountSizeWriteStream::DoWriteL(MStreamOutput& /*anOutput*/,TStreamTransfer /*aTransfer*/)
       
   449 	{
       
   450 	ASSERT_NOT_CALLED;
       
   451 	User::Leave(KErrNotSupported);
       
   452 	return 0;
       
   453 	}
       
   454 
       
   455 TStreamPos RCountSizeWriteStream::DoSeekL(TMark /*aMark*/,TStreamLocation /*aLocation*/,TInt /*anOffset*/)
       
   456 	{
       
   457 	ASSERT_NOT_CALLED;
       
   458 	User::Leave(KErrNotSupported);
       
   459 	return 0;
       
   460 	}
       
   461 
       
   462 #undef ASSERT_NOT_CALLED
       
   463 
       
   464