os/ossrv/genericopenlibs/posixrealtimeextensions/src/timerserver.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description:
    15 *
    16 */
    17 
    18 
    19 #include "sysif.h"
    20 #include "timerserver.h"
    21 #include "timerhandler.h"
    22 #include "timer.h"
    23 #include <pthread.h>
    24 /* Implementation of the CShutDown class
    25  * Implements a timer
    26  */
    27 
    28 // -------------------------------------------------------------------------------
    29 // CShutdown::ConstructL
    30 // -------------------------------------------------------------------------------
    31 void CShutdown::ConstructL()
    32 	{
    33 	CTimer::ConstructL();
    34 	}
    35 
    36 // -------------------------------------------------------------------------------
    37 // CShutdown::Start
    38 // Starts the timer for the specified time given
    39 // -------------------------------------------------------------------------------
    40 void CShutdown::Start()
    41 	{
    42 	CActiveScheduler::Add(this);
    43 	After(KTimerServerShutdownDelay);
    44 	}
    45 
    46 // -------------------------------------------------------------------------------
    47 // CShutdown::RunL
    48 // Initiate server exit when timer expires
    49 // -------------------------------------------------------------------------------
    50 void CShutdown::RunL()
    51     {
    52     getTimerHandler()->ResetClientFlag();
    53     getTimerHandler()->ResetServerFlag();
    54     CActiveScheduler::Stop();
    55     }
    56 
    57 // -------------------------------------------------------------------------------
    58 // CTimerServerSession::CreateL
    59 // 2nd phase construction for sessions. Invoked by the CServer2 framework
    60 // -------------------------------------------------------------------------------
    61 void CTimerServerSession::CreateL()
    62     {
    63     Server().AddSession();
    64     }
    65 
    66 //---------------------------------------------------------------------
    67 //CTimerServerSession::~CTimerServerSession
    68 //Destructor of the server side session
    69 //---------------------------------------------------------------------
    70 CTimerServerSession::~CTimerServerSession()
    71 	{
    72 	Server().DropSession();
    73 	}
    74 
    75 //---------------------------------------------------------------------
    76 // Handle a client request.
    77 // Leaving is handled by CMyServer::ServiceError() which reports
    78 // the error code to the client
    79 //---------------------------------------------------------------------
    80 void CTimerServerSession::ServiceL(const RMessage2& aMessage)
    81 	{
    82 	switch (aMessage.Function())
    83 		{
    84 	case EDeleteTimer:
    85 		{
    86 		TInt timerid = aMessage.Int0();
    87 		TInt ret = Server().RemoveInternal(timerid);
    88 		aMessage.Complete(ret);
    89 		break;
    90 		}
    91 	case ESetTimer:
    92 			{
    93 			TInt timerid = aMessage.Int0();
    94 			TInt ret = Server().SetTimer(timerid);
    95 			aMessage.Complete(ret);
    96 			break;
    97 			}
    98 	default:
    99 		PanicClient(aMessage,EPanicIllegalFunction);
   100 		break;
   101 		}
   102 	}
   103 
   104 CTimerServer& CTimerServerSession::Server()
   105 	{
   106 	return *static_cast<CTimerServer*>(const_cast<CServer2*>(CSession2::Server()));
   107 	}
   108 
   109 //------------------------------------------------------------------------------
   110 // Handle an error from CTimerServerSession::ServiceL()
   111 // A bad descriptor error implies a badly programmed client, so panic it;
   112 // otherwise use the default handling (report the error to the client)
   113 //------------------------------------------------------------------------------
   114 
   115 void CTimerServerSession::ServiceError(const RMessage2& aMessage,TInt aError)
   116 	{
   117 	PanicClient(aMessage,EPanicIllegalFunction);
   118 	CSession2::ServiceError(aMessage,aError);
   119 	}
   120 
   121 //-----------------------------------------------------------------------------------------
   122 // Implementation for CTimerServer class
   123 // Implements the functionalities of the timer server
   124 //------------------------------------------------------------------------------------------
   125 CTimerServer* CTimerServer::NewLC()
   126 	{
   127 	CTimerServer* self=new(ELeave) CTimerServer;
   128 	CleanupStack::PushL(self);
   129 	self->ConstructL();
   130 	return self;
   131 	}
   132 
   133 // -------------------------------------------------------------------------------
   134 // CTimerServer::ConstructL
   135 // Second phase construction. Create the shutdown timer object and the semaphore
   136 // -------------------------------------------------------------------------------
   137 void CTimerServer::ConstructL()
   138     {
   139     CShutdown* shutdown = new(ELeave) CShutdown;
   140     CleanupStack::PushL(shutdown);
   141     shutdown->ConstructL();
   142 	CleanupStack::Pop();
   143 	iShutdown = shutdown;
   144 	shutdown = 0;
   145     }
   146 
   147 // -------------------------------------------------------------------------------
   148 // CTimerServer::AddToScheduler
   149 // Add both the server and the shutdown timer objects to the active scheduler
   150 // -------------------------------------------------------------------------------
   151 TInt CTimerServer::AddToScheduler()
   152 	{
   153 	iShutdown->Start();
   154 	return CServer2::Start(KNullDesC);
   155 	}
   156 
   157 // -------------------------------------------------------------------------------
   158 // CFileDesTransferServer::RemoveFromScheduler
   159 // Remove both the server and the shutdown timer objects from the active scheduler
   160 // -------------------------------------------------------------------------------
   161 void CTimerServer::RemoveFromScheduler()
   162 	{
   163 	if (iShutdown->IsAdded())
   164 		{
   165 		iShutdown->Deque();
   166 		}
   167 	Deque();
   168 	}
   169 
   170 // -------------------------------------------------------------------------------
   171 // CFileDesTransferServer::NewSessionL
   172 // Create a new client session.
   173 // -------------------------------------------------------------------------------
   174 CSession2* CTimerServer::NewSessionL(const TVersion&, const RMessage2&) const
   175     {
   176     return new(ELeave) CTimerServerSession;
   177     }
   178 
   179 // -------------------------------------------------------------------------------
   180 // CFileDesTransferServer::AddSession
   181 // A new session is created. Cancel the shutdown timer if it was running.
   182 // -------------------------------------------------------------------------------
   183 inline void CTimerServer::AddSession()
   184     {
   185     if (iShutdown->IsAdded())
   186         {
   187         iShutdown->Deque();
   188         }
   189     ++iSessionCount;
   190     
   191     }
   192 
   193 // -------------------------------------------------------------------------------
   194 // CTimerServer::DropSession
   195 // The session is destroyed. Stop the ActiveScheduler
   196 // -------------------------------------------------------------------------------
   197 void CTimerServer::DropSession()
   198     {
   199     if (--iSessionCount==0)
   200     	{
   201     	CTimerReqHandler* handler = getTimerHandler();
   202     	handler->ResetClientFlag();
   203     	if ((handler->iTimers.Count()) == 0 )
   204     		{
   205     	    getTimerHandler()->ResetServerFlag();
   206     	    CActiveScheduler::Stop();
   207     	    }
   208     	}
   209     }
   210 
   211 //-------------------------------------------------------------------------
   212 // CTimerServer::NewTimerServerL
   213 // creates an active scheduler and installs it.
   214 //-------------------------------------------------------------------------
   215 TInt CTimerServer::NewTimerServerL()
   216 	{
   217 	CActiveScheduler* pScheduler = new(ELeave) CActiveScheduler;
   218 	CleanupStack::PushL(pScheduler);
   219 	
   220 	CTimerServer* pServer = CTimerServer::NewLC();
   221 	
   222 	CActiveScheduler::Install(pScheduler);
   223 
   224 	TInt err = pServer->AddToScheduler();
   225     	if (err != KErrNone)
   226     		{
   227     		pServer->RemoveFromScheduler();
   228     		CActiveScheduler::Install(NULL);
   229     		User::Leave(err);
   230     		}
   231     	getTimerHandler()->SetServerHandle(pServer->Server());
   232 	// pop both pScheduler and pServer from the cleanup stack
   233     	// Start the scheduler
   234     	RThread().Rendezvous(KErrNone);
   235     	CActiveScheduler::Start();
   236 	CActiveScheduler::Install(NULL);
   237 	
   238 	CleanupStack::PopAndDestroy(2);
   239 	return KErrNone;
   240 	}
   241 // -------------------------------------------------------------------------------
   242 // CFileDesTransferServer::~CFileDesTransferServer
   243 // -------------------------------------------------------------------------------
   244 CTimerServer::~CTimerServer()
   245 	{
   246 	if(iShutdown)
   247 		{
   248 		delete iShutdown;
   249 		iShutdown = 0;
   250 		}
   251 	}
   252 
   253 //---------------------------------------------------------------------------------
   254 // CTimerServer:: RemoveInternal
   255 // Removing the timer object from the list 
   256 //---------------------------------------------------------------------------------
   257 TInt CTimerServer:: RemoveInternal(const TInt aTimerId)
   258 	{
   259 	TInt lTimerIdx = 0;
   260 	TInt lRet = KErrArgument;
   261 	TBool lSigReq = EFalse;
   262 	CTimerReqHandler* handler = getTimerHandler();
   263 	handler->iTimersLock.Wait();
   264 	int lTimerCnt = handler->iTimers.Count();
   265 
   266 	for(lTimerIdx = 0; lTimerIdx != lTimerCnt; lTimerIdx++)
   267 		{
   268 		if(handler->iTimers[lTimerIdx]->iTimerId == aTimerId)
   269 			{
   270 			if (handler->iTimers[lTimerIdx]->iSigEvent.sigev_notify == SIGEV_SIGNAL)
   271 				lSigReq = ETrue;
   272 			RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
   273 			delete handler->iTimers[lTimerIdx];
   274 			handler->iTimers.Delete(lTimerIdx);
   275 			User::SwitchHeap(oldHeap);
   276 			lRet = KErrNone;
   277 			break;
   278 			}
   279 		}	
   280 	if(lRet == KErrNone && lSigReq)
   281 		{
   282 		RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
   283 		handler->iTimers.Compress();	
   284 		User::SwitchHeap(oldHeap);
   285 		#if (defined SYMBIAN_OE_POSIX_SIGNALS && defined SYMBIAN_OE_LIBRT)		
   286 		Backend()->DeleteTimer(aTimerId);
   287 		#endif		
   288 		}
   289 	handler->iTimersLock.Signal();
   290 	if(handler->iTimers.Count() == 0)
   291 		{
   292 		DropSession();
   293 		}
   294 	return lRet;
   295 	}
   296 
   297 //thread startup function for SIGEV_THREAD
   298 static TAny* sThreadFunc(TAny* aArgPtr)
   299 	{
   300 	struct sigevent* lTimerP = reinterpret_cast<struct sigevent *> (aArgPtr);
   301 	lTimerP->sigev_notify_function(lTimerP->sigev_value);	
   302 	return NULL;
   303 	}
   304 
   305 //---------------------------------------------------------------------------------
   306 // CTimerServer:: SetTimer
   307 // Server sets a new value for the timeout.
   308 //---------------------------------------------------------------------------------
   309 TInt CTimerServer:: SetTimer(const TInt aTimerId)
   310 	{
   311 	CRtTimer* lTimer = getTimerHandler()->FindTimer(aTimerId);
   312 	if(lTimer)
   313 		{
   314 		TTime lSetTime(MAKE_TINT64 (0x00dcddb3 ,0x0f2f8000)); 
   315 		if (lTimer->iIsArmed)
   316 			{
   317 			lTimer->iTimer.Cancel();	
   318 			if(lTimer->iIsTimerReset)
   319 				{
   320 				lTimer->iTimer.Deque();
   321 				lTimer->iIsArmed = EFalse;
   322 				return 0;
   323 				}
   324 			}
   325 		else
   326 			lTimer->iTimer.ConstructL();
   327 		
   328 		lSetTime+=(TTimeIntervalSeconds) lTimer->iEndTime.tv_sec;
   329 		lSetTime+=(TTimeIntervalMicroSeconds)(lTimer->iEndTime.tv_nsec/1000);
   330 		
   331 		lTimer->iTimer.AddToAS();
   332 		lTimer->iTimer.At(lSetTime);	//Before requesting a timer event, add this active object to AS.					
   333 		lTimer->iIsArmed = ETrue;										
   334 		}		
   335 	return KErrNone;
   336 	}
   337 
   338 void CLibRtTimer::AddToAS()
   339 	{
   340 	if(!IsAdded())
   341 		CActiveScheduler::Add(this);
   342 	else return;
   343 	}
   344 
   345 void CLibRtTimer::RunL()
   346 	{
   347 	CLocalSystemInterface* lClsiPtr = Backend();
   348 		
   349 		unsigned long lPeriodicTimeout = (1000000 * GetRtPtr()->iStartTime.it_interval.tv_sec) +
   350 			  (GetRtPtr()->iStartTime.it_interval.tv_nsec/1000);
   351 			  
   352 		if(lPeriodicTimeout)
   353 			{
   354 			this->HighRes(lPeriodicTimeout);
   355 			}
   356 		else
   357 			{
   358 			GetRtPtr()->iIsArmed = EFalse;
   359 			}						
   360 		int val = GetRtPtr()->iSigEvent.sigev_notify;
   361 		//run the handler here	
   362 		switch(GetRtPtr()->iSigEvent.sigev_notify)
   363 			{
   364 			#if (defined SYMBIAN_OE_POSIX_SIGNALS && defined SYMBIAN_OE_LIBRT)
   365 			case SIGEV_SIGNAL:
   366 				{
   367 				lClsiPtr->AddTimer(GetRtPtr()->iTimerId);	
   368 				
   369 				if(lClsiPtr->IncrementOverrun(GetRtPtr()->iTimerId) == 1)
   370 					{
   371 					lClsiPtr->RaiseTimerSignal(GetRtPtr()->iSigEvent.sigev_signo,\
   372 							GetRtPtr()->iTimerId);
   373 					}
   374 				}
   375 				break;
   376 			#endif
   377 			case SIGEV_THREAD:
   378 				{
   379 				pthread_t lthread = 0;
   380 				pthread_create(	&lthread,
   381 								(pthread_attr_t*)GetRtPtr()->iSigEvent.sigev_notify_attributes,
   382 								sThreadFunc,
   383 								&GetRtPtr()->iSigEvent );
   384 				}
   385 				break;
   386 
   387 			case SIGEV_NONE:
   388 			default:
   389 				break;						
   390 			}
   391 	}
   392 
   393 // --------------------------------------------------------------------------- 
   394 // RMessage::Panic() also completes the message. This is:
   395 // (a) important for efficient cleanup within the kernel
   396 // (b) a problem if the message is completed a second time
   397 // ---------------------------------------------------------------------------
   398 void PanicClient(const RMessagePtr2& aMessage,TMyPanic aPanic)
   399 	{
   400 	_LIT(KPanic,"TimerServer");
   401 	aMessage.Panic(KPanic,aPanic);
   402 	}
   403