Permalink
Browse files

Simple unit tests for monotonic timers

  • Loading branch information...
1 parent 2c47045 commit 630f077c296de61c7b99ed83bf30de11e75e2740 Nick Mathewson committed Apr 26, 2012
Showing with 96 additions and 13 deletions.
  1. +9 −4 event.c
  2. +20 −8 evutil_time.c
  3. +63 −0 test/regress_util.c
  4. +4 −1 time-internal.h
View
13 event.c
@@ -560,16 +560,23 @@ event_base_new_with_config(const struct event_config *cfg)
return NULL;
}
+ if (cfg)
+ base->flags = cfg->flags;
+
should_check_environment =
!(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));
{
struct timeval tmp;
int precise_time =
cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);
- if (should_check_environment && !precise_time)
+ int flags;
+ if (should_check_environment && !precise_time) {
precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;
- evutil_configure_monotonic_time_(&base->monotonic_timer, precise_time);
+ base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
+ }
+ flags = precise_time ? EV_MONOT_PRECISE : 0;
+ evutil_configure_monotonic_time_(&base->monotonic_timer, flags);
gettime(base, &tmp);
}
@@ -585,8 +592,6 @@ event_base_new_with_config(const struct event_config *cfg)
base->defer_queue.base = base;
base->defer_queue.notify_fn = notify_base_cbq_callback;
base->defer_queue.notify_arg = base;
- if (cfg)
- base->flags = cfg->flags;
evmap_io_initmap_(&base->io);
evmap_signal_initmap_(&base->sigmap);
View
28 evutil_time.c
@@ -107,6 +107,10 @@ evutil_tv_to_msec_(const struct timeval *tv)
return (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
}
+/*
+ Replacement for usleep on platforms that don't have one. Not guaranteed to
+ be any more finegrained than 1 msec.
+ */
void
evutil_usleep_(const struct timeval *tv)
{
@@ -168,27 +172,30 @@ adjust_monotonic_time(struct evutil_monotonic_timer *base,
int
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
- int precise)
+ int flags)
{
/* CLOCK_MONOTONIC exists on FreeBSD, Linux, and Solaris. You need to
* check for it at runtime, because some older kernel versions won't
* have it working. */
+ const int precise = flags & EV_MONOT_PRECISE;
+ const int fallback = flags & EV_MONOT_FALLBACK;
struct timespec ts;
+
#ifdef CLOCK_MONOTONIC_COARSE
#if CLOCK_MONOTONIC_COARSE < 0
/* Technically speaking, nothing keeps CLOCK_* from being negative (as
* far as I know). This check and the one below make sure that it's
* safe for us to use -1 as an "unset" value. */
#error "I didn't expect CLOCK_MONOTONIC_COARSE to be < 0"
#endif
- if (! precise) {
+ if (! precise && ! fallback) {
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
base->monotonic_clock = CLOCK_MONOTONIC_COARSE;
return 0;
}
}
#endif
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ if (!fallback && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
base->monotonic_clock = CLOCK_MONOTONIC;
return 0;
}
@@ -237,12 +244,15 @@ evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
int
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
- int precise)
+ int flags)
{
+ const int fallback = flags & EV_MONOT_FALLBACK;
struct mach_timebase_info mi;
memset(base, 0, sizeof(*base));
/* OSX has mach_absolute_time() */
- if (mach_timebase_info(&mi) == 0 && mach_absolute_time() != 0) {
+ if (!fallback &&
+ mach_timebase_info(&mi) == 0 &&
+ mach_absolute_time() != 0) {
/* mach_timebase_info tells us how to convert
* mach_absolute_time() into nanoseconds, but we
* want to use microseconds instead. */
@@ -367,19 +377,21 @@ evutil_GetTickCount_(struct evutil_monotonic_timer *base)
int
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
- int precise)
+ int flags)
{
+ const int precise = flags & EV_MONOT_PRECISE;
+ const int fallback = flags & EV_MONOT_FALLBACK;
HANDLE h;
memset(base, 0, sizeof(*base));
h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
- if (h != NULL) {
+ if (h != NULL && !fallback) {
base->GetTickCount64_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount64");
base->GetTickCount_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount");
}
base->first_tick = base->last_tick_count = evutil_GetTickCount_(base);
- if (precise) {
+ if (precise && !fallback) {
LARGE_INTEGER freq;
if (QueryPerformanceFrequency(&freq)) {
LARGE_INTEGER counter;
View
63 test/regress_util.c
@@ -1218,6 +1218,66 @@ test_evutil_usleep(void *arg)
;
}
+static void
+test_evutil_monotonic(void *data_)
+{
+ /* Basic santity-test for monotonic timers. What we'd really like
+ * to do is make sure that they can't go backwards even when the
+ * system clock goes backwards. But we haven't got a good way to
+ * move the system clock backwards.
+ */
+ struct basic_test_data *data = data_;
+ struct evutil_monotonic_timer timer;
+ const int precise = strstr(data->setup_data, "precise") != NULL;
+ const int fallback = strstr(data->setup_data, "fallback") != NULL;
+ struct timeval tv[10], delay;
+ int total_diff = 0;
+
+ int flags = 0, wantres, acceptdiff, i;
+ if (precise)
+ flags |= EV_MONOT_PRECISE;
+ if (fallback)
+ flags |= EV_MONOT_FALLBACK;
+ if (precise || fallback) {
+#ifdef _WIN32
+ wantres = 10*1000;
+ acceptdiff = 1000;
+#else
+ wantres = 300;
+ acceptdiff = 100;
+#endif
+ } else {
+ wantres = 40*1000;
+ acceptdiff = 20*1000;
+ }
+
+ TT_BLATHER(("Precise = %d", precise));
+ TT_BLATHER(("Fallback = %d", fallback));
+
+ delay.tv_sec = 0;
+ delay.tv_usec = wantres;
+
+ tt_int_op(evutil_configure_monotonic_time_(&timer, flags), ==, 0);
+
+ for (i = 0; i < 10; ++i) {
+ evutil_gettime_monotonic_(&timer, &tv[i]);
+ evutil_usleep_(&delay);
+ }
+
+ for (i = 0; i < 9; ++i) {
+ struct timeval diff;
+ tt_assert(evutil_timercmp(&tv[i], &tv[i+1], <));
+ evutil_timersub(&tv[i+1], &tv[i], &diff);
+ tt_int_op(diff.tv_sec, ==, 0);
+ total_diff += diff.tv_usec;
+ TT_BLATHER(("Difference = %d", (int)diff.tv_usec));
+ }
+ tt_int_op(abs(total_diff/10 - wantres), <, acceptdiff);
+
+end:
+ ;
+}
+
struct testcase_t util_testcases[] = {
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
{ "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
@@ -1240,6 +1300,9 @@ struct testcase_t util_testcases[] = {
{ "mm_calloc", test_event_calloc, 0, NULL, NULL },
{ "mm_strdup", test_event_strdup, 0, NULL, NULL },
{ "usleep", test_evutil_usleep, 0, NULL, NULL },
+ { "monotonic", test_evutil_monotonic, 0, &basic_setup, (void*)"" },
+ { "monotonic_precise", test_evutil_monotonic, 0, &basic_setup, (void*)"precise" },
+ { "monotonic_fallback", test_evutil_monotonic, 0, &basic_setup, (void*)"fallback" },
END_OF_TESTCASES,
};
View
5 time-internal.h
@@ -86,8 +86,11 @@ struct evutil_monotonic_timer {
struct timeval last_time;
};
+#define EV_MONOT_PRECISE 1
+#define EV_MONOT_FALLBACK 2
+
int evutil_configure_monotonic_time_(struct evutil_monotonic_timer *mt,
- int precise);
+ int flags);
int evutil_gettime_monotonic_(struct evutil_monotonic_timer *mt, struct timeval *tv);

0 comments on commit 630f077

Please sign in to comment.