gettimeofday should provide the same time resolution as utime.
2017-04-30 Bruno Haible <br...@clisp.org> gettimeofday: Provide higher resolution on native Windows. * lib/gettimeofday.c: Don't include <sys/timeb.h>. (GetSystemTimePreciseAsFileTimeFuncType): New variable. (initialize): Initialize it. (gettimeofday) [WINDOWS_NATIVE]: Use it, and convert from FILETIME to 'struct timeval'. Don't use _ftime(). * m4/gettimeofday.m4 (gl_PREREQ_GETTIMEOFDAY): Don't test for <sys/timeb.h> and _ftime. diff --git a/lib/gettimeofday.c b/lib/gettimeofday.c index d6117bd..a4a71a7 100644 --- a/lib/gettimeofday.c +++ b/lib/gettimeofday.c @@ -24,8 +24,9 @@ #include <time.h> -#if HAVE_SYS_TIMEB_H -# include <sys/timeb.h> +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +# define WINDOWS_NATIVE +# include <windows.h> #endif #if GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME @@ -92,6 +93,28 @@ rpl_tzset (void) tzset (); *localtime_buffer_addr = save; } + +#endif + +#ifdef WINDOWS_NATIVE + +/* GetSystemTimePreciseAsFileTime was introduced only in Windows 8. */ +typedef void (WINAPI * GetSystemTimePreciseAsFileTimeFuncType) (FILETIME *lpTime); +static GetSystemTimePreciseAsFileTimeFuncType GetSystemTimePreciseAsFileTimeFunc = NULL; +static BOOL initialized = FALSE; + +static void +initialize (void) +{ + HMODULE kernel32 = LoadLibrary ("kernel32.dll"); + if (kernel32 != NULL) + { + GetSystemTimePreciseAsFileTimeFunc = + (GetSystemTimePreciseAsFileTimeFuncType) GetProcAddress (kernel32, "GetSystemTimePreciseAsFileTime"); + } + initialized = TRUE; +} + #endif /* This is a wrapper for gettimeofday. It is used only on systems @@ -130,12 +153,35 @@ gettimeofday (struct timeval *restrict tv, void *restrict tz) #else -# if HAVE__FTIME - - struct _timeb timebuf; - _ftime (&timebuf); - tv->tv_sec = timebuf.time; - tv->tv_usec = timebuf.millitm * 1000; +# ifdef WINDOWS_NATIVE + + /* On native Windows, there are two ways to get the current time: + GetSystemTimeAsFileTime + <https://msdn.microsoft.com/en-us/library/ms724397.aspx> + or + GetSystemTimePreciseAsFileTime + <https://msdn.microsoft.com/en-us/library/hh706895.aspx>. */ + FILETIME current_time; + + if (!initialized) + initialize (); + if (GetSystemTimePreciseAsFileTimeFunc != NULL) + GetSystemTimePreciseAsFileTimeFunc (¤t_time); + else + GetSystemTimeAsFileTime (¤t_time); + + /* Convert from FILETIME to 'struct timeval'. */ + /* FILETIME: <https://msdn.microsoft.com/en-us/library/ms724284.aspx> */ + ULONGLONG since_1601 = + ((ULONGLONG) current_time.dwHighDateTime << 32) + | (ULONGLONG) current_time.dwLowDateTime; + /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89 leap + years, in total 134774 days. */ + ULONGLONG since_1970 = + since_1601 - (ULONGLONG) 134774 * (ULONGLONG) 86400 * (ULONGLONG) 10000000; + ULONGLONG microseconds_since_1970 = since_1970 / (ULONGLONG) 10; + tv->tv_sec = microseconds_since_1970 / (ULONGLONG) 1000000; + tv->tv_usec = microseconds_since_1970 % (ULONGLONG) 1000000; # else diff --git a/m4/gettimeofday.m4 b/m4/gettimeofday.m4 index 4f501e5..742b6c9 100644 --- a/m4/gettimeofday.m4 +++ b/m4/gettimeofday.m4 @@ -1,4 +1,4 @@ -# serial 21 +# serial 22 # Copyright (C) 2001-2003, 2005, 2007, 2009-2017 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation @@ -132,7 +132,4 @@ AC_DEFUN([gl_GETTIMEOFDAY_REPLACE_LOCALTIME], [ ]) # Prerequisites of lib/gettimeofday.c. -AC_DEFUN([gl_PREREQ_GETTIMEOFDAY], [ - AC_CHECK_HEADERS([sys/timeb.h]) - AC_CHECK_FUNCS([_ftime]) -]) +AC_DEFUN([gl_PREREQ_GETTIMEOFDAY], [:])