]> granicus.if.org Git - libevent/commitdiff
Use GetSystemTimeAsFileTime to implement gettimeofday on win32.
authorNick Mathewson <nickm@torproject.org>
Thu, 2 Sep 2010 21:52:20 +0000 (17:52 -0400)
committerNick Mathewson <nickm@torproject.org>
Thu, 16 Dec 2010 18:26:01 +0000 (13:26 -0500)
It is (in my benchmarks) way faster than _ftime, though the
conversion process is not so straightforward.  In theory, it can
have a better granularity too, though in practice who knows what
you're getting.

evutil.c

index b769acc2b323fa7f90a42074d5bc81af8b395e06..2cb333704cbfce9d7bc26412520c27cfa59777e2 100644 (file)
--- a/evutil.c
+++ b/evutil.c
@@ -364,26 +364,41 @@ evutil_strtoll(const char *s, char **endptr, int base)
 }
 
 #ifndef _EVENT_HAVE_GETTIMEOFDAY
-/* No gettimeofday; this muse be windows. */
+/* No gettimeofday; this must be windows. */
 int
 evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
-       struct _timeb tb;
+#ifdef _MSC_VER
+#define U64_LITERAL(n) n##ui64
+#else
+#define U64_LITERAL(n) n##llu
+#endif
+
+       /* Conversion logic taken from Tor, which in turn took it
+        * from Perl.  GetSystemTimeAsFileTime returns its value as
+        * an unaligned (!) 64-bit value containing the number of
+        * 100-nanosecond intervals since 1 January 1601 UTC. */
+#define EPOCH_BIAS U64_LITERAL(116444736000000000)
+#define UNITS_PER_SEC U64_LITERAL(10000000)
+#define USEC_PER_SEC U64_LITERAL(1000000)
+#define UNITS_PER_USEC U64_LITERAL(10)
+       union {
+               FILETIME ft_ft;
+               ev_uint64_t ft_64;
+       } ft;
 
        if (tv == NULL)
                return -1;
 
-       /* XXXX
-        * _ftime is not the greatest interface here; GetSystemTimeAsFileTime
-        * would give us better resolution, whereas something cobbled together
-        * with GetTickCount could maybe give us monotonic behavior.
-        *
-        * Either way, I think this value might be skewed to ignore the
-        * timezone, and just return local time.  That's not so good.
-        */
-       _ftime(&tb);
-       tv->tv_sec = (long) tb.time;
-       tv->tv_usec = ((int) tb.millitm) * 1000;
+       GetSystemTimeAsFileTime(&ft.ft_ft);
+
+       if (EVUTIL_UNLIKELY(ft.ft_64 < EPOCH_BIAS)) {
+               /* Time before the unix epoch. */
+               return -1;
+       }
+       ft.ft_64 -= EPOCH_BIAS;
+       tv->tv_sec = (long) (ft.ft_64 / UNITS_PER_SEC);
+       tv->tv_usec = (long) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
        return 0;
 }
 #endif