os/mm/mmlibs/mmfw/src/server/BaseClasses/mmfsubthreadbase.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2002-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 #include <mmf/server/mmfsubthreadbase.h>
    17 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
    18 #include <mmf/server/mmfsubthreadbaseimpl.h>
    19 #endif
    20 
    21 
    22 EXPORT_C void RMMFSubThreadBase::ReceiveEvents(TMMFEventPckg& aEventPckg, TRequestStatus& aStatus)
    23 	{
    24 	SendReceiveResult(EMMFSubThreadReceiveEvents, aEventPckg, aStatus);
    25 	}
    26 
    27 EXPORT_C TInt RMMFSubThreadBase::CancelReceiveEvents()
    28 	{
    29 	return SendReceive(EMMFSubThreadCancelReceiveEvents);
    30 	}
    31 
    32 EXPORT_C void RMMFSubThreadBase::Shutdown()
    33 	{
    34 	if (iSubThread.Handle() != KNullHandle)
    35 		{
    36 		// check that the subthread has yet to terminate
    37 		if (iLogonStatus == KRequestPending)
    38 			{	
    39 			//close the subthread and wait for its exit.
    40 			//signal to the subthread to close down.			
    41 			TInt shutdownError = SendReceive(EMMFSubThreadShutdown);
    42 			if (shutdownError != KErrNone)
    43 				{
    44 				iSubThread.LogonCancel(iLogonStatus);
    45 				}
    46 			else
    47 				{
    48 				RTimer timer;
    49 				TInt err = timer.CreateLocal();
    50 				//if we managed to create the timer, wait for both the death and the timeout to minimise the risk of deadlock
    51 				if (!err)
    52 					{
    53 					TRequestStatus timeout;
    54 					timer.After(timeout, iShutdownTimeout);
    55 					User::WaitForRequest(iLogonStatus, timeout);
    56 					if (iLogonStatus == KRequestPending)
    57 						{
    58 						//we have timed out.  Panic the thread in debug mode, kill it in release mode.
    59 						iSubThread.LogonCancel(iLogonStatus);
    60 						User::WaitForRequest(iLogonStatus);
    61 					#ifdef _DEBUG	
    62 						Panic(EMMFSubThreadPanicTimedOut);
    63 					#else
    64 						iSubThread.Kill(KErrDied);
    65 					#endif
    66 						}
    67 					else
    68 						{
    69 						//subthread has exited. Cancel the timer.
    70 						timer.Cancel();
    71 						User::WaitForRequest(timeout);
    72 						}
    73 					}
    74 				else
    75 					{
    76 					//we have no timer so we'll just have to risk the deadlock
    77 					User::WaitForRequest(iLogonStatus);
    78 					}
    79 				timer.Close();
    80 				}
    81 			}
    82 		//close the handle to the subthread
    83 		iSubThread.Close();
    84 		}
    85 	// close our parent
    86 	RHandleBase::Close(); 
    87 	}
    88 	
    89 void RMMFSubThreadBase::Panic(TMMFSubThreadPanicCode aPanicCode)
    90 	{
    91 	_LIT(KMMFSubThreadPanicCategory, "MMFSubThread");
    92 	iSubThread.Panic(KMMFSubThreadPanicCategory, aPanicCode);
    93 	}
    94 
    95 TInt RMMFSubThreadBase::DoCreateSubThread(const TDesC& aName, TThreadFunction aFunction, TBool aUseNewHeap)
    96 	{
    97 	TInt error = KErrNone;
    98 
    99 	if (aUseNewHeap)
   100 		{
   101 		error = iSubThread.Create(aName, aFunction,
   102 			KDefaultStackSize, KMinHeapSize, KMMFSubThreadMaxHeapSize, 
   103 			NULL, EOwnerThread);
   104 		}
   105 	else
   106 		{
   107 		error = iSubThread.Create(aName, aFunction,
   108 			KDefaultStackSize, &User::Heap(), 
   109 			NULL, EOwnerThread);
   110 		}
   111 
   112 	if (error)
   113 		{
   114 		return error;
   115 		}
   116 	
   117 	TRequestStatus rendezvous;
   118 	iSubThread.Rendezvous(rendezvous);
   119 	
   120 	if (rendezvous != KRequestPending)
   121 		{
   122 		iSubThread.Kill(0);
   123 		}
   124 	else
   125 		{
   126 		iLogonStatus = KRequestPending;
   127 		iSubThread.Logon(iLogonStatus);
   128 		if (iLogonStatus != KRequestPending)
   129 			{
   130 			// Failed to log on
   131 			iSubThread.RendezvousCancel(rendezvous);
   132 			User::WaitForRequest(rendezvous);
   133 			iSubThread.Kill(0);
   134 			iSubThread.Close();
   135 			return iLogonStatus.Int();
   136 			}
   137 		else
   138 			{
   139 			iSubThread.Resume();		
   140 			}
   141 		}
   142 	User::WaitForRequest(rendezvous); // wait for start or death
   143 	
   144 	if (rendezvous != KErrNone)
   145 		{
   146 		iSubThread.LogonCancel(iLogonStatus);
   147 		User::WaitForRequest(iLogonStatus);
   148 		iSubThread.Close();
   149 		return rendezvous.Int();
   150 		}
   151 		
   152 	return KErrNone;	
   153 	}
   154 
   155 CMMFSubThreadShutdown* CMMFSubThreadShutdown::NewL() 
   156 	{
   157 	CMMFSubThreadShutdown* s = new(ELeave) CMMFSubThreadShutdown();
   158 	CleanupStack::PushL(s);
   159 	s->ConstructL();
   160 	CleanupStack::Pop();
   161 	return s;
   162 	}
   163 
   164 CMMFSubThreadShutdown::CMMFSubThreadShutdown() : 
   165 	CTimer(EPriorityLow)
   166 	{
   167 	CActiveScheduler::Add(this);
   168 	}
   169 
   170 void CMMFSubThreadShutdown::ConstructL()
   171 	{
   172 	CTimer::ConstructL();
   173 	}
   174 
   175 void CMMFSubThreadShutdown::Start()
   176 	{
   177 	After(EMMFSubThreadShutdownDelay);
   178 	}
   179 
   180 void CMMFSubThreadShutdown::RunL()
   181 	{
   182 	ShutdownNow();
   183 	}
   184 
   185 void CMMFSubThreadShutdown::ShutdownNow()
   186 	{
   187 	CActiveScheduler::Stop();
   188 	}
   189 
   190 
   191 
   192 
   193 CMMFSubThreadServer::CMMFSubThreadServer(TInt aPriority) :
   194 	CMmfIpcServer(aPriority)
   195 	{
   196 	}
   197 
   198 void CMMFSubThreadServer::ConstructL()
   199 	{
   200 	StartL(RThread().Name());
   201 	iShutdownTimer = CMMFSubThreadShutdown::NewL();
   202 	iShutdownTimer->Start();
   203 	}
   204 
   205 CMMFSubThreadServer::~CMMFSubThreadServer()
   206 	{
   207 	delete iShutdownTimer;
   208 	}
   209 
   210 void CMMFSubThreadServer::SessionCreated()
   211 	{
   212 	//stop the shutdown timer
   213 	iShutdownTimer->Cancel();
   214 	}
   215 
   216 void CMMFSubThreadServer::ShutdownNow()
   217 	{
   218 	iShutdownTimer->ShutdownNow();
   219 	}
   220 
   221 TInt CMMFSubThreadServer::RunError(TInt aError)
   222 	{
   223 	//signal the client
   224 	Message().Complete(aError);
   225 	ReStart();
   226 	return KErrNone;
   227 	}
   228 
   229 
   230 
   231 
   232 
   233 CMMFSubThreadEventReceiver* CMMFSubThreadEventReceiver::NewL(const RMmfIpcMessage& aMessage)
   234 	{
   235 	return new(ELeave) CMMFSubThreadEventReceiver(aMessage);
   236 	}
   237 
   238 CMMFSubThreadEventReceiver::~CMMFSubThreadEventReceiver()
   239 	{
   240 	if (iNeedToCompleteMessage)
   241 		iMessage.Complete(KErrDied);
   242 	}
   243 
   244 void CMMFSubThreadEventReceiver::SendEvent(const TMMFEvent& aEvent)
   245 	{
   246 	TMMFEventPckg eventpckg(aEvent);
   247 	TRAPD(err, MmfMessageUtil::WriteL(iMessage, 0, eventpckg));
   248 	iMessage.Complete(err);
   249 	iNeedToCompleteMessage = EFalse;
   250 	}
   251 
   252 CMMFSubThreadEventReceiver::CMMFSubThreadEventReceiver(const RMmfIpcMessage& aMessage) : 
   253 	iMessage(aMessage)
   254 	{
   255 	iNeedToCompleteMessage = ETrue;
   256 	}
   257 
   258 
   259 
   260 
   261 
   262 
   263 void CMMFSubThreadSession::CreateL(const CMmfIpcServer& aServer)
   264 	{
   265 	CMmfIpcSession::CreateL(aServer);
   266 	iServer = STATIC_CAST(CMMFSubThreadServer*, (CONST_CAST(CMmfIpcServer*, &aServer)));
   267 	iServer->SessionCreated();
   268 	}
   269 
   270 
   271 CMMFSubThreadSession::~CMMFSubThreadSession()
   272 	{
   273 	delete iEventReceiver;
   274 	iEvents.Close();
   275 	}
   276 
   277 
   278 TBool CMMFSubThreadSession::ReceiveEventsL(const RMmfIpcMessage& aMessage)
   279 	{
   280 	if (iEventReceiver)
   281 		User::Leave(KErrAlreadyExists);
   282 	iEventReceiver = CMMFSubThreadEventReceiver::NewL(aMessage);
   283 	//send the next cached event (if any) to the client
   284 	if (iEvents.Count() > 0)
   285 		{
   286 		TMMFEvent& event = iEvents[0];
   287 		iEventReceiver->SendEvent(event);
   288 		delete iEventReceiver;
   289 		iEventReceiver=NULL;
   290 		iEvents.Remove(0);
   291 		}
   292 	return EFalse;
   293 	}
   294 
   295 TBool CMMFSubThreadSession::CancelReceiveEvents()
   296 	{
   297 	delete iEventReceiver;
   298 	iEventReceiver = NULL;
   299 	return ETrue;
   300 	}
   301 
   302 TBool CMMFSubThreadSession::ShutDown()
   303 	{
   304 	iServer->ShutdownNow();
   305 	return ETrue;
   306 	}
   307 
   308 TInt CMMFSubThreadSession::SendEventToClient(const TMMFEvent& aEvent)
   309 	{
   310 	TInt error = KErrNone;
   311 	if (iEventReceiver)
   312 		{
   313 		//send event to client now
   314 		iEventReceiver->SendEvent(aEvent);
   315 		delete iEventReceiver;
   316 		iEventReceiver=NULL;
   317 		error = KErrNone;
   318 		}
   319 	else
   320 		{
   321 		//queue the request for later
   322 		TMMFEvent event(aEvent);
   323 		//if we've exceeded the max number of cached messages, delete the first and append this one to the end
   324 		if (iEvents.Count() >= KMMFSubThreadMaxCachedMessages)
   325 			iEvents.Remove(0);
   326 		error = iEvents.Append(event);
   327 		}
   328 	return error;
   329 	}
   330 
   331