]> granicus.if.org Git - libevent/commitdiff
Use mach_absolute_time() for monotonic clock support on OSX.
authorNick Mathewson <nickm@torproject.org>
Mon, 9 Apr 2012 17:39:11 +0000 (13:39 -0400)
committerNick Mathewson <nickm@torproject.org>
Mon, 9 Apr 2012 22:29:30 +0000 (18:29 -0400)
configure.in
event-internal.h
event.c

index bea4aaf344323a3f4a1f579dd6562692c06807a0..9bd2a2da9e525f9ecac7e677128ec08e7c4db3ca 100644 (file)
@@ -198,6 +198,7 @@ AC_CHECK_HEADERS([ \
   fcntl.h \
   ifaddrs.h \
   inttypes.h \
+  mach/mach_time.h \
   netdb.h \
   netinet/in.h \
   netinet/in6.h \
@@ -339,6 +340,7 @@ AC_CHECK_FUNCS([ \
   inet_ntop \
   inet_pton \
   issetugid \
+  mach_absolute_time \
   mmap \
   nanosleep \
   pipe \
index 78b3fe63acfa2c28f0f8a0e350ecbd1233a793bb..d2533fa419f6d9598617dcad5eb603fe29efe755 100644 (file)
@@ -58,6 +58,14 @@ extern "C" {
 #define EV_CLOSURE_SIGNAL 1
 #define EV_CLOSURE_PERSIST 2
 
+/* Define HAVE_ANY_MONOTONIC iff we *might* have a working monotonic
+ * clock implementation */
+#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#define HAVE_ANY_MONOTONIC 1
+#elif defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
+#define HAVE_ANY_MONOTONIC 1
+#endif
+
 /** Structure to define the backend of a given event_base. */
 struct eventop {
        /** The name of this backend. */
@@ -243,7 +251,7 @@ struct event_base {
         * too often. */
        struct timeval tv_cache;
 
-#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#if defined(HAVE_ANY_MONOTONIC)
        /** Difference between internal time (maybe from clock_gettime) and
         * gettimeofday. */
        struct timeval tv_clock_diff;
diff --git a/event.c b/event.c
index 0f10b56976e3575ea451d7cce5e28f6dcf47d1e0..a85d1f5acf33dda59a749723b70303ec04b4b907 100644 (file)
--- a/event.c
+++ b/event.c
@@ -46,6 +46,9 @@
 #ifdef EVENT__HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#ifdef EVENT__HAVE_MACH_MACH_TIME_H
+#include <mach/mach_time.h>
+#endif
 #include <ctype.h>
 #include <errno.h>
 #include <signal.h>
@@ -335,23 +338,45 @@ HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
 #define EVENT_BASE_ASSERT_LOCKED(base)         \
        EVLOCK_ASSERT_LOCKED((base)->th_base_lock)
 
+#if defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
+struct mach_timebase_info mach_timebase_units;
+#endif
+
 /* The first time this function is called, it sets use_monotonic to 1
  * if we have a clock function that supports monotonic time */
 static void
 detect_monotonic(void)
 {
-#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
-       struct timespec ts;
        static int use_monotonic_initialized = 0;
-
        if (use_monotonic_initialized)
                return;
 
-       if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
-               use_monotonic = 1;
+#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+       {
+               /* CLOCK_MONOTONIC exists on FreeBSD, Linux, and Solaris.
+                * You need to check for it at runtime, because some older
+                * versions won't have it working. */
+               struct timespec ts;
 
-       use_monotonic_initialized = 1;
+               if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+                       use_monotonic = 1;
+       }
+#elif defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
+       {
+               struct mach_timebase_info mi;
+               /* OSX has mach_absolute_time() */
+               if (mach_timebase_info(&mi) == 0 && mach_absolute_time() != 0) {
+                       use_monotonic = 1;
+                       /* mach_timebase_info tells us how to convert
+                        * mach_absolute_time() into nanoseconds, but we
+                        * want to use microseconds instead. */
+                       mi.denom *= 1000;
+                       memcpy(&mach_timebase_units, &mi, sizeof(mi));
+               }
+       }
 #endif
+       use_monotonic_initialized = 1;
+
 }
 
 /* How often (in seconds) do we check for changes in wall clock time relative
@@ -373,26 +398,34 @@ gettime(struct event_base *base, struct timeval *tp)
                return (0);
        }
 
-#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
        if (use_monotonic) {
+#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
                struct timespec ts;
-
                if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
                        return (-1);
 
                tp->tv_sec = ts.tv_sec;
                tp->tv_usec = ts.tv_nsec / 1000;
+#elif defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
+               uint64_t abstime = mach_absolute_time();
+               uint64_t usec;
+               usec = (abstime * mach_timebase_units.numer)
+                   / (mach_timebase_units.denom);
+               tp->tv_sec = usec / 1000000;
+               tp->tv_usec = usec % 1000000;
+#else
+#error "Missing monotonic time implementation."
+#endif
                if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL
-                   < ts.tv_sec) {
+                   < tp->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;
+                       base->last_updated_clock_diff = tp->tv_sec;
                }
 
                return (0);
        }
-#endif
 
        return (evutil_gettimeofday(tp, NULL));
 }
@@ -411,7 +444,7 @@ event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv)
        if (base->tv_cache.tv_sec == 0) {
                r = evutil_gettimeofday(tv, NULL);
        } else {
-#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#ifdef HAVE_ANY_MONOTONIC
                evutil_timeradd(&base->tv_cache, &base->tv_clock_diff, tv);
 #else
                *tv = base->tv_cache;
@@ -2014,7 +2047,7 @@ event_pending(const struct event *ev, short event, struct timeval *tv)
        if (tv != NULL && (flags & event & EV_TIMEOUT)) {
                struct timeval tmp = ev->ev_timeout;
                tmp.tv_usec &= MICROSECONDS_MASK;
-#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#ifdef HAVE_ANY_MONOTONIC
                /* correctly remamp to real time */
                evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv);
 #else
@@ -3125,7 +3158,7 @@ dump_inserted_event_fn(struct event_base *base, struct event *e, void *arg)
                struct timeval tv;
                tv.tv_sec = e->ev_timeout.tv_sec;
                tv.tv_usec = e->ev_timeout.tv_usec & MICROSECONDS_MASK;
-#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#if defined(HAVE_ANY_MONOTONIC)
                evutil_timeradd(&tv, &base->tv_clock_diff, &tv);
 #endif
                fprintf(output, " Timeout=%ld.%06d",