]> granicus.if.org Git - libevent/commitdiff
Simple unit tests for monotonic timers
authorNick Mathewson <nickm@torproject.org>
Thu, 26 Apr 2012 15:56:59 +0000 (11:56 -0400)
committerNick Mathewson <nickm@torproject.org>
Thu, 26 Apr 2012 20:42:21 +0000 (16:42 -0400)
event.c
evutil_time.c
test/regress_util.c
time-internal.h

diff --git a/event.c b/event.c
index 7ba39a7d02e94424c79c202dac7767c9aebbd888..b41706cc9e93f069804e29c20853e5949bf46dd7 100644 (file)
--- a/event.c
+++ b/event.c
@@ -560,6 +560,9 @@ 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));
 
@@ -567,9 +570,13 @@ event_base_new_with_config(const struct event_config *cfg)
                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);
index 5125f21823d4d2b7a2e82c45ba8d58523f094f01..7b2043bd5be73c34a1e458cf4e28bc4549b6df46 100644 (file)
@@ -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,12 +172,15 @@ 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
@@ -181,14 +188,14 @@ evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
         * 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;
index 38b91cf6e8b6d88a86f53ca4bd0953cdab8ef1ae..b36af1a541825ddcb68e166ba787d64cf6e38495 100644 (file)
@@ -1218,6 +1218,66 @@ end:
        ;
 }
 
+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,
 };
 
index a889925c142236a64b5cbb8e378d43103f9359d7..daf20f47a30ebf7f5e2aad5bc7a2efb00b969f27 100644 (file)
@@ -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);