14035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin/* Copyright (c) 2015, The Linux Foundation. All rights reserved. 24035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * 34035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * Redistribution and use in source and binary forms, with or without 44035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * modification, are permitted provided that the following conditions are 54035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * met: 64035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * * Redistributions of source code must retain the above copyright 74035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * notice, this list of conditions and the following disclaimer. 84035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * * Redistributions in binary form must reproduce the above 94035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * copyright notice, this list of conditions and the following 104035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * disclaimer in the documentation and/or other materials provided 114035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * with the distribution. 124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * * Neither the name of The Linux Foundation, nor the names of its 134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * contributors may be used to endorse or promote products derived 144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * from this software without specific prior written permission. 154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * 164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin * 284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin */ 294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <time.h> 314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <errno.h> 32a2364e24811e3887505d660f4c789334edd31768Steven Moreland#include <unistd.h> 33a2364e24811e3887505d660f4c789334edd31768Steven Moreland#include <stdio.h> 34a2364e24811e3887505d660f4c789334edd31768Steven Moreland#include <stdlib.h> 354035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <loc_timer.h> 364035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <sys/timerfd.h> 374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <sys/epoll.h> 384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <LocTimer.h> 394035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <LocHeap.h> 404035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <LocThread.h> 414035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <LocSharedLock.h> 424035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#include <MsgTask.h> 434035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 444035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#ifdef __HOST_UNIT_TEST__ 454035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#define EPOLLWAKEUP 0 464035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#define CLOCK_BOOTTIME CLOCK_MONOTONIC 474035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#define CLOCK_BOOTTIME_ALARM CLOCK_MONOTONIC 484035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#endif 494035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 504035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin/* 514035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinThere are implementations of 5 classes in this file: 524035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimer, LocTimerDelegate, LocTimerContainer, LocTimerPollTask, LocTimerWrapper 534035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 544035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimer - client front end, interface for client to start / stop timers, also 554035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin to provide a callback. 564035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerDelegate - an internal timer entity, which also is a LocRankable obj. 574035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin Its life cycle is different than that of LocTimer. It gets 584035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin created when LocTimer::start() is called, and gets deleted 594035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin when it expires or clients calls the hosting LocTimer obj's 604035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin stop() method. When a LocTimerDelegate obj is ticking, it 614035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin stays in the corresponding LocTimerContainer. When expired 624035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin or stopped, the obj is removed from the container. Since it 634035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin is also a LocRankable obj, and LocTimerContainer also is a 644035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin heap, its ranks() implementation decides where it is placed 654035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin in the heap. 664035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerContainer - core of the timer service. It is a container (derived from 674035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocHeap) for LocTimerDelegate (implements LocRankable) objs. 684035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin There are 2 of such containers, one for sw timers (or Linux 694035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timers) one for hw timers (or Linux alarms). It adds one of 704035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin each (those that expire the soonest) to kernel via services 714035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin provided by LocTimerPollTask. All the heap management on the 724035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate objs are done in the MsgTask context, such 734035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin that synchronization is ensured. 744035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerPollTask - is a class that wraps timerfd and epoll POXIS APIs. It also 754035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin both implements LocRunnalbe with epoll_wait() in the run() 764035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin method. It is also a LocThread client, so as to loop the run 774035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin method. 784035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerWrapper - a LocTimer client itself, to implement the existing C API with 794035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin APIs, loc_timer_start() and loc_timer_stop(). 804035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 814035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin*/ 824035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 834035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinclass LocTimerPollTask; 844035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 854035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// This is a multi-functaional class that: 864035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// * extends the LocHeap class for the detection of head update upon add / remove 874035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// events. When that happens, soonest time out changes, so timerfd needs update. 884035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// * contains the timers, and add / remove them into the heap 894035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// * provides and maps 2 of such containers, one for timers (or mSwTimers), one 904035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// for alarms (or mHwTimers); 914035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// * provides a polling thread; 924035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// * provides a MsgTask thread for synchronized add / remove / timer client callback. 934035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinclass LocTimerContainer : public LocHeap { 944035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // mutex to synchronize getters of static members 954035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static pthread_mutex_t mMutex; 964035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // Container of timers 974035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static LocTimerContainer* mSwTimers; 984035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // Container of alarms 994035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static LocTimerContainer* mHwTimers; 1004035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // Msg task to provider msg Q, sender and reader. 1014035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static MsgTask* mMsgTask; 1024035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // Poll task to provide epoll call and threading to poll. 1034035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static LocTimerPollTask* mPollTask; 1044035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // timer / alarm fd 1054035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int mDevFd; 1064035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // ctor 1074035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer(bool wakeOnExpire); 1084035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // dtor 1094035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin ~LocTimerContainer(); 1104035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static MsgTask* getMsgTaskLocked(); 1114035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static LocTimerPollTask* getPollTaskLocked(); 1124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // extend LocHeap and pop if the top outRanks input 1134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* popIfOutRanks(LocTimerDelegate& timer); 1144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // update the timer POSIX calls with updated soonest timer spec 1154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void updateSoonestTime(LocTimerDelegate* priorTop); 1164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 1174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinpublic: 1184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // factory method to control the creation of mSwTimers / mHwTimers 1194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static LocTimerContainer* get(bool wakeOnExpire); 1204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 1214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* getSoonestTimer(); 1224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int getTimerFd(); 1234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // add a timer / alarm obj into the container 1244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void add(LocTimerDelegate& timer); 1254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // remove a timer / alarm obj from the container 1264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void remove(LocTimerDelegate& timer); 1274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // handling of timer / alarm expiration 1284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void expire(); 1294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin}; 1304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 1314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// This class implements the polling thread that epolls imer / alarm fds. 1324035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// The LocRunnable::run() contains the actual polling. The other methods 1334035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// will be run in the caller's thread context to add / remove timer / alarm 1344035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// fds the kernel, while the polling is blocked on epoll_wait() call. 1354035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// Since the design is that we have maximally 2 polls, one for all the 1364035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// timers; one for all the alarms, we will poll at most on 2 fds. But it 1374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// is possile that all we have are only timers or alarms at one time, so we 1384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// allow dynamically add / remove fds we poll on. The design decision of 1394035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// having 1 fd per container of timer / alarm is such that, we may not need 1404035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// to make a system call each time a timer / alarm is added / removed, unless 1414035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// that changes the "soonest" time out of that of all the timers / alarms. 1424035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinclass LocTimerPollTask : public LocRunnable { 1434035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // the epoll fd 1444035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin const int mFd; 1454035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // the thread that calls run() method 1464035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocThread* mThread; 1474035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin friend class LocThreadDelegate; 1484035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // dtor 1494035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin ~LocTimerPollTask(); 1504035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinpublic: 1514035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // ctor 1524035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerPollTask(); 1534035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // this obj will be deleted once thread is deleted 1544035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void destroy(); 1554035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // add a container of timers. Each contain has a unique device fd, i.e. 1564035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // either timer or alarm fd, and a heap of timers / alarms. It is expected 1574035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // that container would have written to the device fd with the soonest 1584035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // time out value in the heap at the time of calling this method. So all 1594035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // this method does is to add the fd of the input container to the poll 1604035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // and also add the pointer of the container to the event data ptr, such 1614035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // when poll_wait wakes up on events, we know who is the owner of the fd. 1624035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void addPoll(LocTimerContainer& timerContainer); 1634035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // remove a fd that is assciated with a container. The expectation is that 1644035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // the atual timer would have been removed from the container. 1654035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void removePoll(LocTimerContainer& timerContainer); 1664035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // The polling thread context will call this method. This is where 1674035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // epoll_wait() is blocking and waiting for events.. 1684035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin virtual bool run(); 1694035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin}; 1704035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 1714035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// Internal class of timer obj. It gets born when client calls LocTimer::start(); 1724035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// and gets deleted when client calls LocTimer::stop() or when the it expire()'s. 1734035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// This class implements LocRankable::ranks() so that when an obj is added into 1744035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// the container (of LocHeap), it gets placed in sorted order. 1754035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinclass LocTimerDelegate : public LocRankable { 1764035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin friend class LocTimerContainer; 1774035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin friend class LocTimer; 1784035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimer* mClient; 1794035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocSharedLock* mLock; 1804035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct timespec mFutureTime; 1814035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer* mContainer; 1824035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // not a complete obj, just ctor for LocRankable comparisons 1834035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline LocTimerDelegate(struct timespec& delay) 1844035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin : mClient(NULL), mLock(NULL), mFutureTime(delay), mContainer(NULL) {} 1854035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline ~LocTimerDelegate() { if (mLock) { mLock->drop(); mLock = NULL; } } 1864035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinpublic: 1874035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate(LocTimer& client, struct timespec& futureTime, bool wakeOnExpire); 1884035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void destroyLocked(); 1894035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // LocRankable virtual method 1904035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin virtual int ranks(LocRankable& rankable); 1914035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void expire(); 1924035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline struct timespec getFutureTime() { return mFutureTime; } 1934035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin}; 1944035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 1954035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin/***************************LocTimerContainer methods***************************/ 1964035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 1974035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// Most of these static recources are created on demand. They however are never 1984035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// destoyed. The theory is that there are processes that link to this util lib 1994035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// but never use timer, then these resources would never need to be created. 2004035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// For those processes that do use timer, it will likely also need to every 2014035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// once in a while. It might be cheaper keeping them around. 2024035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinpthread_mutex_t LocTimerContainer::mMutex = PTHREAD_MUTEX_INITIALIZER; 2034035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerContainer* LocTimerContainer::mSwTimers = NULL; 2044035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerContainer* LocTimerContainer::mHwTimers = NULL; 2054035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinMsgTask* LocTimerContainer::mMsgTask = NULL; 2064035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerPollTask* LocTimerContainer::mPollTask = NULL; 2074035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2084035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// ctor - initialize timer heaps 2094035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// A container for swTimer (timer) is created, when wakeOnExpire is true; or 2104035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// HwTimer (alarm), when wakeOnExpire is false. 2114035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerContainer::LocTimerContainer(bool wakeOnExpire) : 2124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mDevFd(timerfd_create(wakeOnExpire ? CLOCK_BOOTTIME_ALARM : CLOCK_BOOTTIME, 0)) { 2134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if ((-1 == mDevFd) && (errno == EINVAL)) { 2154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LOC_LOGW("%s: timerfd_create failure, fallback to CLOCK_MONOTONIC - %s", 2164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin __FUNCTION__, strerror(errno)); 2174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mDevFd = timerfd_create(CLOCK_MONOTONIC, 0); 2184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 2194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (-1 != mDevFd) { 2214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // ensure we have the necessary resources created 2224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer::getPollTaskLocked(); 2234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer::getMsgTaskLocked(); 2244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else { 2254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LOC_LOGE("%s: timerfd_create failure - %s", __FUNCTION__, strerror(errno)); 2264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 2274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 2284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// dtor 2304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// we do not ever destroy the static resources. 2314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 2324035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerContainer::~LocTimerContainer() { 2334035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin close(mDevFd); 2344035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 2354035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2364035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerContainer* LocTimerContainer::get(bool wakeOnExpire) { 2374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // get the reference of either mHwTimer or mSwTimers per wakeOnExpire 2384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer*& container = wakeOnExpire ? mHwTimers : mSwTimers; 2394035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // it is cheap to check pointer first than locking mutext unconditionally 2404035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!container) { 2414035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin pthread_mutex_lock(&mMutex); 2424035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // let's check one more time to be safe 2434035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!container) { 2444035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin container = new LocTimerContainer(wakeOnExpire); 2454035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // timerfd_create failure 2464035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (-1 == container->getTimerFd()) { 2474035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete container; 2484035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin container = NULL; 2494035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 2504035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 2514035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin pthread_mutex_unlock(&mMutex); 2524035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 2534035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return container; 2544035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 2554035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2564035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinMsgTask* LocTimerContainer::getMsgTaskLocked() { 2574035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // it is cheap to check pointer first than locking mutext unconditionally 2584035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!mMsgTask) { 2594035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mMsgTask = new MsgTask("LocTimerMsgTask", false); 2604035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 2614035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return mMsgTask; 2624035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 2634035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2644035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerPollTask* LocTimerContainer::getPollTaskLocked() { 2654035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // it is cheap to check pointer first than locking mutext unconditionally 2664035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!mPollTask) { 2674035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mPollTask = new LocTimerPollTask(); 2684035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 2694035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return mPollTask; 2704035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 2714035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2724035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 2734035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerDelegate* LocTimerContainer::getSoonestTimer() { 2744035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return (LocTimerDelegate*)(peek()); 2754035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 2764035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2774035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 2784035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinint LocTimerContainer::getTimerFd() { 2794035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return mDevFd; 2804035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 2814035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2824035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerContainer::updateSoonestTime(LocTimerDelegate* priorTop) { 2834035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* curTop = getSoonestTimer(); 2844035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 2854035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // check if top has changed 2864035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (curTop != priorTop) { 2874035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct itimerspec delay = {0}; 2884035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin bool toSetTime = false; 2894035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // if tree is empty now, we remove poll and disarm timer 2904035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!curTop) { 2914035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mPollTask->removePoll(*this); 2924035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // setting the values to disarm timer 2934035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delay.it_value.tv_sec = 0; 2944035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delay.it_value.tv_nsec = 0; 2954035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin toSetTime = true; 2964035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else if (!priorTop || curTop->outRanks(*priorTop)) { 2974035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // do this first to avoid race condition, in case settime is called 2984035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // with too small an interval 2994035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mPollTask->addPoll(*this); 3004035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delay.it_value = curTop->getFutureTime(); 3014035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin toSetTime = true; 3024035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3034035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (toSetTime) { 3044035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL); 3054035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3064035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3074035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 3084035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3094035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// all the heap management is done in the MsgTask context. 3104035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 3114035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerContainer::add(LocTimerDelegate& timer) { 3124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct MsgTimerPush : public LocMsg { 3134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer* mTimerContainer; 3144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocHeapNode* mTree; 3154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* mTimer; 3164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline MsgTimerPush(LocTimerContainer& container, LocTimerDelegate& timer) : 3174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocMsg(), mTimerContainer(&container), mTimer(&timer) {} 3184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline virtual void proc() const { 3194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer(); 3204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mTimerContainer->push((LocRankable&)(*mTimer)); 3214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mTimerContainer->updateSoonestTime(priorTop); 3224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin }; 3244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mMsgTask->sendMsg(new MsgTimerPush(*this, timer)); 3264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 3274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// all the heap management is done in the MsgTask context. 3294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerContainer::remove(LocTimerDelegate& timer) { 3304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct MsgTimerRemove : public LocMsg { 3314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer* mTimerContainer; 3324035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* mTimer; 3334035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline MsgTimerRemove(LocTimerContainer& container, LocTimerDelegate& timer) : 3344035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocMsg(), mTimerContainer(&container), mTimer(&timer) {} 3354035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline virtual void proc() const { 3364035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer(); 3374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // update soonest timer only if mTimer is actually removed from 3394035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // mTimerContainer AND mTimer is not priorTop. 3404035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (priorTop == ((LocHeap*)mTimerContainer)->remove((LocRankable&)*mTimer)) { 3414035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // if passing in NULL, we tell updateSoonestTime to update 3424035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // kernel with the current top timer interval. 3434035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mTimerContainer->updateSoonestTime(NULL); 3444035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3454035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // all timers are deleted here, and only here. 3464035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete mTimer; 3474035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3484035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin }; 3494035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3504035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mMsgTask->sendMsg(new MsgTimerRemove(*this, timer)); 3514035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 3524035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3534035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// all the heap management is done in the MsgTask context. 3544035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// Upon expire, we check and continuously pop the heap until 3554035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// the top node's timeout is in the future. 3564035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerContainer::expire() { 3574035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct MsgTimerExpire : public LocMsg { 3584035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer* mTimerContainer; 3594035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline MsgTimerExpire(LocTimerContainer& container) : 3604035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocMsg(), mTimerContainer(&container) {} 3614035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline virtual void proc() const { 3624035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct timespec now; 3634035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // get time spec of now 3644035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin clock_gettime(CLOCK_BOOTTIME, &now); 3654035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate timerOfNow(now); 3664035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // pop everything in the heap that outRanks now, i.e. has time older than now 3674035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // and then call expire() on that timer. 3684035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin for (LocTimerDelegate* timer = (LocTimerDelegate*)mTimerContainer->pop(); 3694035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin NULL != timer; 3704035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timer = mTimerContainer->popIfOutRanks(timerOfNow)) { 3714035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // the timer delegate obj will be deleted before the return of this call 3724035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timer->expire(); 3734035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3744035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mTimerContainer->updateSoonestTime(NULL); 3754035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3764035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin }; 3774035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3784035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct itimerspec delay = {0}; 3794035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL); 3804035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mPollTask->removePoll(*this); 3814035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mMsgTask->sendMsg(new MsgTimerExpire(*this)); 3824035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 3834035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3844035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerDelegate* LocTimerContainer::popIfOutRanks(LocTimerDelegate& timer) { 3854035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* poppedNode = NULL; 3864035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (mTree && !timer.outRanks(*peek())) { 3874035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin poppedNode = (LocTimerDelegate*)(pop()); 3884035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 3894035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3904035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return poppedNode; 3914035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 3924035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3934035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3944035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin/***************************LocTimerPollTask methods***************************/ 3954035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 3964035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 3974035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerPollTask::LocTimerPollTask() 3984035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin : mFd(epoll_create(2)), mThread(new LocThread()) { 3994035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // before a next call returens, a thread will be created. The run() method 4004035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // could already be running in parallel. Also, since each of the objs 4014035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // creates a thread, the container will make sure that there will be only 4024035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // one of such obj for our timer implementation. 4034035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!mThread->start("LocTimerPollTask", this)) { 4044035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete mThread; 4054035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mThread = NULL; 4064035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 4074035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 4084035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4094035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 4104035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerPollTask::~LocTimerPollTask() { 4114035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // when fs is closed, epoll_wait() should fail run() should return false 4124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // and the spawned thread should exit. 4134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin close(mFd); 4144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 4154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerPollTask::destroy() { 4174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (mThread) { 4184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocThread* thread = mThread; 4194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mThread = NULL; 4204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete thread; 4214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else { 4224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete this; 4234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 4244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 4254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerPollTask::addPoll(LocTimerContainer& timerContainer) { 4274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct epoll_event ev; 4284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin memset(&ev, 0, sizeof(ev)); 4294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin ev.events = EPOLLIN | EPOLLWAKEUP; 4314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin ev.data.fd = timerContainer.getTimerFd(); 4324035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // it is important that we set this context pointer with the input 4334035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // timer container this is how we know which container should handle 4344035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // which expiration. 4354035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin ev.data.ptr = &timerContainer; 4364035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin epoll_ctl(mFd, EPOLL_CTL_ADD, timerContainer.getTimerFd(), &ev); 4384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 4394035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4404035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 4414035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerPollTask::removePoll(LocTimerContainer& timerContainer) { 4424035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin epoll_ctl(mFd, EPOLL_CTL_DEL, timerContainer.getTimerFd(), NULL); 4434035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 4444035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4454035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// The polling thread context will call this method. If run() method needs to 4464035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// be repetitvely called, it must return true from the previous call. 4474035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinbool LocTimerPollTask::run() { 4484035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct epoll_event ev[2]; 4494035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4504035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // we have max 2 descriptors to poll from 4514035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int fds = epoll_wait(mFd, ev, 2, -1); 4524035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4534035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // we pretty much want to continually poll until the fd is closed 4544035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin bool rerun = (fds > 0) || (errno == EINTR); 4554035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4564035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (fds > 0) { 4574035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // we may have 2 events 4584035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin for (int i = 0; i < fds; i++) { 4594035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // each fd has a context pointer associated with the right timer container 4604035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer* container = (LocTimerContainer*)(ev[i].data.ptr); 4614035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (container) { 4624035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin container->expire(); 4634035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else { 4644035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin epoll_ctl(mFd, EPOLL_CTL_DEL, ev[i].data.fd, NULL); 4654035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 4664035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 4674035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 4684035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4694035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // if rerun is true, we are requesting to be scheduled again 4704035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return rerun; 4714035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 4724035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4734035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin/***************************LocTimerDelegate methods***************************/ 4744035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4754035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 4764035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimerDelegate::LocTimerDelegate(LocTimer& client, struct timespec& futureTime, bool wakeOnExpire) 4774035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin : mClient(&client), 4784035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mLock(mClient->mLock->share()), 4794035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mFutureTime(futureTime), 4804035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mContainer(LocTimerContainer::get(wakeOnExpire)) { 4814035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // adding the timer into the container 4824035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mContainer->add(*this); 4834035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 4844035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4854035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 4864035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerDelegate::destroyLocked() { 4874035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // client handle will likely be deleted soon after this 4884035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // method returns. Nulling this handle so that expire() 4894035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // won't call the callback on the dead handle any more. 4904035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mClient = NULL; 4914035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 4924035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (mContainer) { 4934035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerContainer* container = mContainer; 4944035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mContainer = NULL; 4954035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (container) { 4964035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin container->remove(*this); 4974035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 4984035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } // else we do not do anything. No such *this* can be 4994035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // created and reached here with mContainer ever been 5004035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // a non NULL. So *this* must have reached the if clause 5014035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // once, and we want it reach there only once. 5024035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 5034035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5044035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinint LocTimerDelegate::ranks(LocRankable& rankable) { 5054035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int rank = -1; 5064035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* timer = (LocTimerDelegate*)(&rankable); 5074035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (timer) { 5084035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // larger time ranks lower!!! 5094035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // IOW, if input obj has bigger tv_sec, this obj outRanks higher 5104035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin rank = timer->mFutureTime.tv_sec - mFutureTime.tv_sec; 5114035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return rank; 5134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 5144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjininline 5164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid LocTimerDelegate::expire() { 5174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // keeping a copy of client pointer to be safe 5184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // when timeOutCallback() is called at the end of this 5194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // method, *this* obj may be already deleted. 5204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimer* client = mClient; 5214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // force a stop, which will lead to delete of this obj 5224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (client && client->stop()) { 5234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // calling client callback with a pointer save on the stack 5244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // only if stop() returns true, i.e. it hasn't been stopped 5254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // already. 5264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin client->timeOutCallback(); 5274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 5294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin/***************************LocTimer methods***************************/ 5324035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimer::LocTimer() : mTimer(NULL), mLock(new LocSharedLock()) { 5334035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 5344035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5354035be28a255eaa5605dbd9abeb2340db584249cPatrick TjinLocTimer::~LocTimer() { 5364035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin stop(); 5374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (mLock) { 5384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mLock->drop(); 5394035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mLock = NULL; 5404035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5414035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 5424035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5434035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinbool LocTimer::start(unsigned int timeOutInMs, bool wakeOnExpire) { 5444035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin bool success = false; 5454035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mLock->lock(); 5464035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!mTimer) { 5474035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct timespec futureTime; 5484035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin clock_gettime(CLOCK_BOOTTIME, &futureTime); 5494035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin futureTime.tv_sec += timeOutInMs / 1000; 5504035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin futureTime.tv_nsec += (timeOutInMs % 1000) * 1000000; 5514035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (futureTime.tv_nsec >= 1000000000) { 5524035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin futureTime.tv_sec += futureTime.tv_nsec / 1000000000; 5534035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin futureTime.tv_nsec %= 1000000000; 5544035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5554035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mTimer = new LocTimerDelegate(*this, futureTime, wakeOnExpire); 5564035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin // if mTimer is non 0, success should be 0; or vice versa 5574035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin success = (NULL != mTimer); 5584035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5594035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mLock->unlock(); 5604035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return success; 5614035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 5624035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5634035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinbool LocTimer::stop() { 5644035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin bool success = false; 5654035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mLock->lock(); 5664035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (mTimer) { 5674035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerDelegate* timer = mTimer; 5684035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mTimer = NULL; 5694035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (timer) { 5704035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timer->destroyLocked(); 5714035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin success = true; 5724035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5734035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5744035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mLock->unlock(); 5754035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return success; 5764035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 5774035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 5784035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin/***************************LocTimerWrapper methods***************************/ 5794035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin////////////////////////////////////////////////////////////////////////// 5804035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// This section below wraps for the C style APIs 5814035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin////////////////////////////////////////////////////////////////////////// 5824035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinclass LocTimerWrapper : public LocTimer { 5834035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin loc_timer_callback mCb; 5844035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void* mCallerData; 5854035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerWrapper* mMe; 5864035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin static pthread_mutex_t mMutex; 5874035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline ~LocTimerWrapper() { mCb = NULL; mMe = NULL; } 5884035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinpublic: 5894035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline LocTimerWrapper(loc_timer_callback cb, void* callerData) : 5904035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mCb(cb), mCallerData(callerData), mMe(this) { 5914035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5924035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void destroy() { 5934035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin pthread_mutex_lock(&mMutex); 5944035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (NULL != mCb && this == mMe) { 5954035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete this; 5964035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5974035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin pthread_mutex_unlock(&mMutex); 5984035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 5994035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin virtual void timeOutCallback() { 6004035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin loc_timer_callback cb = mCb; 6014035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void* callerData = mCallerData; 6024035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (cb) { 6034035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin cb(callerData, 0); 6044035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6054035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin destroy(); 6064035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6074035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin}; 6084035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6094035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinpthread_mutex_t LocTimerWrapper::mMutex = PTHREAD_MUTEX_INITIALIZER; 6104035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6114035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid* loc_timer_start(uint64_t msec, loc_timer_callback cb_func, 6124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin void *caller_data, bool wake_on_expire) 6134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin{ 6144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerWrapper* locTimerWrapper = NULL; 6154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (cb_func) { 6174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin locTimerWrapper = new LocTimerWrapper(cb_func, caller_data); 6184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (locTimerWrapper) { 6204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin locTimerWrapper->start(msec, wake_on_expire); 6214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return locTimerWrapper; 6254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 6264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinvoid loc_timer_stop(void*& handle) 6284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin{ 6294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (handle) { 6304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerWrapper* locTimerWrapper = (LocTimerWrapper*)(handle); 6314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin locTimerWrapper->destroy(); 6324035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin handle = NULL; 6334035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6344035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 6354035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6364035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin////////////////////////////////////////////////////////////////////////// 6374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// This section above wraps for the C style APIs 6384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin////////////////////////////////////////////////////////////////////////// 6394035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6404035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#ifdef __LOC_DEBUG__ 6414035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6424035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjindouble getDeltaSeconds(struct timespec from, struct timespec to) { 6434035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return (double)to.tv_sec + (double)to.tv_nsec / 1000000000 6444035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin - from.tv_sec - (double)from.tv_nsec / 1000000000; 6454035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 6464035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6474035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinstruct timespec getNow() { 6484035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct timespec now; 6494035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin clock_gettime(CLOCK_BOOTTIME, &now); 6504035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return now; 6514035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 6524035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6534035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinclass LocTimerTest : public LocTimer, public LocRankable { 6544035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int mTimeOut; 6554035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin const struct timespec mTimeOfBirth; 6564035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline struct timespec getTimerWrapper(int timeout) { 6574035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct timespec now; 6584035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin clock_gettime(CLOCK_BOOTTIME, &now); 6594035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin now.tv_sec += timeout; 6604035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return now; 6614035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6624035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinpublic: 6634035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline LocTimerTest(int timeout) : LocTimer(), LocRankable(), 6644035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin mTimeOut(timeout), mTimeOfBirth(getTimerWrapper(0)) {} 6654035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline virtual int ranks(LocRankable& rankable) { 6664035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerTest* timer = dynamic_cast<LocTimerTest*>(&rankable); 6674035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return timer->mTimeOut - mTimeOut; 6684035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6694035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin inline virtual void timeOutCallback() { 6704035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("timeOutCallback() - "); 6714035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin deviation(); 6724035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6734035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin double deviation() { 6744035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct timespec now = getTimerWrapper(0); 6754035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin double delta = getDeltaSeconds(mTimeOfBirth, now); 6764035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("%lf: %lf\n", delta, delta * 100 / mTimeOut); 6774035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return delta / mTimeOut; 6784035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 6794035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin}; 6804035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6814035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// For Linux command line testing: 6824035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// compilation: 6834035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocHeap.o LocHeap.cpp 6844035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -std=c++0x -I. -I../../../../system/core/include -lpthread -o LocThread.o LocThread.cpp 6854035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocTimer.o LocTimer.cpp 6864035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjinint main(int argc, char** argv) { 6874035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin struct timespec timeOfStart=getNow(); 6884035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin srand(time(NULL)); 6894035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int tries = atoi(argv[1]); 6904035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int checks = tries >> 3; 6914035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerTest** timerArray = new LocTimerTest*[tries]; 6924035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin memset(timerArray, NULL, tries); 6934035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 6944035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin for (int i = 0; i < tries; i++) { 6954035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin int r = rand() % tries; 6964035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin LocTimerTest* timer = new LocTimerTest(r); 6974035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (timerArray[r]) { 6984035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!timer->stop()) { 6994035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); 7004035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("ERRER: %dth timer, id %d, not running when it should be\n", i, r); 7014035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin exit(0); 7024035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else { 7034035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("stop() - %d\n", r); 7044035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete timer; 7054035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timerArray[r] = NULL; 7064035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 7074035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else { 7084035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!timer->start(r, false)) { 7094035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); 7104035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("ERRER: %dth timer, id %d, running when it should not be\n", i, r); 7114035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin exit(0); 7124035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else { 7134035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("stop() - %d\n", r); 7144035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timerArray[r] = timer; 7154035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 7164035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 7174035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 7184035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 7194035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin for (int i = 0; i < tries; i++) { 7204035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (timerArray[i]) { 7214035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin if (!timerArray[i]->stop()) { 7224035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); 7234035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("ERRER: %dth timer, not running when it should be\n", i); 7244035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin exit(0); 7254035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } else { 7264035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin printf("stop() - %d\n", i); 7274035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete timerArray[i]; 7284035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin timerArray[i] = NULL; 7294035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 7304035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 7314035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin } 7324035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 7334035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin delete[] timerArray; 7344035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 7354035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin return 0; 7364035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin} 7374035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin 7384035be28a255eaa5605dbd9abeb2340db584249cPatrick Tjin#endif 739