Use mach_absolute_time() for monotonic clock support on OSX.

This commit is contained in:
Nick Mathewson 2012-04-09 13:39:11 -04:00
parent a969f7e706
commit b8fd6f918b
3 changed files with 58 additions and 15 deletions

View 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 \

View 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;

59
event.c
View File

@ -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 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;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
use_monotonic = 1;
use_monotonic_initialized = 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",