From a459ef70ec82eaa07680b0a4bc25e5d05efcc6fb Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 3 Mar 2011 15:34:22 -0500 Subject: [PATCH] Have event_base_gettimeofday_cached() always return wall-clock time Based on code by Dave Hart --- event-internal.h | 12 +++++++++++- event.c | 35 ++++++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/event-internal.h b/event-internal.h index e3da33da..12ca8bc1 100644 --- a/event-internal.h +++ b/event-internal.h @@ -32,6 +32,7 @@ extern "C" { #endif #include "event2/event-config.h" +#include #include #include "event2/event_struct.h" #include "minheap-internal.h" @@ -235,9 +236,18 @@ struct event_base { /** Priority queue of events with timeouts. */ struct min_heap timeheap; - /** Stored timeval: used to avoid calling gettimeofday too often. */ + /** Stored timeval: used to avoid calling gettimeofday/clock_gettime + * too often. */ struct timeval tv_cache; +#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + /** Difference between internal time (maybe from clock_gettime) and + * gettimeofday. */ + struct timeval tv_clock_diff; + /** Second in which we last updated tv_clock_diff, in monotonic time. */ + time_t last_updated_clock_diff; +#endif + #ifndef _EVENT_DISABLE_THREAD_SUPPORT /* threading support */ /** The thread currently running the event_loop for this base */ diff --git a/event.c b/event.c index fedb9c73..2469c44a 100644 --- a/event.c +++ b/event.c @@ -330,6 +330,10 @@ detect_monotonic(void) #endif } +/* How often (in seconds) do we check for changes in wall clock time relative + * to monotonic time? Set this to -1 for 'never.' */ +#define CLOCK_SYNC_INTERVAL 5 + /** Set 'tp' to the current time according to 'base'. We must hold the lock * on 'base'. If there is a cached time, return it. Otherwise, use * clock_gettime or gettimeofday as appropriate to find out the right time. @@ -354,6 +358,14 @@ gettime(struct event_base *base, struct timeval *tp) tp->tv_sec = ts.tv_sec; tp->tv_usec = ts.tv_nsec / 1000; + if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL + < ts.tv_sec) { + struct timeval tv; + evutil_gettimeofday(&tv,NULL); + evutil_timersub(&tv, tp, &base->tv_clock_diff); + base->last_updated_clock_diff = ts.tv_sec; + } + return (0); } #endif @@ -372,7 +384,16 @@ event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv) } EVBASE_ACQUIRE_LOCK(base, th_base_lock); - r = gettime(base, tv); + if (base->tv_cache.tv_sec == 0) { + r = evutil_gettimeofday(tv, NULL); + } else { +#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + evutil_timeradd(&base->tv_cache, &base->tv_clock_diff, tv); +#else + *tv = base->tv_cache; +#endif + r = 0; + } EVBASE_RELEASE_LOCK(base, th_base_lock); return r; } @@ -1778,7 +1799,6 @@ event_priority_set(struct event *ev, int pri) int event_pending(const struct event *ev, short event, struct timeval *tv) { - struct timeval now, res; int flags = 0; _event_debug_assert_is_setup(ev); @@ -1795,12 +1815,13 @@ event_pending(const struct event *ev, short event, struct timeval *tv) /* See if there is a timeout that we should report */ if (tv != NULL && (flags & event & EV_TIMEOUT)) { struct timeval tmp = ev->ev_timeout; - event_base_gettimeofday_cached(ev->ev_base, &now); tmp.tv_usec &= MICROSECONDS_MASK; - evutil_timersub(&tmp, &now, &res); - /* correctly remap to real time */ - evutil_gettimeofday(&now, NULL); - evutil_timeradd(&now, &res, tv); +#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + /* correctly remamp to real time */ + evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv); +#else + *tv = tmp; +#endif } return (flags & event);