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