#include #include "evloop.h" #include "timeheap.h" #if defined(HAVE_CLOCK_MONOTONIC) #ifdef CLOCK_MONOTONIC_FAST #define TIMER_CLOCK CLOCK_MONOTONIC_FAST #else #define TIMER_CLOCK CLOCK_MONOTONIC #endif int evtimer_gettime(struct timespec *ts) { return clock_gettime(TIMER_CLOCK, ts); } #elif defined(HAVE_MACH_ABSOLUTE_TIME) #include int evtimer_gettime(struct timespec *ts) { uint64_t nsecs; static double nsmul; static mach_timebase_info_data_t nsratio = { 0, 0 }; if (nsratio.denom == 0) { mach_timebase_info(&nsratio); nsmul = (double)nsratio.numer / nsratio.denom; } nsecs = mach_absolute_time() * nsmul; ts->tv_sec = nsecs / 1000000000ULL; ts->tv_nsec = nsecs - ts->tv_sec * 1000000000ULL; return 0; } #else #error No supported time mechanism #endif static struct timespec addtime(struct timespec a, struct timespec b) { struct timespec ret; ret.tv_sec = a.tv_sec + b.tv_sec; ret.tv_nsec = a.tv_nsec + b.tv_nsec; if (ret.tv_nsec >= 1000000000) { ret.tv_sec += 1; ret.tv_nsec -= 1000000000; } return ret; } static struct timespec subtime(struct timespec a, struct timespec b) { struct timespec ret; ret.tv_sec = a.tv_sec - b.tv_sec; ret.tv_nsec = a.tv_nsec - b.tv_nsec; if (ret.tv_nsec < 0) { ret.tv_sec -= 1; ret.tv_nsec += 1000000000; } return ret; } void evtimer_init(struct timeout *h, evloop_cb_t cb, void *arg) { h->cb = cb; h->arg = arg; h->th.i = -1; h->th.data = h; } int evtimer_add(struct timeout *h, struct timespec *t) { struct timespec now, sum; evtimer_gettime(&now); sum = addtime(now, *t); if (h->th.i == -1) return timeheap_insert(&h->th, &sum); else { timeheap_change(&h->th, &sum); return 0; } } void evtimer_del(struct timeout *h) { if (h->th.i >= 0) { timeheap_remove(&h->th); h->th.i = -1; } } void evtimers_run(void) { struct timespec now; evtimer_gettime(&now); while (timeheap_size() > 0) { struct timespec diff = subtime(timeheap_top(), now); if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec < 1000000)) { struct timeout *t = timeheap_remove_top(); t->th.i = -1; t->cb(-1, EV_TIMEOUT, t->arg); } else break; } } struct timespec evtimer_delay(void) { struct timespec now, diff; if (timeheap_size() == 0) { diff.tv_sec = -1; diff.tv_nsec = 0; } else { evtimer_gettime(&now); diff = subtime(timeheap_top(), now); if (diff.tv_sec < 0) { diff.tv_sec = 0; diff.tv_nsec = 0; } } return diff; }