sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // Name        : timerhandler.cpp
sl@0: // Part of     : librt-timer specific cpp file
sl@0: // This is a project specific source file for building the 
sl@0: // timer related functions as part of librt library.
sl@0: // 
sl@0: //
sl@0: 
sl@0: 
sl@0: #include "sysif.h"
sl@0: #include "timerhandler.h"
sl@0: #include "timerclient.h"
sl@0: #include "timerserver.h"
sl@0: #include "timermessage.h"
sl@0: #include "timer.h"
sl@0: #include <pthread.h>
sl@0: 
sl@0: #ifdef __WINSCW__ 
sl@0: #include <pls.h> // For emulator WSD API 
sl@0: const TUid KLibrtUid3 = {0x2001E553}; 
sl@0: #elif defined __X86GCC__
sl@0: CTimerReqHandler gTimerHandler;
sl@0: #endif
sl@0: 
sl@0: 
sl@0: CTimerReqHandler* getTimerHandler()
sl@0: 	{
sl@0: #ifdef __WINSCW__	
sl@0: 	// Access the PLS of this process
sl@0: 	CTimerReqHandler* lTimerHandlerPtr = Pls<CTimerReqHandler>(KLibrtUid3); 
sl@0: 	return lTimerHandlerPtr;  
sl@0: #elif defined __X86GCC__
sl@0: 	return &gTimerHandler;
sl@0: #else
sl@0: 	static CTimerReqHandler sgTimerHandler;
sl@0: 	return &sgTimerHandler;
sl@0: #endif
sl@0: 	}
sl@0: 
sl@0: 
sl@0:  CTimerReqHandler::CTimerReqHandler() : iTimers(CTimerReqHandler::KTimersGran)
sl@0: 	{
sl@0: 	iTimersLock.CreateLocal();
sl@0: 	iServConnectLock.CreateLocal();
sl@0: 	iTimerSemaphore.CreateLocal(0);
sl@0: 	}
sl@0: 
sl@0: 
sl@0:  CTimerReqHandler::~CTimerReqHandler()
sl@0: 	{
sl@0: 	iTimersLock.Close();
sl@0: 	iTimers.ResetAndDestroy();
sl@0: 	iTimerSemaphore.Close();
sl@0: 	iServ.Close();
sl@0: 	iServConnectLock.Close();
sl@0: 	}
sl@0: 
sl@0: //method to create a timer
sl@0: TInt CTimerReqHandler::CreateTimer(TInt& aTimerId, struct sigevent *aSig)
sl@0: 	{
sl@0: 	TInt lRet = KErrNone;
sl@0: 	if(iTimers.Count() >= MAXTIMERLIMIT)
sl@0: 		{
sl@0: 		lRet = KErrWouldBlock;
sl@0: 		}
sl@0: 		
sl@0: 	if(lRet == KErrNone)
sl@0: 		{
sl@0: 		if(aSig != NULL)
sl@0: 			{
sl@0: 			switch(aSig->sigev_notify)	
sl@0: 				{
sl@0: 				case SIGEV_SIGNAL:
sl@0: #if (!defined SYMBIAN_OE_POSIX_SIGNALS || !defined SYMBIAN_OE_LIBRT)
sl@0: 					{
sl@0: 					aTimerId = -1;
sl@0: 					lRet = KErrNotSupported;
sl@0: 					break;	
sl@0: 					}
sl@0: #else			
sl@0: 				
sl@0: 				if(aSig->sigev_signo < 1 || aSig->sigev_signo > SIGRTMAX)
sl@0: 					{
sl@0: 					aTimerId = -1;
sl@0: 					lRet = KErrArgument;						
sl@0: 					}
sl@0: #endif	
sl@0: 					
sl@0: 				case SIGEV_NONE:					
sl@0: 				case SIGEV_THREAD:
sl@0: 					break;
sl@0: 				default:
sl@0: 					aTimerId = -1;	
sl@0: 					lRet = KErrArgument;
sl@0: 					break;
sl@0: 				}
sl@0: 			}
sl@0: 			
sl@0: 		if(lRet == KErrNone)	
sl@0: 			{
sl@0: 			RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
sl@0: 			CRtTimer *lTimer = CRtTimer::New(aSig);
sl@0: 			if(NULL == lTimer)
sl@0: 				{
sl@0: 				aTimerId = -1;	
sl@0: 				lRet = KErrNoMemory;
sl@0: 				User::SwitchHeap(oldHeap);
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				aTimerId = lTimer->iTimerId;				
sl@0: 				iTimersLock.Wait();	
sl@0: 				TRAP(lRet, iTimers.AppendL(lTimer));				
sl@0: 				User::SwitchHeap(oldHeap);
sl@0: 				iTimersLock.Signal();			
sl@0: 				}	
sl@0: 			}
sl@0: 		}
sl@0: 		
sl@0: 	return lRet;	
sl@0: 	}
sl@0: 
sl@0: //method to delete a timer
sl@0: TInt CTimerReqHandler::RemoveTimer(const TInt& aTimerId)
sl@0: 	{
sl@0: 	if(FindTimer(aTimerId)== NULL)
sl@0: 		{
sl@0: 		return KErrArgument;
sl@0: 		}
sl@0: 	TInt lRet = Connect();
sl@0: 	if(lRet == KErrNone)
sl@0: 		{
sl@0: 		session.OnDemandConnect(iServer);
sl@0: 		lRet = session.DeleteTimer(aTimerId);
sl@0: 		}	
sl@0: 	return lRet;		
sl@0: 	}
sl@0: 
sl@0: //method to set a new timeout value for a timer
sl@0: TInt CTimerReqHandler::SetTime(const TInt& aTimerId, TInt aFlag, const struct itimerspec *aIpTime,
sl@0: 			 struct itimerspec *aOpTime) 
sl@0: 	{
sl@0: 	TInt lRet = Connect();
sl@0: 	if(lRet == KErrNone)
sl@0: 		{
sl@0: 		CRtTimer* lTimer = FindTimer(aTimerId);	
sl@0: 		if(lTimer != NULL)
sl@0: 			lRet = lTimer->SetTime(aFlag, aIpTime, aOpTime);	
sl@0: 		else
sl@0: 			lRet = KErrArgument;	
sl@0: 		}
sl@0: 		
sl@0: 	return lRet;	
sl@0: 	}
sl@0: 
sl@0: //method to makesure that the timer server is started only once on demand.
sl@0: TInt CTimerReqHandler::Connect()
sl@0: 	{
sl@0: 	TInt lRet = KErrNone;
sl@0: 	
sl@0: 	iServConnectLock.Wait();
sl@0: 	if(!iIsServStarted)
sl@0: 		{
sl@0: 		lRet = StartTimerServer();
sl@0: 		if(lRet == KErrNone)
sl@0: 			iIsServStarted = ETrue;
sl@0: 		}
sl@0: 	iServConnectLock.Signal();
sl@0: 	return lRet;		
sl@0: 	}
sl@0: 
sl@0: //start up function for the timer server.
sl@0: static TInt sTimerServer(TAny*)
sl@0: 	{
sl@0: 	RHeap *oldHeap = User::SwitchHeap(Backend()->Heap());
sl@0: 	CTrapCleanup* cleanup = CTrapCleanup::New();
sl@0: 	TRAPD(ret, CTimerServer::NewTimerServerL());
sl@0: 	delete cleanup;
sl@0: 	User::SwitchHeap(oldHeap);
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: //method to start the timer server
sl@0: TInt CTimerReqHandler::StartTimerServer()
sl@0: 	{
sl@0: 	TRequestStatus status;
sl@0: 	TInt lRet = iServ.Create(KNullDesC, sTimerServer, 
sl@0: 			KDefaultStackSize, NULL, (TAny*)NULL);
sl@0: 	if(lRet == KErrNone)							
sl@0: 		{
sl@0: 		iServ.SetPriority(EPriorityAbsoluteHigh);// match the signal server priority.
sl@0: 		iServ.Rendezvous(status);
sl@0: 		iServ.Resume(); //get this ready
sl@0: 		User::WaitForRequest(status);
sl@0: 		}
sl@0: 	return lRet;
sl@0: 	}
sl@0: 
sl@0: //method to get the "time to expiration" of a timer
sl@0: TInt CTimerReqHandler::Time(const TInt& aTimerId, struct itimerspec *aTime)
sl@0: 	{
sl@0:  	CRtTimer* lTimer = FindTimer(aTimerId);
sl@0: 	if(lTimer == NULL)
sl@0: 		return KErrArgument;	
sl@0: 	return lTimer->Time(aTime);
sl@0: 	}
sl@0: 
sl@0: //method to get the overruns for a timer
sl@0: TInt CTimerReqHandler::OverrunCount(const TInt& aTimerId, TInt& aOverrunCount)
sl@0: 	{
sl@0: 	CRtTimer* lTimer = FindTimer(aTimerId);
sl@0: 	if(lTimer == NULL)
sl@0: 		return KErrArgument;		
sl@0: 	return lTimer->OverrunCount(aOverrunCount);
sl@0: 	}
sl@0: 
sl@0: //find the timer with the given timer id
sl@0: CRtTimer* CTimerReqHandler::FindTimer(const TInt& aTimerId)
sl@0: 	{
sl@0: 	CRtTimer* lRtTimerP = NULL;
sl@0: 	iTimersLock.Wait();	
sl@0: 	TInt lTimerCount = iTimers.Count();	
sl@0: 	for(TInt lIdx =0; lIdx < lTimerCount; lIdx++)
sl@0: 		{
sl@0: 		if(iTimers[lIdx]->iTimerId == aTimerId)
sl@0: 			{
sl@0: 			lRtTimerP = (iTimers[lIdx]);
sl@0: 			break;	
sl@0: 			}
sl@0: 		}
sl@0: 	iTimersLock.Signal();
sl@0: 	return lRtTimerP;	
sl@0: 	}
sl@0: