Merge branch '21_choose_monotonic'

This commit is contained in:
Nick Mathewson 2012-04-17 17:54:26 -04:00
commit 5595a79ff1
3 changed files with 73 additions and 30 deletions

View File

@ -36,6 +36,10 @@ extern "C" {
#include <time.h>
#include <sys/queue.h>
#ifdef EVENT__HAVE_MACH_MACH_TIME_H
/* For mach_timebase_info */
#include <mach/mach_time.h>
#endif
#include "event2/event_struct.h"
#include "minheap-internal.h"
#include "evsignal-internal.h"
@ -64,6 +68,8 @@ extern "C" {
#define HAVE_ANY_MONOTONIC 1
#elif defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
#define HAVE_ANY_MONOTONIC 1
#elif defined(_WIN32)
#define HAVE_ANY_MONOTONIC 1
#endif
/** Structure to define the backend of a given event_base. */
@ -251,7 +257,21 @@ struct event_base {
* too often. */
struct timeval tv_cache;
#if defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
struct mach_timebase_info mach_timebase_units;
#endif
#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) && defined(CLOCK_MONOTONIC_COARSE)
#define CLOCK_IS_SELECTED
int monotonic_clock;
#endif
#ifdef _WIN32
DWORD last_tick_count;
struct timeval adjust_tick_count;
#endif
#if defined(HAVE_ANY_MONOTONIC)
/** True iff we should use our system's monotonic time implementation */
/* TODO: Support systems where we don't need to detct monotonic time */
int use_monotonic;
/** Difference between internal time (maybe from clock_gettime) and
* gettimeofday. */
struct timeval tv_clock_diff;

74
event.c
View File

@ -46,9 +46,6 @@
#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>
@ -131,10 +128,6 @@ struct event_base *event_global_current_base_ = NULL;
/* Global state */
#ifdef HAVE_ANY_MONOTONIC
static int use_monotonic;
#endif
static void *event_self_cbarg_ptr_ = NULL;
/* Prototypes */
@ -345,19 +338,11 @@ 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 */
/* Set base->use_monotonic to 1 if we have a clock function that supports
* monotonic time */
static void
detect_monotonic(void)
detect_monotonic(struct event_base *base, const struct event_config *cfg)
{
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.
@ -365,25 +350,34 @@ detect_monotonic(void)
* versions won't have it working. */
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
use_monotonic = 1;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
base->use_monotonic = 1;
#ifdef CLOCK_IS_SELECTED
base->monotonic_clock = CLOCK_MONOTONIC;
if (cfg == NULL ||
!(cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER)) {
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0)
base->monotonic_clock = CLOCK_MONOTONIC_COARSE;
}
#endif
}
}
#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;
base->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));
memcpy(&base->mach_timebase_units, &mi, sizeof(mi));
}
}
#elif defined(_WIN32)
base->use_monotonic = 1;
#endif
use_monotonic_initialized = 1;
}
/* How often (in seconds) do we check for changes in wall clock time relative
@ -406,21 +400,43 @@ gettime(struct event_base *base, struct timeval *tp)
}
#ifdef HAVE_ANY_MONOTONIC
if (use_monotonic) {
if (base->use_monotonic) {
#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec ts;
#ifdef CLOCK_IS_SELECTED
if (clock_gettime(base->monotonic_clock, &ts) == -1)
return (-1);
#else
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
return (-1);
#endif
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);
usec = (abstime * base->mach_timebase_units.numer)
/ (base->mach_timebase_units.denom);
tp->tv_sec = usec / 1000000;
tp->tv_usec = usec % 1000000;
#elif defined(_WIN32)
/* TODO: Support GetTickCount64. */
/* TODO: Support alternate timer backends if the user asked
* for a high-precision timer. QueryPerformanceCounter is
* possibly a good idea, but it is also supposed to have
* reliability issues under various circumstances. */
DWORD ticks = GetTickCount();
if (ticks < base->last_tick_count) {
/* The 32-bit timer rolled over. Let's assume it only
* happened once. Add 2**32 msec to adjust_tick_count. */
const struct timeval tv_rollover = { 4294967, 296000 };
evutil_timeradd(&tv_rollover, &base->adjust_tick_count, &base->adjust_tick_count);
}
base->last_tick_count = ticks;
tp->tv_sec = ticks / 1000;
tp->tv_usec = (ticks % 1000) * 1000;
evutil_timeradd(tp, &base->adjust_tick_count, tp);
#else
#error "Missing monotonic time implementation."
#endif
@ -631,7 +647,7 @@ event_base_new_with_config(const struct event_config *cfg)
event_warn("%s: calloc", __func__);
return NULL;
}
detect_monotonic();
detect_monotonic(base, cfg);
gettime(base, &base->event_tv);
min_heap_ctor_(&base->timeheap);
@ -2621,7 +2637,7 @@ timeout_correct(struct event_base *base, struct timeval *tv)
int i;
#ifdef HAVE_ANY_MONOTONIC
if (use_monotonic)
if (base->use_monotonic)
return;
#endif

View File

@ -481,7 +481,14 @@ enum event_base_config_flag {
This flag has no effect if you wind up using a backend other than
epoll.
*/
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
/** Ordinarily, Libevent implements its time and timeout code using
the fastest monotonic timer that we have. If this flag is set,
however, we use less efficient more precise timer, assuming one is
present.
*/
EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};
/**