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