1129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/* Copyright (c) 2015, The Linux Foundation. All rights reserved. 2129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * 3129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * Redistribution and use in source and binary forms, with or without 4129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * modification, are permitted provided that the following conditions are 5129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * met: 6129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * * Redistributions of source code must retain the above copyright 7129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * notice, this list of conditions and the following disclaimer. 8129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * * Redistributions in binary form must reproduce the above 9129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * copyright notice, this list of conditions and the following 10129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * disclaimer in the documentation and/or other materials provided 11129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * with the distribution. 12129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * * Neither the name of The Linux Foundation, nor the names of its 13129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * contributors may be used to endorse or promote products derived 14129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * from this software without specific prior written permission. 15129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * 16129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * 28129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel */ 29129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 30129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <stdio.h> 31129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <stdlib.h> 32129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <time.h> 33129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <errno.h> 34129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <loc_timer.h> 35129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <sys/timerfd.h> 36129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <sys/epoll.h> 375e83ad6ed3ddaf8479a47c4f9f1428cb99eb5cc9Steven Moreland#include <unistd.h> 38129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <LocTimer.h> 39129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <LocHeap.h> 40129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <LocThread.h> 41129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <LocSharedLock.h> 42129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <MsgTask.h> 43129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 44129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#ifdef __HOST_UNIT_TEST__ 45129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#define EPOLLWAKEUP 0 46129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#define CLOCK_BOOTTIME CLOCK_MONOTONIC 47129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#define CLOCK_BOOTTIME_ALARM CLOCK_MONOTONIC 48129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#endif 49129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 50129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/* 51129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelThere are implementations of 5 classes in this file: 52129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimer, LocTimerDelegate, LocTimerContainer, LocTimerPollTask, LocTimerWrapper 53129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 54129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimer - client front end, interface for client to start / stop timers, also 55129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel to provide a callback. 56129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerDelegate - an internal timer entity, which also is a LocRankable obj. 57129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel Its life cycle is different than that of LocTimer. It gets 58129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel created when LocTimer::start() is called, and gets deleted 59129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel when it expires or clients calls the hosting LocTimer obj's 60129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel stop() method. When a LocTimerDelegate obj is ticking, it 61129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel stays in the corresponding LocTimerContainer. When expired 62129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel or stopped, the obj is removed from the container. Since it 63129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel is also a LocRankable obj, and LocTimerContainer also is a 64129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel heap, its ranks() implementation decides where it is placed 65129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel in the heap. 66129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerContainer - core of the timer service. It is a container (derived from 67129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocHeap) for LocTimerDelegate (implements LocRankable) objs. 68129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel There are 2 of such containers, one for sw timers (or Linux 69129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timers) one for hw timers (or Linux alarms). It adds one of 70129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel each (those that expire the soonest) to kernel via services 71129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel provided by LocTimerPollTask. All the heap management on the 72129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate objs are done in the MsgTask context, such 73129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel that synchronization is ensured. 74129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerPollTask - is a class that wraps timerfd and epoll POXIS APIs. It also 75129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel both implements LocRunnalbe with epoll_wait() in the run() 76129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel method. It is also a LocThread client, so as to loop the run 77129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel method. 78129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerWrapper - a LocTimer client itself, to implement the existing C API with 79129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel APIs, loc_timer_start() and loc_timer_stop(). 80129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 81129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel*/ 82129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 83129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocTimerPollTask; 84129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 85129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// This is a multi-functaional class that: 86129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// * extends the LocHeap class for the detection of head update upon add / remove 87129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// events. When that happens, soonest time out changes, so timerfd needs update. 88129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// * contains the timers, and add / remove them into the heap 89129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// * provides and maps 2 of such containers, one for timers (or mSwTimers), one 90129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// for alarms (or mHwTimers); 91129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// * provides a polling thread; 92129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// * provides a MsgTask thread for synchronized add / remove / timer client callback. 93129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocTimerContainer : public LocHeap { 94129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // mutex to synchronize getters of static members 95129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static pthread_mutex_t mMutex; 96129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // Container of timers 97129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static LocTimerContainer* mSwTimers; 98129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // Container of alarms 99129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static LocTimerContainer* mHwTimers; 100129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // Msg task to provider msg Q, sender and reader. 101129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static MsgTask* mMsgTask; 102129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // Poll task to provide epoll call and threading to poll. 103129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static LocTimerPollTask* mPollTask; 104129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // timer / alarm fd 105129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int mDevFd; 106129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // ctor 107129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer(bool wakeOnExpire); 108129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // dtor 109129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel ~LocTimerContainer(); 110129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static MsgTask* getMsgTaskLocked(); 111129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static LocTimerPollTask* getPollTaskLocked(); 112129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // extend LocHeap and pop if the top outRanks input 113129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* popIfOutRanks(LocTimerDelegate& timer); 114129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // update the timer POSIX calls with updated soonest timer spec 115129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void updateSoonestTime(LocTimerDelegate* priorTop); 116129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 117129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpublic: 118129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // factory method to control the creation of mSwTimers / mHwTimers 119129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static LocTimerContainer* get(bool wakeOnExpire); 120129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 121129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* getSoonestTimer(); 122129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int getTimerFd(); 123129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // add a timer / alarm obj into the container 124129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void add(LocTimerDelegate& timer); 125129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // remove a timer / alarm obj from the container 126129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void remove(LocTimerDelegate& timer); 127129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // handling of timer / alarm expiration 128129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void expire(); 129129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}; 130129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 131129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// This class implements the polling thread that epolls imer / alarm fds. 132129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// The LocRunnable::run() contains the actual polling. The other methods 133129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// will be run in the caller's thread context to add / remove timer / alarm 134129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// fds the kernel, while the polling is blocked on epoll_wait() call. 135129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// Since the design is that we have maximally 2 polls, one for all the 136129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// timers; one for all the alarms, we will poll at most on 2 fds. But it 137129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// is possile that all we have are only timers or alarms at one time, so we 138129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// allow dynamically add / remove fds we poll on. The design decision of 139129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// having 1 fd per container of timer / alarm is such that, we may not need 140129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// to make a system call each time a timer / alarm is added / removed, unless 141129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// that changes the "soonest" time out of that of all the timers / alarms. 142129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocTimerPollTask : public LocRunnable { 143129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // the epoll fd 144129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel const int mFd; 145129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // the thread that calls run() method 146129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocThread* mThread; 147129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel friend class LocThreadDelegate; 148129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // dtor 149129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel ~LocTimerPollTask(); 150129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpublic: 151129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // ctor 152129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerPollTask(); 153129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // this obj will be deleted once thread is deleted 154129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void destroy(); 155129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // add a container of timers. Each contain has a unique device fd, i.e. 156129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // either timer or alarm fd, and a heap of timers / alarms. It is expected 157129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // that container would have written to the device fd with the soonest 158129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // time out value in the heap at the time of calling this method. So all 159129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // this method does is to add the fd of the input container to the poll 160129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // and also add the pointer of the container to the event data ptr, such 161129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // when poll_wait wakes up on events, we know who is the owner of the fd. 162129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void addPoll(LocTimerContainer& timerContainer); 163129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // remove a fd that is assciated with a container. The expectation is that 164129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // the atual timer would have been removed from the container. 165129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void removePoll(LocTimerContainer& timerContainer); 166129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // The polling thread context will call this method. This is where 167129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // epoll_wait() is blocking and waiting for events.. 168129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel virtual bool run(); 169129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}; 170129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 171129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// Internal class of timer obj. It gets born when client calls LocTimer::start(); 172129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// and gets deleted when client calls LocTimer::stop() or when the it expire()'s. 173129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// This class implements LocRankable::ranks() so that when an obj is added into 174129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// the container (of LocHeap), it gets placed in sorted order. 175129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocTimerDelegate : public LocRankable { 176129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel friend class LocTimerContainer; 177129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel friend class LocTimer; 178129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimer* mClient; 179129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocSharedLock* mLock; 180129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct timespec mFutureTime; 181129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer* mContainer; 182129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // not a complete obj, just ctor for LocRankable comparisons 183129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline LocTimerDelegate(struct timespec& delay) 184129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel : mClient(NULL), mLock(NULL), mFutureTime(delay), mContainer(NULL) {} 185129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline ~LocTimerDelegate() { if (mLock) { mLock->drop(); mLock = NULL; } } 186129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpublic: 1873b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean LocTimerDelegate(LocTimer& client, struct timespec& futureTime, LocTimerContainer* container); 188129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void destroyLocked(); 189129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // LocRankable virtual method 190129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel virtual int ranks(LocRankable& rankable); 191129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void expire(); 192129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline struct timespec getFutureTime() { return mFutureTime; } 193129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}; 194129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 195129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/***************************LocTimerContainer methods***************************/ 196129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 197129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// Most of these static recources are created on demand. They however are never 198129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// destoyed. The theory is that there are processes that link to this util lib 199129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// but never use timer, then these resources would never need to be created. 200129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// For those processes that do use timer, it will likely also need to every 201129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// once in a while. It might be cheaper keeping them around. 202129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpthread_mutex_t LocTimerContainer::mMutex = PTHREAD_MUTEX_INITIALIZER; 203129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerContainer* LocTimerContainer::mSwTimers = NULL; 204129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerContainer* LocTimerContainer::mHwTimers = NULL; 205129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelMsgTask* LocTimerContainer::mMsgTask = NULL; 206129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerPollTask* LocTimerContainer::mPollTask = NULL; 207129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 208129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// ctor - initialize timer heaps 209129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// A container for swTimer (timer) is created, when wakeOnExpire is true; or 210129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// HwTimer (alarm), when wakeOnExpire is false. 211129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerContainer::LocTimerContainer(bool wakeOnExpire) : 212129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mDevFd(timerfd_create(wakeOnExpire ? CLOCK_BOOTTIME_ALARM : CLOCK_BOOTTIME, 0)) { 213129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 214129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if ((-1 == mDevFd) && (errno == EINVAL)) { 215129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LOC_LOGW("%s: timerfd_create failure, fallback to CLOCK_MONOTONIC - %s", 216129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel __FUNCTION__, strerror(errno)); 217129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mDevFd = timerfd_create(CLOCK_MONOTONIC, 0); 218129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 219129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 220129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (-1 != mDevFd) { 221129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // ensure we have the necessary resources created 222129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer::getPollTaskLocked(); 223129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer::getMsgTaskLocked(); 224129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else { 225129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LOC_LOGE("%s: timerfd_create failure - %s", __FUNCTION__, strerror(errno)); 226129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 227129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 228129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 229129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// dtor 230129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// we do not ever destroy the static resources. 231129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 232129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerContainer::~LocTimerContainer() { 233129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel close(mDevFd); 234129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 235129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 236129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerContainer* LocTimerContainer::get(bool wakeOnExpire) { 237129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // get the reference of either mHwTimer or mSwTimers per wakeOnExpire 238129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer*& container = wakeOnExpire ? mHwTimers : mSwTimers; 239129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // it is cheap to check pointer first than locking mutext unconditionally 240129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!container) { 241129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel pthread_mutex_lock(&mMutex); 242129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // let's check one more time to be safe 243129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!container) { 244129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel container = new LocTimerContainer(wakeOnExpire); 245129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // timerfd_create failure 246129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (-1 == container->getTimerFd()) { 247129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete container; 248129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel container = NULL; 249129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 250129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 251129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel pthread_mutex_unlock(&mMutex); 252129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 253129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return container; 254129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 255129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 256129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelMsgTask* LocTimerContainer::getMsgTaskLocked() { 257129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // it is cheap to check pointer first than locking mutext unconditionally 258129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!mMsgTask) { 259129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mMsgTask = new MsgTask("LocTimerMsgTask", false); 260129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 261129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return mMsgTask; 262129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 263129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 264129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerPollTask* LocTimerContainer::getPollTaskLocked() { 265129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // it is cheap to check pointer first than locking mutext unconditionally 266129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!mPollTask) { 267129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mPollTask = new LocTimerPollTask(); 268129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 269129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return mPollTask; 270129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 271129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 272129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 273129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerDelegate* LocTimerContainer::getSoonestTimer() { 274129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return (LocTimerDelegate*)(peek()); 275129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 276129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 277129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 278129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelint LocTimerContainer::getTimerFd() { 279129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return mDevFd; 280129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 281129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 282129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerContainer::updateSoonestTime(LocTimerDelegate* priorTop) { 283129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* curTop = getSoonestTimer(); 284129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 285129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // check if top has changed 286129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (curTop != priorTop) { 287129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct itimerspec delay = {0}; 288129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel bool toSetTime = false; 289129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // if tree is empty now, we remove poll and disarm timer 290129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!curTop) { 291129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mPollTask->removePoll(*this); 292129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // setting the values to disarm timer 293129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delay.it_value.tv_sec = 0; 294129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delay.it_value.tv_nsec = 0; 295129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel toSetTime = true; 296129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else if (!priorTop || curTop->outRanks(*priorTop)) { 297129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // do this first to avoid race condition, in case settime is called 298129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // with too small an interval 299129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mPollTask->addPoll(*this); 300129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delay.it_value = curTop->getFutureTime(); 301129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel toSetTime = true; 302129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 303129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (toSetTime) { 304129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL); 305129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 306129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 307129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 308129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 309129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// all the heap management is done in the MsgTask context. 310129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 311129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerContainer::add(LocTimerDelegate& timer) { 312129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct MsgTimerPush : public LocMsg { 313129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer* mTimerContainer; 314129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocHeapNode* mTree; 315129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* mTimer; 316129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline MsgTimerPush(LocTimerContainer& container, LocTimerDelegate& timer) : 317129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocMsg(), mTimerContainer(&container), mTimer(&timer) {} 318129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline virtual void proc() const { 319129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer(); 320129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mTimerContainer->push((LocRankable&)(*mTimer)); 321129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mTimerContainer->updateSoonestTime(priorTop); 322129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 323129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel }; 324129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 325129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mMsgTask->sendMsg(new MsgTimerPush(*this, timer)); 326129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 327129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 328129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// all the heap management is done in the MsgTask context. 329129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerContainer::remove(LocTimerDelegate& timer) { 330129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct MsgTimerRemove : public LocMsg { 331129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer* mTimerContainer; 332129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* mTimer; 333129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline MsgTimerRemove(LocTimerContainer& container, LocTimerDelegate& timer) : 334129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocMsg(), mTimerContainer(&container), mTimer(&timer) {} 335129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline virtual void proc() const { 336129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer(); 337129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 338129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // update soonest timer only if mTimer is actually removed from 339129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // mTimerContainer AND mTimer is not priorTop. 340129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (priorTop == ((LocHeap*)mTimerContainer)->remove((LocRankable&)*mTimer)) { 341129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // if passing in NULL, we tell updateSoonestTime to update 342129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // kernel with the current top timer interval. 343129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mTimerContainer->updateSoonestTime(NULL); 344129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 345129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // all timers are deleted here, and only here. 346129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete mTimer; 347129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 348129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel }; 349129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 350129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mMsgTask->sendMsg(new MsgTimerRemove(*this, timer)); 351129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 352129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 353129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// all the heap management is done in the MsgTask context. 354129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// Upon expire, we check and continuously pop the heap until 355129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// the top node's timeout is in the future. 356129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerContainer::expire() { 357129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct MsgTimerExpire : public LocMsg { 358129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer* mTimerContainer; 359129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline MsgTimerExpire(LocTimerContainer& container) : 360129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocMsg(), mTimerContainer(&container) {} 361129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline virtual void proc() const { 362129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct timespec now; 363129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // get time spec of now 364129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel clock_gettime(CLOCK_BOOTTIME, &now); 365129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate timerOfNow(now); 366129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // pop everything in the heap that outRanks now, i.e. has time older than now 367129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // and then call expire() on that timer. 368129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel for (LocTimerDelegate* timer = (LocTimerDelegate*)mTimerContainer->pop(); 369129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel NULL != timer; 370129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timer = mTimerContainer->popIfOutRanks(timerOfNow)) { 371129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // the timer delegate obj will be deleted before the return of this call 372129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timer->expire(); 373129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 374129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mTimerContainer->updateSoonestTime(NULL); 375129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 376129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel }; 377129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 378129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct itimerspec delay = {0}; 379129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL); 380129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mPollTask->removePoll(*this); 381129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mMsgTask->sendMsg(new MsgTimerExpire(*this)); 382129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 383129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 384129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerDelegate* LocTimerContainer::popIfOutRanks(LocTimerDelegate& timer) { 385129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* poppedNode = NULL; 386129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (mTree && !timer.outRanks(*peek())) { 387129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel poppedNode = (LocTimerDelegate*)(pop()); 388129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 389129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 390129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return poppedNode; 391129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 392129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 393129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 394129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/***************************LocTimerPollTask methods***************************/ 395129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 396129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 397129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerPollTask::LocTimerPollTask() 398129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel : mFd(epoll_create(2)), mThread(new LocThread()) { 399129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // before a next call returens, a thread will be created. The run() method 400129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // could already be running in parallel. Also, since each of the objs 401129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // creates a thread, the container will make sure that there will be only 402129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // one of such obj for our timer implementation. 403129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!mThread->start("LocTimerPollTask", this)) { 404129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete mThread; 405129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mThread = NULL; 406129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 407129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 408129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 409129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 410129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimerPollTask::~LocTimerPollTask() { 411129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // when fs is closed, epoll_wait() should fail run() should return false 412129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // and the spawned thread should exit. 413129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel close(mFd); 414129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 415129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 416129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerPollTask::destroy() { 417129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (mThread) { 418129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocThread* thread = mThread; 419129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mThread = NULL; 420129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete thread; 421129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else { 422129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete this; 423129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 424129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 425129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 426129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerPollTask::addPoll(LocTimerContainer& timerContainer) { 427129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct epoll_event ev; 428129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel memset(&ev, 0, sizeof(ev)); 429129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 430129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel ev.events = EPOLLIN | EPOLLWAKEUP; 431129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel ev.data.fd = timerContainer.getTimerFd(); 432129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // it is important that we set this context pointer with the input 433129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // timer container this is how we know which container should handle 434129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // which expiration. 435129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel ev.data.ptr = &timerContainer; 436129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 437129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel epoll_ctl(mFd, EPOLL_CTL_ADD, timerContainer.getTimerFd(), &ev); 438129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 439129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 440129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 441129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerPollTask::removePoll(LocTimerContainer& timerContainer) { 442129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel epoll_ctl(mFd, EPOLL_CTL_DEL, timerContainer.getTimerFd(), NULL); 443129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 444129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 445129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// The polling thread context will call this method. If run() method needs to 446129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// be repetitvely called, it must return true from the previous call. 447129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelbool LocTimerPollTask::run() { 448129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct epoll_event ev[2]; 449129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 450129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // we have max 2 descriptors to poll from 451129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int fds = epoll_wait(mFd, ev, 2, -1); 452129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 453129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // we pretty much want to continually poll until the fd is closed 454129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel bool rerun = (fds > 0) || (errno == EINTR); 455129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 456129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (fds > 0) { 457129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // we may have 2 events 458129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel for (int i = 0; i < fds; i++) { 459129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // each fd has a context pointer associated with the right timer container 460129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer* container = (LocTimerContainer*)(ev[i].data.ptr); 461129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (container) { 462129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel container->expire(); 463129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else { 464129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel epoll_ctl(mFd, EPOLL_CTL_DEL, ev[i].data.fd, NULL); 465129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 466129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 467129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 468129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 469129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // if rerun is true, we are requesting to be scheduled again 470129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return rerun; 471129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 472129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 473129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/***************************LocTimerDelegate methods***************************/ 474129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 475129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 4763b71ca7447a2cd4b76264d5f094676c8da629297Mike CaileanLocTimerDelegate::LocTimerDelegate(LocTimer& client, 4773b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean struct timespec& futureTime, 4783b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean LocTimerContainer* container) 479129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel : mClient(&client), 480129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mLock(mClient->mLock->share()), 481129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mFutureTime(futureTime), 4823b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean mContainer(container) { 483129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // adding the timer into the container 484129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mContainer->add(*this); 485129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 486129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 487129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 488129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerDelegate::destroyLocked() { 489129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // client handle will likely be deleted soon after this 490129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // method returns. Nulling this handle so that expire() 491129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // won't call the callback on the dead handle any more. 492129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mClient = NULL; 493129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 494129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (mContainer) { 495129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerContainer* container = mContainer; 496129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mContainer = NULL; 497129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (container) { 498129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel container->remove(*this); 499129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 500129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } // else we do not do anything. No such *this* can be 501129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // created and reached here with mContainer ever been 502129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // a non NULL. So *this* must have reached the if clause 503129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // once, and we want it reach there only once. 504129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 505129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 506129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelint LocTimerDelegate::ranks(LocRankable& rankable) { 507129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int rank = -1; 508129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* timer = (LocTimerDelegate*)(&rankable); 509129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (timer) { 510129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // larger time ranks lower!!! 511129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // IOW, if input obj has bigger tv_sec/tv_nsec, this obj outRanks higher 512129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel rank = timer->mFutureTime.tv_sec - mFutureTime.tv_sec; 513129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if(0 == rank) 514129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel { 515129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel //rank against tv_nsec for msec accuracy 516129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel rank = (int)(timer->mFutureTime.tv_nsec - mFutureTime.tv_nsec); 517129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 518129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 519129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return rank; 520129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 521129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 522129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline 523129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocTimerDelegate::expire() { 524129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // keeping a copy of client pointer to be safe 525129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // when timeOutCallback() is called at the end of this 526129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // method, *this* obj may be already deleted. 527129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimer* client = mClient; 528129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // force a stop, which will lead to delete of this obj 529129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (client && client->stop()) { 530129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // calling client callback with a pointer save on the stack 531129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // only if stop() returns true, i.e. it hasn't been stopped 532129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel // already. 533129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel client->timeOutCallback(); 534129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 535129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 536129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 537129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 538129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/***************************LocTimer methods***************************/ 539129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimer::LocTimer() : mTimer(NULL), mLock(new LocSharedLock()) { 540129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 541129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 542129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocTimer::~LocTimer() { 543129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel stop(); 544129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (mLock) { 545129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mLock->drop(); 546129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mLock = NULL; 547129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 548129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 549129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 550129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelbool LocTimer::start(unsigned int timeOutInMs, bool wakeOnExpire) { 551129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel bool success = false; 552129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mLock->lock(); 553129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!mTimer) { 554129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct timespec futureTime; 555129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel clock_gettime(CLOCK_BOOTTIME, &futureTime); 556129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel futureTime.tv_sec += timeOutInMs / 1000; 557129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel futureTime.tv_nsec += (timeOutInMs % 1000) * 1000000; 558129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (futureTime.tv_nsec >= 1000000000) { 559129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel futureTime.tv_sec += futureTime.tv_nsec / 1000000000; 560129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel futureTime.tv_nsec %= 1000000000; 561129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 5623b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean 5633b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean LocTimerContainer* container; 5643b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean container = LocTimerContainer::get(wakeOnExpire); 5653b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean if (NULL != container) { 5663b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean mTimer = new LocTimerDelegate(*this, futureTime, container); 5673b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean // if mTimer is non 0, success should be 0; or vice versa 5683b71ca7447a2cd4b76264d5f094676c8da629297Mike Cailean } 569129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel success = (NULL != mTimer); 570129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 571129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mLock->unlock(); 572129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return success; 573129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 574129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 575129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelbool LocTimer::stop() { 576129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel bool success = false; 577129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mLock->lock(); 578129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (mTimer) { 579129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerDelegate* timer = mTimer; 580129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mTimer = NULL; 581129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (timer) { 582129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timer->destroyLocked(); 583129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel success = true; 584129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 585129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 586129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mLock->unlock(); 587129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return success; 588129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 589129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 590129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/***************************LocTimerWrapper methods***************************/ 591129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel////////////////////////////////////////////////////////////////////////// 592129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// This section below wraps for the C style APIs 593129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel////////////////////////////////////////////////////////////////////////// 594129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocTimerWrapper : public LocTimer { 595129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel loc_timer_callback mCb; 596129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void* mCallerData; 597129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerWrapper* mMe; 598129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel static pthread_mutex_t mMutex; 599129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline ~LocTimerWrapper() { mCb = NULL; mMe = NULL; } 600129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpublic: 601129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline LocTimerWrapper(loc_timer_callback cb, void* callerData) : 602129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mCb(cb), mCallerData(callerData), mMe(this) { 603129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 604129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void destroy() { 605129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel pthread_mutex_lock(&mMutex); 606129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (NULL != mCb && this == mMe) { 607129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete this; 608129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 609129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel pthread_mutex_unlock(&mMutex); 610129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 611129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel virtual void timeOutCallback() { 612129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel loc_timer_callback cb = mCb; 613129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void* callerData = mCallerData; 614129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (cb) { 615129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel cb(callerData, 0); 616129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 617129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel destroy(); 618129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 619129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}; 620129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 621129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpthread_mutex_t LocTimerWrapper::mMutex = PTHREAD_MUTEX_INITIALIZER; 622129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 623129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid* loc_timer_start(uint64_t msec, loc_timer_callback cb_func, 624129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel void *caller_data, bool wake_on_expire) 625129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel{ 626129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerWrapper* locTimerWrapper = NULL; 627129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 628129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (cb_func) { 629129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel locTimerWrapper = new LocTimerWrapper(cb_func, caller_data); 630129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 631129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (locTimerWrapper) { 632129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel locTimerWrapper->start(msec, wake_on_expire); 633129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 634129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 635129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 636129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return locTimerWrapper; 637129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 638129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 639129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid loc_timer_stop(void*& handle) 640129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel{ 641129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (handle) { 642129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerWrapper* locTimerWrapper = (LocTimerWrapper*)(handle); 643129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel locTimerWrapper->destroy(); 644129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel handle = NULL; 645129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 646129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 647129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 648129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel////////////////////////////////////////////////////////////////////////// 649129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// This section above wraps for the C style APIs 650129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel////////////////////////////////////////////////////////////////////////// 651129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 652129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#ifdef __LOC_DEBUG__ 653129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 654129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudeldouble getDeltaSeconds(struct timespec from, struct timespec to) { 655129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return (double)to.tv_sec + (double)to.tv_nsec / 1000000000 656129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel - from.tv_sec - (double)from.tv_nsec / 1000000000; 657129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 658129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 659129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelstruct timespec getNow() { 660129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct timespec now; 661129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel clock_gettime(CLOCK_BOOTTIME, &now); 662129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return now; 663129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 664129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 665129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocTimerTest : public LocTimer, public LocRankable { 666129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int mTimeOut; 667129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel const struct timespec mTimeOfBirth; 668129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline struct timespec getTimerWrapper(int timeout) { 669129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct timespec now; 670129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel clock_gettime(CLOCK_BOOTTIME, &now); 671129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel now.tv_sec += timeout; 672129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return now; 673129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 674129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpublic: 675129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline LocTimerTest(int timeout) : LocTimer(), LocRankable(), 676129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel mTimeOut(timeout), mTimeOfBirth(getTimerWrapper(0)) {} 677129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline virtual int ranks(LocRankable& rankable) { 678129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerTest* timer = dynamic_cast<LocTimerTest*>(&rankable); 679129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return timer->mTimeOut - mTimeOut; 680129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 681129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel inline virtual void timeOutCallback() { 682129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("timeOutCallback() - "); 683129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel deviation(); 684129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 685129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel double deviation() { 686129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct timespec now = getTimerWrapper(0); 687129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel double delta = getDeltaSeconds(mTimeOfBirth, now); 688129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("%lf: %lf\n", delta, delta * 100 / mTimeOut); 689129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return delta / mTimeOut; 690129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 691129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}; 692129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 693129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// For Linux command line testing: 694129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// compilation: 695129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocHeap.o LocHeap.cpp 696129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -std=c++0x -I. -I../../../../system/core/include -lpthread -o LocThread.o LocThread.cpp 697129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocTimer.o LocTimer.cpp 698129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelint main(int argc, char** argv) { 699129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel struct timespec timeOfStart=getNow(); 700129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel srand(time(NULL)); 701129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int tries = atoi(argv[1]); 702129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int checks = tries >> 3; 703129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerTest** timerArray = new LocTimerTest*[tries]; 704129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel memset(timerArray, NULL, tries); 705129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 706129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel for (int i = 0; i < tries; i++) { 707129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel int r = rand() % tries; 708129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel LocTimerTest* timer = new LocTimerTest(r); 709129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (timerArray[r]) { 710129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!timer->stop()) { 711129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); 712129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("ERRER: %dth timer, id %d, not running when it should be\n", i, r); 713129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel exit(0); 714129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else { 715129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("stop() - %d\n", r); 716129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete timer; 717129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timerArray[r] = NULL; 718129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 719129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else { 720129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!timer->start(r, false)) { 721129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); 722129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("ERRER: %dth timer, id %d, running when it should not be\n", i, r); 723129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel exit(0); 724129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else { 725129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("stop() - %d\n", r); 726129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timerArray[r] = timer; 727129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 728129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 729129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 730129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 731129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel for (int i = 0; i < tries; i++) { 732129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (timerArray[i]) { 733129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel if (!timerArray[i]->stop()) { 734129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); 735129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("ERRER: %dth timer, not running when it should be\n", i); 736129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel exit(0); 737129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } else { 738129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel printf("stop() - %d\n", i); 739129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete timerArray[i]; 740129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel timerArray[i] = NULL; 741129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 742129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 743129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel } 744129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 745129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel delete[] timerArray; 746129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 747129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel return 0; 748129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel} 749129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel 750129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#endif 751