#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. */
* 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;
#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>
#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
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));
}
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;
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
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",