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