Permalink
Browse files

Use GetSystemTimeAsFileTime to implement gettimeofday on win32.

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.
  • Loading branch information...
1 parent 04ba27e commit b8b8aa560c038c6f0c22a574d99d314a1f4a3b7a Nick Mathewson committed Sep 2, 2010
Showing with 28 additions and 13 deletions.
  1. +28 −13 evutil.c
View
@@ -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

0 comments on commit b8b8aa5

Please sign in to comment.