1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericopenlibs/posixrealtimeextensions/src/timerserver.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,403 @@
1.4 +/*
1.5 +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +#include "sysif.h"
1.23 +#include "timerserver.h"
1.24 +#include "timerhandler.h"
1.25 +#include "timer.h"
1.26 +#include <pthread.h>
1.27 +/* Implementation of the CShutDown class
1.28 + * Implements a timer
1.29 + */
1.30 +
1.31 +// -------------------------------------------------------------------------------
1.32 +// CShutdown::ConstructL
1.33 +// -------------------------------------------------------------------------------
1.34 +void CShutdown::ConstructL()
1.35 + {
1.36 + CTimer::ConstructL();
1.37 + }
1.38 +
1.39 +// -------------------------------------------------------------------------------
1.40 +// CShutdown::Start
1.41 +// Starts the timer for the specified time given
1.42 +// -------------------------------------------------------------------------------
1.43 +void CShutdown::Start()
1.44 + {
1.45 + CActiveScheduler::Add(this);
1.46 + After(KTimerServerShutdownDelay);
1.47 + }
1.48 +
1.49 +// -------------------------------------------------------------------------------
1.50 +// CShutdown::RunL
1.51 +// Initiate server exit when timer expires
1.52 +// -------------------------------------------------------------------------------
1.53 +void CShutdown::RunL()
1.54 + {
1.55 + getTimerHandler()->ResetClientFlag();
1.56 + getTimerHandler()->ResetServerFlag();
1.57 + CActiveScheduler::Stop();
1.58 + }
1.59 +
1.60 +// -------------------------------------------------------------------------------
1.61 +// CTimerServerSession::CreateL
1.62 +// 2nd phase construction for sessions. Invoked by the CServer2 framework
1.63 +// -------------------------------------------------------------------------------
1.64 +void CTimerServerSession::CreateL()
1.65 + {
1.66 + Server().AddSession();
1.67 + }
1.68 +
1.69 +//---------------------------------------------------------------------
1.70 +//CTimerServerSession::~CTimerServerSession
1.71 +//Destructor of the server side session
1.72 +//---------------------------------------------------------------------
1.73 +CTimerServerSession::~CTimerServerSession()
1.74 + {
1.75 + Server().DropSession();
1.76 + }
1.77 +
1.78 +//---------------------------------------------------------------------
1.79 +// Handle a client request.
1.80 +// Leaving is handled by CMyServer::ServiceError() which reports
1.81 +// the error code to the client
1.82 +//---------------------------------------------------------------------
1.83 +void CTimerServerSession::ServiceL(const RMessage2& aMessage)
1.84 + {
1.85 + switch (aMessage.Function())
1.86 + {
1.87 + case EDeleteTimer:
1.88 + {
1.89 + TInt timerid = aMessage.Int0();
1.90 + TInt ret = Server().RemoveInternal(timerid);
1.91 + aMessage.Complete(ret);
1.92 + break;
1.93 + }
1.94 + case ESetTimer:
1.95 + {
1.96 + TInt timerid = aMessage.Int0();
1.97 + TInt ret = Server().SetTimer(timerid);
1.98 + aMessage.Complete(ret);
1.99 + break;
1.100 + }
1.101 + default:
1.102 + PanicClient(aMessage,EPanicIllegalFunction);
1.103 + break;
1.104 + }
1.105 + }
1.106 +
1.107 +CTimerServer& CTimerServerSession::Server()
1.108 + {
1.109 + return *static_cast<CTimerServer*>(const_cast<CServer2*>(CSession2::Server()));
1.110 + }
1.111 +
1.112 +//------------------------------------------------------------------------------
1.113 +// Handle an error from CTimerServerSession::ServiceL()
1.114 +// A bad descriptor error implies a badly programmed client, so panic it;
1.115 +// otherwise use the default handling (report the error to the client)
1.116 +//------------------------------------------------------------------------------
1.117 +
1.118 +void CTimerServerSession::ServiceError(const RMessage2& aMessage,TInt aError)
1.119 + {
1.120 + PanicClient(aMessage,EPanicIllegalFunction);
1.121 + CSession2::ServiceError(aMessage,aError);
1.122 + }
1.123 +
1.124 +//-----------------------------------------------------------------------------------------
1.125 +// Implementation for CTimerServer class
1.126 +// Implements the functionalities of the timer server
1.127 +//------------------------------------------------------------------------------------------
1.128 +CTimerServer* CTimerServer::NewLC()
1.129 + {
1.130 + CTimerServer* self=new(ELeave) CTimerServer;
1.131 + CleanupStack::PushL(self);
1.132 + self->ConstructL();
1.133 + return self;
1.134 + }
1.135 +
1.136 +// -------------------------------------------------------------------------------
1.137 +// CTimerServer::ConstructL
1.138 +// Second phase construction. Create the shutdown timer object and the semaphore
1.139 +// -------------------------------------------------------------------------------
1.140 +void CTimerServer::ConstructL()
1.141 + {
1.142 + CShutdown* shutdown = new(ELeave) CShutdown;
1.143 + CleanupStack::PushL(shutdown);
1.144 + shutdown->ConstructL();
1.145 + CleanupStack::Pop();
1.146 + iShutdown = shutdown;
1.147 + shutdown = 0;
1.148 + }
1.149 +
1.150 +// -------------------------------------------------------------------------------
1.151 +// CTimerServer::AddToScheduler
1.152 +// Add both the server and the shutdown timer objects to the active scheduler
1.153 +// -------------------------------------------------------------------------------
1.154 +TInt CTimerServer::AddToScheduler()
1.155 + {
1.156 + iShutdown->Start();
1.157 + return CServer2::Start(KNullDesC);
1.158 + }
1.159 +
1.160 +// -------------------------------------------------------------------------------
1.161 +// CFileDesTransferServer::RemoveFromScheduler
1.162 +// Remove both the server and the shutdown timer objects from the active scheduler
1.163 +// -------------------------------------------------------------------------------
1.164 +void CTimerServer::RemoveFromScheduler()
1.165 + {
1.166 + if (iShutdown->IsAdded())
1.167 + {
1.168 + iShutdown->Deque();
1.169 + }
1.170 + Deque();
1.171 + }
1.172 +
1.173 +// -------------------------------------------------------------------------------
1.174 +// CFileDesTransferServer::NewSessionL
1.175 +// Create a new client session.
1.176 +// -------------------------------------------------------------------------------
1.177 +CSession2* CTimerServer::NewSessionL(const TVersion&, const RMessage2&) const
1.178 + {
1.179 + return new(ELeave) CTimerServerSession;
1.180 + }
1.181 +
1.182 +// -------------------------------------------------------------------------------
1.183 +// CFileDesTransferServer::AddSession
1.184 +// A new session is created. Cancel the shutdown timer if it was running.
1.185 +// -------------------------------------------------------------------------------
1.186 +inline void CTimerServer::AddSession()
1.187 + {
1.188 + if (iShutdown->IsAdded())
1.189 + {
1.190 + iShutdown->Deque();
1.191 + }
1.192 + ++iSessionCount;
1.193 +
1.194 + }
1.195 +
1.196 +// -------------------------------------------------------------------------------
1.197 +// CTimerServer::DropSession
1.198 +// The session is destroyed. Stop the ActiveScheduler
1.199 +// -------------------------------------------------------------------------------
1.200 +void CTimerServer::DropSession()
1.201 + {
1.202 + if (--iSessionCount==0)
1.203 + {
1.204 + CTimerReqHandler* handler = getTimerHandler();
1.205 + handler->ResetClientFlag();
1.206 + if ((handler->iTimers.Count()) == 0 )
1.207 + {
1.208 + getTimerHandler()->ResetServerFlag();
1.209 + CActiveScheduler::Stop();
1.210 + }
1.211 + }
1.212 + }
1.213 +
1.214 +//-------------------------------------------------------------------------
1.215 +// CTimerServer::NewTimerServerL
1.216 +// creates an active scheduler and installs it.
1.217 +//-------------------------------------------------------------------------
1.218 +TInt CTimerServer::NewTimerServerL()
1.219 + {
1.220 + CActiveScheduler* pScheduler = new(ELeave) CActiveScheduler;
1.221 + CleanupStack::PushL(pScheduler);
1.222 +
1.223 + CTimerServer* pServer = CTimerServer::NewLC();
1.224 +
1.225 + CActiveScheduler::Install(pScheduler);
1.226 +
1.227 + TInt err = pServer->AddToScheduler();
1.228 + if (err != KErrNone)
1.229 + {
1.230 + pServer->RemoveFromScheduler();
1.231 + CActiveScheduler::Install(NULL);
1.232 + User::Leave(err);
1.233 + }
1.234 + getTimerHandler()->SetServerHandle(pServer->Server());
1.235 + // pop both pScheduler and pServer from the cleanup stack
1.236 + // Start the scheduler
1.237 + RThread().Rendezvous(KErrNone);
1.238 + CActiveScheduler::Start();
1.239 + CActiveScheduler::Install(NULL);
1.240 +
1.241 + CleanupStack::PopAndDestroy(2);
1.242 + return KErrNone;
1.243 + }
1.244 +// -------------------------------------------------------------------------------
1.245 +// CFileDesTransferServer::~CFileDesTransferServer
1.246 +// -------------------------------------------------------------------------------
1.247 +CTimerServer::~CTimerServer()
1.248 + {
1.249 + if(iShutdown)
1.250 + {
1.251 + delete iShutdown;
1.252 + iShutdown = 0;
1.253 + }
1.254 + }
1.255 +
1.256 +//---------------------------------------------------------------------------------
1.257 +// CTimerServer:: RemoveInternal
1.258 +// Removing the timer object from the list
1.259 +//---------------------------------------------------------------------------------
1.260 +TInt CTimerServer:: RemoveInternal(const TInt aTimerId)
1.261 + {
1.262 + TInt lTimerIdx = 0;
1.263 + TInt lRet = KErrArgument;
1.264 + TBool lSigReq = EFalse;
1.265 + CTimerReqHandler* handler = getTimerHandler();
1.266 + handler->iTimersLock.Wait();
1.267 + int lTimerCnt = handler->iTimers.Count();
1.268 +
1.269 + for(lTimerIdx = 0; lTimerIdx != lTimerCnt; lTimerIdx++)
1.270 + {
1.271 + if(handler->iTimers[lTimerIdx]->iTimerId == aTimerId)
1.272 + {
1.273 + if (handler->iTimers[lTimerIdx]->iSigEvent.sigev_notify == SIGEV_SIGNAL)
1.274 + lSigReq = ETrue;
1.275 + RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
1.276 + delete handler->iTimers[lTimerIdx];
1.277 + handler->iTimers.Delete(lTimerIdx);
1.278 + User::SwitchHeap(oldHeap);
1.279 + lRet = KErrNone;
1.280 + break;
1.281 + }
1.282 + }
1.283 + if(lRet == KErrNone && lSigReq)
1.284 + {
1.285 + RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
1.286 + handler->iTimers.Compress();
1.287 + User::SwitchHeap(oldHeap);
1.288 + #if (defined SYMBIAN_OE_POSIX_SIGNALS && defined SYMBIAN_OE_LIBRT)
1.289 + Backend()->DeleteTimer(aTimerId);
1.290 + #endif
1.291 + }
1.292 + handler->iTimersLock.Signal();
1.293 + if(handler->iTimers.Count() == 0)
1.294 + {
1.295 + DropSession();
1.296 + }
1.297 + return lRet;
1.298 + }
1.299 +
1.300 +//thread startup function for SIGEV_THREAD
1.301 +static TAny* sThreadFunc(TAny* aArgPtr)
1.302 + {
1.303 + struct sigevent* lTimerP = reinterpret_cast<struct sigevent *> (aArgPtr);
1.304 + lTimerP->sigev_notify_function(lTimerP->sigev_value);
1.305 + return NULL;
1.306 + }
1.307 +
1.308 +//---------------------------------------------------------------------------------
1.309 +// CTimerServer:: SetTimer
1.310 +// Server sets a new value for the timeout.
1.311 +//---------------------------------------------------------------------------------
1.312 +TInt CTimerServer:: SetTimer(const TInt aTimerId)
1.313 + {
1.314 + CRtTimer* lTimer = getTimerHandler()->FindTimer(aTimerId);
1.315 + if(lTimer)
1.316 + {
1.317 + TTime lSetTime(MAKE_TINT64 (0x00dcddb3 ,0x0f2f8000));
1.318 + if (lTimer->iIsArmed)
1.319 + {
1.320 + lTimer->iTimer.Cancel();
1.321 + if(lTimer->iIsTimerReset)
1.322 + {
1.323 + lTimer->iTimer.Deque();
1.324 + lTimer->iIsArmed = EFalse;
1.325 + return 0;
1.326 + }
1.327 + }
1.328 + else
1.329 + lTimer->iTimer.ConstructL();
1.330 +
1.331 + lSetTime+=(TTimeIntervalSeconds) lTimer->iEndTime.tv_sec;
1.332 + lSetTime+=(TTimeIntervalMicroSeconds)(lTimer->iEndTime.tv_nsec/1000);
1.333 +
1.334 + lTimer->iTimer.AddToAS();
1.335 + lTimer->iTimer.At(lSetTime); //Before requesting a timer event, add this active object to AS.
1.336 + lTimer->iIsArmed = ETrue;
1.337 + }
1.338 + return KErrNone;
1.339 + }
1.340 +
1.341 +void CLibRtTimer::AddToAS()
1.342 + {
1.343 + if(!IsAdded())
1.344 + CActiveScheduler::Add(this);
1.345 + else return;
1.346 + }
1.347 +
1.348 +void CLibRtTimer::RunL()
1.349 + {
1.350 + CLocalSystemInterface* lClsiPtr = Backend();
1.351 +
1.352 + unsigned long lPeriodicTimeout = (1000000 * GetRtPtr()->iStartTime.it_interval.tv_sec) +
1.353 + (GetRtPtr()->iStartTime.it_interval.tv_nsec/1000);
1.354 +
1.355 + if(lPeriodicTimeout)
1.356 + {
1.357 + this->HighRes(lPeriodicTimeout);
1.358 + }
1.359 + else
1.360 + {
1.361 + GetRtPtr()->iIsArmed = EFalse;
1.362 + }
1.363 + int val = GetRtPtr()->iSigEvent.sigev_notify;
1.364 + //run the handler here
1.365 + switch(GetRtPtr()->iSigEvent.sigev_notify)
1.366 + {
1.367 + #if (defined SYMBIAN_OE_POSIX_SIGNALS && defined SYMBIAN_OE_LIBRT)
1.368 + case SIGEV_SIGNAL:
1.369 + {
1.370 + lClsiPtr->AddTimer(GetRtPtr()->iTimerId);
1.371 +
1.372 + if(lClsiPtr->IncrementOverrun(GetRtPtr()->iTimerId) == 1)
1.373 + {
1.374 + lClsiPtr->RaiseTimerSignal(GetRtPtr()->iSigEvent.sigev_signo,\
1.375 + GetRtPtr()->iTimerId);
1.376 + }
1.377 + }
1.378 + break;
1.379 + #endif
1.380 + case SIGEV_THREAD:
1.381 + {
1.382 + pthread_t lthread = 0;
1.383 + pthread_create( <hread,
1.384 + (pthread_attr_t*)GetRtPtr()->iSigEvent.sigev_notify_attributes,
1.385 + sThreadFunc,
1.386 + &GetRtPtr()->iSigEvent );
1.387 + }
1.388 + break;
1.389 +
1.390 + case SIGEV_NONE:
1.391 + default:
1.392 + break;
1.393 + }
1.394 + }
1.395 +
1.396 +// ---------------------------------------------------------------------------
1.397 +// RMessage::Panic() also completes the message. This is:
1.398 +// (a) important for efficient cleanup within the kernel
1.399 +// (b) a problem if the message is completed a second time
1.400 +// ---------------------------------------------------------------------------
1.401 +void PanicClient(const RMessagePtr2& aMessage,TMyPanic aPanic)
1.402 + {
1.403 + _LIT(KPanic,"TimerServer");
1.404 + aMessage.Panic(KPanic,aPanic);
1.405 + }
1.406 +