123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648 |
- /* Copyright (c) 2015, 2020-2021 The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation, nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <errno.h>
- #include <sys/timerfd.h>
- #include <sys/epoll.h>
- #include <log_util.h>
- #include <loc_timer.h>
- #include <LocTimer.h>
- #include <LocHeap.h>
- #include <LocThread.h>
- #include <LocSharedLock.h>
- #include <MsgTask.h>
- #ifdef __HOST_UNIT_TEST__
- #define EPOLLWAKEUP 0
- #define CLOCK_BOOTTIME CLOCK_MONOTONIC
- #define CLOCK_BOOTTIME_ALARM CLOCK_MONOTONIC
- #endif
- namespace loc_util {
- /*
- There are implementations of 5 classes in this file:
- LocTimer, LocTimerDelegate, LocTimerContainer, LocTimerPollTask, LocTimerWrapper
- LocTimer - client front end, interface for client to start / stop timers, also
- to provide a callback.
- LocTimerDelegate - an internal timer entity, which also is a LocRankable obj.
- Its life cycle is different than that of LocTimer. It gets
- created when LocTimer::start() is called, and gets deleted
- when it expires or clients calls the hosting LocTimer obj's
- stop() method. When a LocTimerDelegate obj is ticking, it
- stays in the corresponding LocTimerContainer. When expired
- or stopped, the obj is removed from the container. Since it
- is also a LocRankable obj, and LocTimerContainer also is a
- heap, its ranks() implementation decides where it is placed
- in the heap.
- LocTimerContainer - core of the timer service. It is a container (derived from
- LocHeap) for LocTimerDelegate (implements LocRankable) objs.
- There are 2 of such containers, one for sw timers (or Linux
- timers) one for hw timers (or Linux alarms). It adds one of
- each (those that expire the soonest) to kernel via services
- provided by LocTimerPollTask. All the heap management on the
- LocTimerDelegate objs are done in the MsgTask context, such
- that synchronization is ensured.
- LocTimerPollTask - is a class that wraps timerfd and epoll POXIS APIs. It also
- both implements LocRunnalbe with epoll_wait() in the run()
- method. It is also a LocThread client, so as to loop the run
- method.
- LocTimerWrapper - a LocTimer client itself, to implement the existing C API with
- APIs, loc_timer_start() and loc_timer_stop().
- */
- class LocTimerPollTask;
- // This is a multi-functaional class that:
- // * extends the LocHeap class for the detection of head update upon add / remove
- // events. When that happens, soonest time out changes, so timerfd needs update.
- // * contains the timers, and add / remove them into the heap
- // * provides and maps 2 of such containers, one for timers (or mSwTimers), one
- // for alarms (or mHwTimers);
- // * provides a polling thread;
- // * provides a MsgTask thread for synchronized add / remove / timer client callback.
- class LocTimerContainer : public LocHeap {
- // mutex to synchronize getters of static members
- static pthread_mutex_t mMutex;
- // Container of timers
- static LocTimerContainer* mSwTimers;
- // Container of alarms
- static LocTimerContainer* mHwTimers;
- // Msg task to provider msg Q, sender and reader.
- static MsgTask* mMsgTask;
- // Poll task to provide epoll call and threading to poll.
- static LocTimerPollTask* mPollTask;
- // timer / alarm fd
- int mDevFd;
- // ctor
- LocTimerContainer(bool wakeOnExpire);
- // dtor
- ~LocTimerContainer();
- static MsgTask* getMsgTaskLocked();
- static LocTimerPollTask* getPollTaskLocked();
- // extend LocHeap and pop if the top outRanks input
- LocTimerDelegate* popIfOutRanks(LocTimerDelegate& timer);
- // update the timer POSIX calls with updated soonest timer spec
- void updateSoonestTime(LocTimerDelegate* priorTop);
- public:
- // factory method to control the creation of mSwTimers / mHwTimers
- static LocTimerContainer* get(bool wakeOnExpire);
- LocTimerDelegate* getSoonestTimer();
- int getTimerFd();
- // add a timer / alarm obj into the container
- void add(LocTimerDelegate& timer);
- // remove a timer / alarm obj from the container
- void remove(LocTimerDelegate& timer);
- // handling of timer / alarm expiration
- void expire();
- };
- class TimerRunnable : public LocRunnable {
- const int mFd;
- public:
- inline TimerRunnable(const int fd) : mFd(fd) {}
- // The method to be implemented by thread clients
- // and be scheduled by LocThread
- // This method will be repeated called until it returns false; or
- // until thread is stopped.
- virtual bool run() override;
- // The method to wake up the potential blocking thread
- // no op if not applicable
- inline virtual void interrupt() { close(mFd); }
- };
- // This class implements the polling thread that epolls imer / alarm fds.
- // The LocRunnable::run() contains the actual polling. The other methods
- // will be run in the caller's thread context to add / remove timer / alarm
- // fds the kernel, while the polling is blocked on epoll_wait() call.
- // Since the design is that we have maximally 2 polls, one for all the
- // timers; one for all the alarms, we will poll at most on 2 fds. But it
- // is possile that all we have are only timers or alarms at one time, so we
- // allow dynamically add / remove fds we poll on. The design decision of
- // having 1 fd per container of timer / alarm is such that, we may not need
- // to make a system call each time a timer / alarm is added / removed, unless
- // that changes the "soonest" time out of that of all the timers / alarms.
- class LocTimerPollTask {
- // the epoll fd
- const int mFd;
- // the thread that calls TimerRunnable::run() method, where
- // epoll_wait() is blocking and waiting for events..
- LocThread mThread;
- public:
- // ctor
- LocTimerPollTask();
- // dtor
- ~LocTimerPollTask() = default;
- // add a container of timers. Each contain has a unique device fd, i.e.
- // either timer or alarm fd, and a heap of timers / alarms. It is expected
- // that container would have written to the device fd with the soonest
- // time out value in the heap at the time of calling this method. So all
- // this method does is to add the fd of the input container to the poll
- // and also add the pointer of the container to the event data ptr, such
- // when poll_wait wakes up on events, we know who is the owner of the fd.
- void addPoll(LocTimerContainer& timerContainer);
- // remove a fd that is assciated with a container. The expectation is that
- // the atual timer would have been removed from the container.
- void removePoll(LocTimerContainer& timerContainer);
- };
- // Internal class of timer obj. It gets born when client calls LocTimer::start();
- // and gets deleted when client calls LocTimer::stop() or when the it expire()'s.
- // This class implements LocRankable::ranks() so that when an obj is added into
- // the container (of LocHeap), it gets placed in sorted order.
- class LocTimerDelegate : public LocRankable {
- friend class LocTimerContainer;
- friend class LocTimer;
- LocTimer* mClient;
- LocSharedLock* mLock;
- struct timespec mFutureTime;
- LocTimerContainer* mContainer;
- // not a complete obj, just ctor for LocRankable comparisons
- inline LocTimerDelegate(struct timespec& delay)
- : mClient(NULL), mLock(NULL), mFutureTime(delay), mContainer(NULL) {}
- inline ~LocTimerDelegate() { if (mLock) { mLock->drop(); mLock = NULL; } }
- public:
- LocTimerDelegate(LocTimer& client, struct timespec& futureTime, LocTimerContainer* container);
- void destroyLocked();
- // LocRankable virtual method
- virtual int ranks(LocRankable& rankable);
- void expire();
- inline struct timespec getFutureTime() { return mFutureTime; }
- };
- /***************************LocTimerContainer methods***************************/
- // Most of these static recources are created on demand. They however are never
- // destoyed. The theory is that there are processes that link to this util lib
- // but never use timer, then these resources would never need to be created.
- // For those processes that do use timer, it will likely also need to every
- // once in a while. It might be cheaper keeping them around.
- pthread_mutex_t LocTimerContainer::mMutex = PTHREAD_MUTEX_INITIALIZER;
- LocTimerContainer* LocTimerContainer::mSwTimers = NULL;
- LocTimerContainer* LocTimerContainer::mHwTimers = NULL;
- MsgTask* LocTimerContainer::mMsgTask = NULL;
- LocTimerPollTask* LocTimerContainer::mPollTask = NULL;
- // ctor - initialize timer heaps
- // A container for swTimer (timer) is created, when wakeOnExpire is true; or
- // HwTimer (alarm), when wakeOnExpire is false.
- LocTimerContainer::LocTimerContainer(bool wakeOnExpire) :
- mDevFd(timerfd_create(wakeOnExpire ? CLOCK_BOOTTIME_ALARM : CLOCK_BOOTTIME, 0)) {
- if ((-1 == mDevFd) && (errno == EINVAL)) {
- LOC_LOGW("%s: timerfd_create failure, fallback to CLOCK_MONOTONIC - %s",
- __FUNCTION__, strerror(errno));
- mDevFd = timerfd_create(CLOCK_MONOTONIC, 0);
- }
- if (-1 != mDevFd) {
- // ensure we have the necessary resources created
- LocTimerContainer::getPollTaskLocked();
- LocTimerContainer::getMsgTaskLocked();
- } else {
- LOC_LOGE("%s: timerfd_create failure - %s", __FUNCTION__, strerror(errno));
- }
- }
- // dtor
- // we do not ever destroy the static resources.
- inline
- LocTimerContainer::~LocTimerContainer() {
- close(mDevFd);
- }
- LocTimerContainer* LocTimerContainer::get(bool wakeOnExpire) {
- // get the reference of either mHwTimer or mSwTimers per wakeOnExpire
- LocTimerContainer*& container = wakeOnExpire ? mHwTimers : mSwTimers;
- // it is cheap to check pointer first than locking mutext unconditionally
- if (!container) {
- pthread_mutex_lock(&mMutex);
- // let's check one more time to be safe
- if (!container) {
- container = new LocTimerContainer(wakeOnExpire);
- // timerfd_create failure
- if (-1 == container->getTimerFd()) {
- delete container;
- container = NULL;
- }
- }
- pthread_mutex_unlock(&mMutex);
- }
- return container;
- }
- MsgTask* LocTimerContainer::getMsgTaskLocked() {
- // it is cheap to check pointer first than locking mutext unconditionally
- if (!mMsgTask) {
- mMsgTask = new MsgTask("LocTimerMsgTask");
- }
- return mMsgTask;
- }
- LocTimerPollTask* LocTimerContainer::getPollTaskLocked() {
- // it is cheap to check pointer first than locking mutext unconditionally
- if (!mPollTask) {
- mPollTask = new LocTimerPollTask();
- }
- return mPollTask;
- }
- inline
- LocTimerDelegate* LocTimerContainer::getSoonestTimer() {
- return (LocTimerDelegate*)(peek());
- }
- inline
- int LocTimerContainer::getTimerFd() {
- return mDevFd;
- }
- void LocTimerContainer::updateSoonestTime(LocTimerDelegate* priorTop) {
- LocTimerDelegate* curTop = getSoonestTimer();
- // check if top has changed
- if (curTop != priorTop) {
- struct itimerspec delay;
- memset(&delay, 0, sizeof(struct itimerspec));
- bool toSetTime = false;
- // if tree is empty now, we remove poll and disarm timer
- if (!curTop) {
- mPollTask->removePoll(*this);
- // setting the values to disarm timer
- delay.it_value.tv_sec = 0;
- delay.it_value.tv_nsec = 0;
- toSetTime = true;
- } else if (!priorTop || curTop->outRanks(*priorTop)) {
- // do this first to avoid race condition, in case settime is called
- // with too small an interval
- mPollTask->addPoll(*this);
- delay.it_value = curTop->getFutureTime();
- toSetTime = true;
- }
- if (toSetTime) {
- timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL);
- }
- }
- }
- // all the heap management is done in the MsgTask context.
- inline
- void LocTimerContainer::add(LocTimerDelegate& timer) {
- struct MsgTimerPush : public LocMsg {
- LocTimerContainer* mTimerContainer;
- LocTimerDelegate* mTimer;
- inline MsgTimerPush(LocTimerContainer& container, LocTimerDelegate& timer) :
- LocMsg(), mTimerContainer(&container), mTimer(&timer) {}
- inline virtual void proc() const {
- LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer();
- mTimerContainer->push((LocRankable&)(*mTimer));
- mTimerContainer->updateSoonestTime(priorTop);
- }
- };
- mMsgTask->sendMsg(new MsgTimerPush(*this, timer));
- }
- // all the heap management is done in the MsgTask context.
- void LocTimerContainer::remove(LocTimerDelegate& timer) {
- struct MsgTimerRemove : public LocMsg {
- LocTimerContainer* mTimerContainer;
- LocTimerDelegate* mTimer;
- inline MsgTimerRemove(LocTimerContainer& container, LocTimerDelegate& timer) :
- LocMsg(), mTimerContainer(&container), mTimer(&timer) {}
- inline virtual void proc() const {
- LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer();
- // update soonest timer only if mTimer is actually removed from
- // mTimerContainer AND mTimer is not priorTop.
- if (priorTop == ((LocHeap*)mTimerContainer)->remove((LocRankable&)*mTimer)) {
- // if passing in NULL, we tell updateSoonestTime to update
- // kernel with the current top timer interval.
- mTimerContainer->updateSoonestTime(NULL);
- }
- // all timers are deleted here, and only here.
- delete mTimer;
- }
- };
- mMsgTask->sendMsg(new MsgTimerRemove(*this, timer));
- }
- // all the heap management is done in the MsgTask context.
- // Upon expire, we check and continuously pop the heap until
- // the top node's timeout is in the future.
- void LocTimerContainer::expire() {
- struct MsgTimerExpire : public LocMsg {
- LocTimerContainer* mTimerContainer;
- inline MsgTimerExpire(LocTimerContainer& container) :
- LocMsg(), mTimerContainer(&container) {}
- inline virtual void proc() const {
- struct timespec now = {};
- // get time spec of now
- clock_gettime(CLOCK_BOOTTIME, &now);
- LocTimerDelegate timerOfNow(now);
- // pop everything in the heap that outRanks now, i.e. has time older than now
- // and then call expire() on that timer.
- for (LocTimerDelegate* timer = (LocTimerDelegate*)mTimerContainer->pop();
- NULL != timer;
- timer = mTimerContainer->popIfOutRanks(timerOfNow)) {
- // the timer delegate obj will be deleted before the return of this call
- timer->expire();
- }
- mTimerContainer->updateSoonestTime(NULL);
- }
- };
- struct itimerspec delay;
- memset(&delay, 0, sizeof(struct itimerspec));
- timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL);
- mPollTask->removePoll(*this);
- mMsgTask->sendMsg(new MsgTimerExpire(*this));
- }
- LocTimerDelegate* LocTimerContainer::popIfOutRanks(LocTimerDelegate& timer) {
- LocTimerDelegate* poppedNode = NULL;
- if (mTree && !timer.outRanks(*peek())) {
- poppedNode = (LocTimerDelegate*)(pop());
- }
- return poppedNode;
- }
- /***************************LocTimerPollTask methods***************************/
- inline
- LocTimerPollTask::LocTimerPollTask()
- : mFd(epoll_create(2)), mThread() {
- // before a next call returens, a thread will be created. The run() method
- // could already be running in parallel. Also, since each of the objs
- // creates a thread, the container will make sure that there will be only
- // one of such obj for our timer implementation.
- mThread.start("LocTimerPollTask", std::make_shared<TimerRunnable>(mFd));
- }
- void LocTimerPollTask::addPoll(LocTimerContainer& timerContainer) {
- struct epoll_event ev;
- memset(&ev, 0, sizeof(ev));
- ev.events = EPOLLIN;
- ev.data.fd = timerContainer.getTimerFd();
- // it is important that we set this context pointer with the input
- // timer container this is how we know which container should handle
- // which expiration.
- ev.data.ptr = &timerContainer;
- epoll_ctl(mFd, EPOLL_CTL_ADD, timerContainer.getTimerFd(), &ev);
- }
- inline
- void LocTimerPollTask::removePoll(LocTimerContainer& timerContainer) {
- epoll_ctl(mFd, EPOLL_CTL_DEL, timerContainer.getTimerFd(), NULL);
- }
- // The polling thread context will call this method. If run() method needs to
- // be repetitvely called, it must return true from the previous call.
- bool TimerRunnable::run() {
- struct epoll_event ev[2];
- // we have max 2 descriptors to poll from
- int fds = epoll_wait(mFd, ev, 2, -1);
- // we pretty much want to continually poll until the fd is closed
- bool rerun = (fds > 0) || (errno == EINTR);
- if (fds > 0) {
- // we may have 2 events
- for (int i = 0; i < fds; i++) {
- // each fd has a context pointer associated with the right timer container
- LocTimerContainer* container = (LocTimerContainer*)(ev[i].data.ptr);
- if (container) {
- container->expire();
- } else {
- epoll_ctl(mFd, EPOLL_CTL_DEL, ev[i].data.fd, NULL);
- }
- }
- }
- // if rerun is true, we are requesting to be scheduled again
- return rerun;
- }
- /***************************LocTimerDelegate methods***************************/
- inline
- LocTimerDelegate::LocTimerDelegate(LocTimer& client,
- struct timespec& futureTime,
- LocTimerContainer* container)
- : mClient(&client),
- mLock(mClient->mLock->share()),
- mFutureTime(futureTime),
- mContainer(container) {
- // adding the timer into the container
- mContainer->add(*this);
- }
- inline
- void LocTimerDelegate::destroyLocked() {
- // client handle will likely be deleted soon after this
- // method returns. Nulling this handle so that expire()
- // won't call the callback on the dead handle any more.
- mClient = NULL;
- if (mContainer) {
- LocTimerContainer* container = mContainer;
- mContainer = NULL;
- if (container) {
- container->remove(*this);
- }
- } // else we do not do anything. No such *this* can be
- // created and reached here with mContainer ever been
- // a non NULL. So *this* must have reached the if clause
- // once, and we want it reach there only once.
- }
- int LocTimerDelegate::ranks(LocRankable& rankable) {
- int rank = -1;
- LocTimerDelegate* timer = (LocTimerDelegate*)(&rankable);
- if (timer) {
- // larger time ranks lower!!!
- // IOW, if input obj has bigger tv_sec/tv_nsec, this obj outRanks higher
- rank = timer->mFutureTime.tv_sec - mFutureTime.tv_sec;
- if(0 == rank)
- {
- //rank against tv_nsec for msec accuracy
- rank = (int)(timer->mFutureTime.tv_nsec - mFutureTime.tv_nsec);
- }
- }
- return rank;
- }
- inline
- void LocTimerDelegate::expire() {
- // keeping a copy of client pointer to be safe
- // when timeOutCallback() is called at the end of this
- // method, *this* obj may be already deleted.
- LocTimer* client = mClient;
- // force a stop, which will lead to delete of this obj
- if (client && client->stop()) {
- // calling client callback with a pointer save on the stack
- // only if stop() returns true, i.e. it hasn't been stopped
- // already.
- client->timeOutCallback();
- }
- }
- /***************************LocTimer methods***************************/
- LocTimer::LocTimer() : mTimer(NULL), mLock(new LocSharedLock()) {
- }
- LocTimer::~LocTimer() {
- stop();
- if (mLock) {
- mLock->drop();
- mLock = NULL;
- }
- }
- bool LocTimer::start(unsigned int timeOutInMs, bool wakeOnExpire) {
- bool success = false;
- mLock->lock();
- if (!mTimer) {
- struct timespec futureTime = {};
- clock_gettime(CLOCK_BOOTTIME, &futureTime);
- futureTime.tv_sec += timeOutInMs / 1000;
- futureTime.tv_nsec += (timeOutInMs % 1000) * 1000000;
- if (futureTime.tv_nsec >= 1000000000) {
- futureTime.tv_sec += futureTime.tv_nsec / 1000000000;
- futureTime.tv_nsec %= 1000000000;
- }
- LocTimerContainer* container;
- container = LocTimerContainer::get(wakeOnExpire);
- if (NULL != container) {
- mTimer = new LocTimerDelegate(*this, futureTime, container);
- // if mTimer is non 0, success should be 0; or vice versa
- }
- success = (NULL != mTimer);
- }
- mLock->unlock();
- return success;
- }
- bool LocTimer::stop() {
- bool success = false;
- mLock->lock();
- if (mTimer) {
- LocTimerDelegate* timer = mTimer;
- mTimer = NULL;
- if (timer) {
- timer->destroyLocked();
- success = true;
- }
- }
- mLock->unlock();
- return success;
- }
- /***************************LocTimerWrapper methods***************************/
- //////////////////////////////////////////////////////////////////////////
- // This section below wraps for the C style APIs
- //////////////////////////////////////////////////////////////////////////
- class LocTimerWrapper : public LocTimer {
- loc_timer_callback mCb;
- void* mCallerData;
- LocTimerWrapper* mMe;
- static pthread_mutex_t mMutex;
- inline ~LocTimerWrapper() { mCb = NULL; mMe = NULL; }
- public:
- inline LocTimerWrapper(loc_timer_callback cb, void* callerData) :
- mCb(cb), mCallerData(callerData), mMe(this) {
- }
- void destroy() {
- pthread_mutex_lock(&mMutex);
- if (NULL != mCb && this == mMe) {
- delete this;
- }
- pthread_mutex_unlock(&mMutex);
- }
- virtual void timeOutCallback() {
- loc_timer_callback cb = mCb;
- void* callerData = mCallerData;
- if (cb) {
- cb(callerData, 0);
- }
- destroy();
- }
- };
- } // namespace loc_util
- //////////////////////////////////////////////////////////////////////////
- // This section below wraps for the C style APIs
- //////////////////////////////////////////////////////////////////////////
- using loc_util::LocTimerWrapper;
- pthread_mutex_t LocTimerWrapper::mMutex = PTHREAD_MUTEX_INITIALIZER;
- void* loc_timer_start(uint64_t msec, loc_timer_callback cb_func,
- void *caller_data, bool wake_on_expire)
- {
- LocTimerWrapper* locTimerWrapper = NULL;
- if (cb_func) {
- locTimerWrapper = new LocTimerWrapper(cb_func, caller_data);
- if (locTimerWrapper) {
- locTimerWrapper->start(msec, wake_on_expire);
- }
- }
- return locTimerWrapper;
- }
- void loc_timer_stop(void*& handle)
- {
- if (handle) {
- LocTimerWrapper* locTimerWrapper = (LocTimerWrapper*)(handle);
- locTimerWrapper->destroy();
- handle = NULL;
- }
- }
|