sl@0: /* sl@0: * Copyright (c) 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: * sl@0: */ sl@0: sl@0: sl@0: #include "sysif.h" sl@0: #include "timerserver.h" sl@0: #include "timerhandler.h" sl@0: #include "timer.h" sl@0: #include sl@0: /* Implementation of the CShutDown class sl@0: * Implements a timer sl@0: */ sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CShutdown::ConstructL sl@0: // ------------------------------------------------------------------------------- sl@0: void CShutdown::ConstructL() sl@0: { sl@0: CTimer::ConstructL(); sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CShutdown::Start sl@0: // Starts the timer for the specified time given sl@0: // ------------------------------------------------------------------------------- sl@0: void CShutdown::Start() sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: After(KTimerServerShutdownDelay); sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CShutdown::RunL sl@0: // Initiate server exit when timer expires sl@0: // ------------------------------------------------------------------------------- sl@0: void CShutdown::RunL() sl@0: { sl@0: getTimerHandler()->ResetClientFlag(); sl@0: getTimerHandler()->ResetServerFlag(); sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CTimerServerSession::CreateL sl@0: // 2nd phase construction for sessions. Invoked by the CServer2 framework sl@0: // ------------------------------------------------------------------------------- sl@0: void CTimerServerSession::CreateL() sl@0: { sl@0: Server().AddSession(); sl@0: } sl@0: sl@0: //--------------------------------------------------------------------- sl@0: //CTimerServerSession::~CTimerServerSession sl@0: //Destructor of the server side session sl@0: //--------------------------------------------------------------------- sl@0: CTimerServerSession::~CTimerServerSession() sl@0: { sl@0: Server().DropSession(); sl@0: } sl@0: sl@0: //--------------------------------------------------------------------- sl@0: // Handle a client request. sl@0: // Leaving is handled by CMyServer::ServiceError() which reports sl@0: // the error code to the client sl@0: //--------------------------------------------------------------------- sl@0: void CTimerServerSession::ServiceL(const RMessage2& aMessage) sl@0: { sl@0: switch (aMessage.Function()) sl@0: { sl@0: case EDeleteTimer: sl@0: { sl@0: TInt timerid = aMessage.Int0(); sl@0: TInt ret = Server().RemoveInternal(timerid); sl@0: aMessage.Complete(ret); sl@0: break; sl@0: } sl@0: case ESetTimer: sl@0: { sl@0: TInt timerid = aMessage.Int0(); sl@0: TInt ret = Server().SetTimer(timerid); sl@0: aMessage.Complete(ret); sl@0: break; sl@0: } sl@0: default: sl@0: PanicClient(aMessage,EPanicIllegalFunction); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: CTimerServer& CTimerServerSession::Server() sl@0: { sl@0: return *static_cast(const_cast(CSession2::Server())); sl@0: } sl@0: sl@0: //------------------------------------------------------------------------------ sl@0: // Handle an error from CTimerServerSession::ServiceL() sl@0: // A bad descriptor error implies a badly programmed client, so panic it; sl@0: // otherwise use the default handling (report the error to the client) sl@0: //------------------------------------------------------------------------------ sl@0: sl@0: void CTimerServerSession::ServiceError(const RMessage2& aMessage,TInt aError) sl@0: { sl@0: PanicClient(aMessage,EPanicIllegalFunction); sl@0: CSession2::ServiceError(aMessage,aError); sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------------------- sl@0: // Implementation for CTimerServer class sl@0: // Implements the functionalities of the timer server sl@0: //------------------------------------------------------------------------------------------ sl@0: CTimerServer* CTimerServer::NewLC() sl@0: { sl@0: CTimerServer* self=new(ELeave) CTimerServer; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CTimerServer::ConstructL sl@0: // Second phase construction. Create the shutdown timer object and the semaphore sl@0: // ------------------------------------------------------------------------------- sl@0: void CTimerServer::ConstructL() sl@0: { sl@0: CShutdown* shutdown = new(ELeave) CShutdown; sl@0: CleanupStack::PushL(shutdown); sl@0: shutdown->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: iShutdown = shutdown; sl@0: shutdown = 0; sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CTimerServer::AddToScheduler sl@0: // Add both the server and the shutdown timer objects to the active scheduler sl@0: // ------------------------------------------------------------------------------- sl@0: TInt CTimerServer::AddToScheduler() sl@0: { sl@0: iShutdown->Start(); sl@0: return CServer2::Start(KNullDesC); sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CFileDesTransferServer::RemoveFromScheduler sl@0: // Remove both the server and the shutdown timer objects from the active scheduler sl@0: // ------------------------------------------------------------------------------- sl@0: void CTimerServer::RemoveFromScheduler() sl@0: { sl@0: if (iShutdown->IsAdded()) sl@0: { sl@0: iShutdown->Deque(); sl@0: } sl@0: Deque(); sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CFileDesTransferServer::NewSessionL sl@0: // Create a new client session. sl@0: // ------------------------------------------------------------------------------- sl@0: CSession2* CTimerServer::NewSessionL(const TVersion&, const RMessage2&) const sl@0: { sl@0: return new(ELeave) CTimerServerSession; sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CFileDesTransferServer::AddSession sl@0: // A new session is created. Cancel the shutdown timer if it was running. sl@0: // ------------------------------------------------------------------------------- sl@0: inline void CTimerServer::AddSession() sl@0: { sl@0: if (iShutdown->IsAdded()) sl@0: { sl@0: iShutdown->Deque(); sl@0: } sl@0: ++iSessionCount; sl@0: sl@0: } sl@0: sl@0: // ------------------------------------------------------------------------------- sl@0: // CTimerServer::DropSession sl@0: // The session is destroyed. Stop the ActiveScheduler sl@0: // ------------------------------------------------------------------------------- sl@0: void CTimerServer::DropSession() sl@0: { sl@0: if (--iSessionCount==0) sl@0: { sl@0: CTimerReqHandler* handler = getTimerHandler(); sl@0: handler->ResetClientFlag(); sl@0: if ((handler->iTimers.Count()) == 0 ) sl@0: { sl@0: getTimerHandler()->ResetServerFlag(); sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: //------------------------------------------------------------------------- sl@0: // CTimerServer::NewTimerServerL sl@0: // creates an active scheduler and installs it. sl@0: //------------------------------------------------------------------------- sl@0: TInt CTimerServer::NewTimerServerL() sl@0: { sl@0: CActiveScheduler* pScheduler = new(ELeave) CActiveScheduler; sl@0: CleanupStack::PushL(pScheduler); sl@0: sl@0: CTimerServer* pServer = CTimerServer::NewLC(); sl@0: sl@0: CActiveScheduler::Install(pScheduler); sl@0: sl@0: TInt err = pServer->AddToScheduler(); sl@0: if (err != KErrNone) sl@0: { sl@0: pServer->RemoveFromScheduler(); sl@0: CActiveScheduler::Install(NULL); sl@0: User::Leave(err); sl@0: } sl@0: getTimerHandler()->SetServerHandle(pServer->Server()); sl@0: // pop both pScheduler and pServer from the cleanup stack sl@0: // Start the scheduler sl@0: RThread().Rendezvous(KErrNone); sl@0: CActiveScheduler::Start(); sl@0: CActiveScheduler::Install(NULL); sl@0: sl@0: CleanupStack::PopAndDestroy(2); sl@0: return KErrNone; sl@0: } sl@0: // ------------------------------------------------------------------------------- sl@0: // CFileDesTransferServer::~CFileDesTransferServer sl@0: // ------------------------------------------------------------------------------- sl@0: CTimerServer::~CTimerServer() sl@0: { sl@0: if(iShutdown) sl@0: { sl@0: delete iShutdown; sl@0: iShutdown = 0; sl@0: } sl@0: } sl@0: sl@0: //--------------------------------------------------------------------------------- sl@0: // CTimerServer:: RemoveInternal sl@0: // Removing the timer object from the list sl@0: //--------------------------------------------------------------------------------- sl@0: TInt CTimerServer:: RemoveInternal(const TInt aTimerId) sl@0: { sl@0: TInt lTimerIdx = 0; sl@0: TInt lRet = KErrArgument; sl@0: TBool lSigReq = EFalse; sl@0: CTimerReqHandler* handler = getTimerHandler(); sl@0: handler->iTimersLock.Wait(); sl@0: int lTimerCnt = handler->iTimers.Count(); sl@0: sl@0: for(lTimerIdx = 0; lTimerIdx != lTimerCnt; lTimerIdx++) sl@0: { sl@0: if(handler->iTimers[lTimerIdx]->iTimerId == aTimerId) sl@0: { sl@0: if (handler->iTimers[lTimerIdx]->iSigEvent.sigev_notify == SIGEV_SIGNAL) sl@0: lSigReq = ETrue; sl@0: RHeap* oldHeap = User::SwitchHeap(Backend()->Heap()); sl@0: delete handler->iTimers[lTimerIdx]; sl@0: handler->iTimers.Delete(lTimerIdx); sl@0: User::SwitchHeap(oldHeap); sl@0: lRet = KErrNone; sl@0: break; sl@0: } sl@0: } sl@0: if(lRet == KErrNone && lSigReq) sl@0: { sl@0: RHeap* oldHeap = User::SwitchHeap(Backend()->Heap()); sl@0: handler->iTimers.Compress(); sl@0: User::SwitchHeap(oldHeap); sl@0: #if (defined SYMBIAN_OE_POSIX_SIGNALS && defined SYMBIAN_OE_LIBRT) sl@0: Backend()->DeleteTimer(aTimerId); sl@0: #endif sl@0: } sl@0: handler->iTimersLock.Signal(); sl@0: if(handler->iTimers.Count() == 0) sl@0: { sl@0: DropSession(); sl@0: } sl@0: return lRet; sl@0: } sl@0: sl@0: //thread startup function for SIGEV_THREAD sl@0: static TAny* sThreadFunc(TAny* aArgPtr) sl@0: { sl@0: struct sigevent* lTimerP = reinterpret_cast (aArgPtr); sl@0: lTimerP->sigev_notify_function(lTimerP->sigev_value); sl@0: return NULL; sl@0: } sl@0: sl@0: //--------------------------------------------------------------------------------- sl@0: // CTimerServer:: SetTimer sl@0: // Server sets a new value for the timeout. sl@0: //--------------------------------------------------------------------------------- sl@0: TInt CTimerServer:: SetTimer(const TInt aTimerId) sl@0: { sl@0: CRtTimer* lTimer = getTimerHandler()->FindTimer(aTimerId); sl@0: if(lTimer) sl@0: { sl@0: TTime lSetTime(MAKE_TINT64 (0x00dcddb3 ,0x0f2f8000)); sl@0: if (lTimer->iIsArmed) sl@0: { sl@0: lTimer->iTimer.Cancel(); sl@0: if(lTimer->iIsTimerReset) sl@0: { sl@0: lTimer->iTimer.Deque(); sl@0: lTimer->iIsArmed = EFalse; sl@0: return 0; sl@0: } sl@0: } sl@0: else sl@0: lTimer->iTimer.ConstructL(); sl@0: sl@0: lSetTime+=(TTimeIntervalSeconds) lTimer->iEndTime.tv_sec; sl@0: lSetTime+=(TTimeIntervalMicroSeconds)(lTimer->iEndTime.tv_nsec/1000); sl@0: sl@0: lTimer->iTimer.AddToAS(); sl@0: lTimer->iTimer.At(lSetTime); //Before requesting a timer event, add this active object to AS. sl@0: lTimer->iIsArmed = ETrue; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CLibRtTimer::AddToAS() sl@0: { sl@0: if(!IsAdded()) sl@0: CActiveScheduler::Add(this); sl@0: else return; sl@0: } sl@0: sl@0: void CLibRtTimer::RunL() sl@0: { sl@0: CLocalSystemInterface* lClsiPtr = Backend(); sl@0: sl@0: unsigned long lPeriodicTimeout = (1000000 * GetRtPtr()->iStartTime.it_interval.tv_sec) + sl@0: (GetRtPtr()->iStartTime.it_interval.tv_nsec/1000); sl@0: sl@0: if(lPeriodicTimeout) sl@0: { sl@0: this->HighRes(lPeriodicTimeout); sl@0: } sl@0: else sl@0: { sl@0: GetRtPtr()->iIsArmed = EFalse; sl@0: } sl@0: int val = GetRtPtr()->iSigEvent.sigev_notify; sl@0: //run the handler here sl@0: switch(GetRtPtr()->iSigEvent.sigev_notify) sl@0: { sl@0: #if (defined SYMBIAN_OE_POSIX_SIGNALS && defined SYMBIAN_OE_LIBRT) sl@0: case SIGEV_SIGNAL: sl@0: { sl@0: lClsiPtr->AddTimer(GetRtPtr()->iTimerId); sl@0: sl@0: if(lClsiPtr->IncrementOverrun(GetRtPtr()->iTimerId) == 1) sl@0: { sl@0: lClsiPtr->RaiseTimerSignal(GetRtPtr()->iSigEvent.sigev_signo,\ sl@0: GetRtPtr()->iTimerId); sl@0: } sl@0: } sl@0: break; sl@0: #endif sl@0: case SIGEV_THREAD: sl@0: { sl@0: pthread_t lthread = 0; sl@0: pthread_create( <hread, sl@0: (pthread_attr_t*)GetRtPtr()->iSigEvent.sigev_notify_attributes, sl@0: sThreadFunc, sl@0: &GetRtPtr()->iSigEvent ); sl@0: } sl@0: break; sl@0: sl@0: case SIGEV_NONE: sl@0: default: sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // RMessage::Panic() also completes the message. This is: sl@0: // (a) important for efficient cleanup within the kernel sl@0: // (b) a problem if the message is completed a second time sl@0: // --------------------------------------------------------------------------- sl@0: void PanicClient(const RMessagePtr2& aMessage,TMyPanic aPanic) sl@0: { sl@0: _LIT(KPanic,"TimerServer"); sl@0: aMessage.Panic(KPanic,aPanic); sl@0: } sl@0: