kernel32, ntdll: Use monotonic timesource in GetTickCount

Michal Malý madcatxster at gmail.com
Fri Aug 31 19:42:07 CDT 2012


This patch replaces gettimeofday() with more suitable functions to make
sure that the time returned by GetTickCount() is not affected by adjustments
to system clock by NTP, SetSystemTime() or the user changing the system
clock while the WINE server is running. The patch has been tested on
Linux kernel 3.5.2 (Fedora 17) and MacOS X 10.6. This fixes bug #11230.

-------------- next part --------------
>From b18160702bbc3d3812251b73b9dfcb364eb36684 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Mal=C3=BD?= <madcatxster at gmail.com>
Date: Fri, 31 Aug 2012 21:54:27 +0200
Subject: [PATCH] kernel32, ntdll: Use monotonic time source in GetTickCount()

---
 configure                   | 44 ++++++++++++++++++++++++++++++++
 dlls/kernel32/Makefile.in   |  2 +-
 dlls/kernel32/kernel_main.c | 62 +++++++++++++++++++++++++++++++++++++++++----
 dlls/ntdll/Makefile.in      |  2 +-
 dlls/ntdll/ntdll_misc.h     |  8 ++++++
 dlls/ntdll/server.c         |  5 +++-
 dlls/ntdll/time.c           | 32 ++++++++++++++++++++---
 include/config.h.in         |  3 +++
 server/object.h             |  9 +++++++
 9 files changed, 155 insertions(+), 12 deletions(-)

diff --git a/configure b/configure
index 29b50e8..c6d2975 100755
--- a/configure
+++ b/configure
@@ -730,6 +730,7 @@ TOOLSDIR
 WOW64_DISABLE
 TARGETFLAGS
 CPPBIN
+LIBRT
 ac_ct_CXX
 CXXFLAGS
 CXX
@@ -5861,6 +5862,7 @@ for ac_header in \
 	mach-o/nlist.h \
 	mach-o/loader.h \
 	mach/mach.h \
+	mach/mach_time.h \
 	mach/machine.h \
 	machine/cpu.h \
 	machine/limits.h \
@@ -7232,6 +7234,48 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if ${ac_cv_lib_rt_clock_gettime+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_rt_clock_gettime=yes
+else
+  ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
+  LIBRT="-lrt"
+$as_echo "#define HAVE_LIBRT_GETTIME" >>confdefs.h
+fi
+
+
 if test "$ac_cv_header_pthread_h" = "yes"
 then
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in
index 6cea0bf..0e5dc89 100644
--- a/dlls/kernel32/Makefile.in
+++ b/dlls/kernel32/Makefile.in
@@ -2,7 +2,7 @@ EXTRADEFS = -D_KERNEL32_ -D_NORMALIZE_
 MODULE    = kernel32.dll
 IMPORTLIB = kernel32
 IMPORTS   = winecrt0 ntdll
-EXTRALIBS = @COREFOUNDATIONLIB@ @LIBPOLL@
+EXTRALIBS = @COREFOUNDATIONLIB@ @LIBPOLL@ @LIBRT@
 EXTRADLLFLAGS = -nodefaultlibs -Wb,-F,KERNEL32.dll -Wl,--image-base,0x7b800000
 
 C_SRCS = \
diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c
index cf06765..a017461 100644
--- a/dlls/kernel32/kernel_main.c
+++ b/dlls/kernel32/kernel_main.c
@@ -36,12 +36,20 @@
 #include "kernel_private.h"
 #include "console_private.h"
 #include "wine/debug.h"
+#ifdef __APPLE__
+# include <mach/mach.h>
+# include <mach/mach_time.h>
+#endif
 
 WINE_DEFAULT_DEBUG_CHANNEL(process);
 
 extern int CDECL __wine_set_signal_handler(unsigned, int (*)(unsigned));
 
 static ULONGLONG server_start_time;
+static ULONGLONG server_start_time_mono;
+#ifdef __APPLE__
+static mach_timebase_info_data_t mach_tbinfo;
+#endif
 
 /***********************************************************************
  *           set_entry_point
@@ -83,12 +91,35 @@ static void set_entry_point( HMODULE module, const char *name, DWORD rva )
  */
 static BOOL process_attach( HMODULE module )
 {
-    SYSTEM_TIMEOFDAY_INFORMATION ti;
+	SYSTEM_TIMEOFDAY_INFORMATION ti;
     RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
 
     NtQuerySystemInformation( SystemTimeOfDayInformation, &ti, sizeof(ti), NULL );
     server_start_time = ti.liKeBootTime.QuadPart;
 
+#ifdef HAVE_LIBRT_GETTIME
+    /* Since Linux 2.6.28 - Linux specific */
+    #ifdef CLOCK_MONOTONIC_RAW
+    clockid_t id = CLOCK_MONOTONIC_RAW;
+    /* Other *NIX platforms */
+    #elif defined(CLOCK_MONOTONIC)
+    clockid_t id = CLOCK_MONOTONIC;
+    #else
+        #error Your platform does not have any monotonic clock source.
+    #endif
+    struct timespec ts;
+    clock_gettime(id, &ts);
+    server_start_time_mono = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+
+/* Mach kernel specific */
+#elif defined(__APPLE__)
+    ULONGLONG mach_start = mach_absolute_time();
+    mach_timebase_info(&mach_tbinfo);
+    server_start_time_mono = (mach_start * mach_tbinfo.numer / mach_tbinfo.denom) / 1000000;
+#else
+    #error We do not know how to get monotonic clock source of your platform.
+#endif
+
     /* Setup registry locale information */
     LOCALE_InitRegistry();
 
@@ -179,10 +210,31 @@ INT WINAPI MulDiv( INT nMultiplicand, INT nMultiplier, INT nDivisor)
  */
 ULONGLONG WINAPI GetTickCount64(void)
 {
-    LARGE_INTEGER now;
-
-    NtQuerySystemTime( &now );
-    return (now.QuadPart - server_start_time) / 10000;
+#ifdef HAVE_LIBRT_GETTIME
+    /* Since Linux 2.6.28 - Linux specific */
+    #ifdef CLOCK_MONOTONIC_RAW
+    clockid_t id = CLOCK_MONOTONIC_RAW;
+    /* Other *NIX systems */
+    #elif defined(CLOCK_MONOTONIC)
+    clockid_t id = CLOCK_MONOTONIC;
+    #else
+        #error Your platform does not have any monotonic clock source.
+    #endif
+
+    struct timespec ts;
+    clock_gettime(id, &ts);
+    return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) - server_start_time_mono;
+
+/* Mach kernel specific */
+#elif defined(__APPLE__)
+    ULONGLONG mach_now = mach_absolute_time();
+    if (mach_tbinfo.denom == 0) {
+        mach_timebase_info(&mach_tbinfo);
+	}
+    return ((mach_now * mach_tbinfo.numer / mach_tbinfo.denom) / 1000000) - server_start_time_mono;
+#else
+    #error We do not know how to get monotonic clock source of your platform.
+#endif
 }
 
 
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 0047731..fdf8ac9 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -2,7 +2,7 @@ EXTRADEFS = -D_NTSYSTEM_
 MODULE    = ntdll.dll
 IMPORTLIB = ntdll
 IMPORTS   = winecrt0
-EXTRALIBS = @IOKITLIB@ @LIBPTHREAD@
+EXTRALIBS = @IOKITLIB@ @LIBPTHREAD@ @LIBRT@
 EXTRADLLFLAGS = -nodefaultlibs -Wl,--image-base,0x7bc00000
 
 C_SRCS = \
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 20f1c45..7934bcb 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -23,6 +23,10 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <pthread.h>
+#ifdef __APPLE__
+#include <mach/mach_time.h>
+#endif
+
 
 #include "windef.h"
 #include "winnt.h"
@@ -75,7 +79,11 @@ extern void fill_cpu_info(void) DECLSPEC_HIDDEN;
 extern void heap_set_debug_flags( HANDLE handle ) DECLSPEC_HIDDEN;
 
 /* server support */
+extern timeout_t server_start_time_mono DECLSPEC_HIDDEN;
 extern timeout_t server_start_time DECLSPEC_HIDDEN;
+#ifdef __APPLE__
+extern mach_timebase_info_data_t mach_tbinfo;
+#endif
 extern unsigned int server_cpus DECLSPEC_HIDDEN;
 extern int is_wow64 DECLSPEC_HIDDEN;
 extern void server_init_process(void) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index 218c6eb..9c1a4df 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -109,7 +109,11 @@ static const enum cpu_type client_cpu = CPU_ARM;
 unsigned int server_cpus = 0;
 int is_wow64 = FALSE;
 
+timeout_t server_start_time_mono = 0;  /* monotonic time of server startup in milliseconds*/
 timeout_t server_start_time = 0;  /* time of server startup */
+#ifdef __APPLE__
+mach_timebase_info_data_t mach_tbinfo;
+#endif
 
 sigset_t server_block_set;  /* signals to block during server calls */
 static int fd_socket = -1;  /* socket to exchange file descriptors with the server */
@@ -899,7 +903,6 @@ static int server_connect(void)
 
 
 #ifdef __APPLE__
-#include <mach/mach.h>
 #include <mach/mach_error.h>
 #include <servers/bootstrap.h>
 
diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c
index d233f23..7b61d6b 100644
--- a/dlls/ntdll/time.c
+++ b/dlls/ntdll/time.c
@@ -38,6 +38,9 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
+#ifdef __APPLE__
+# include <mach/mach.h>
+#endif
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
@@ -484,10 +487,31 @@ NTSTATUS WINAPI NtQueryPerformanceCounter( PLARGE_INTEGER Counter, PLARGE_INTEGE
  */
 ULONG WINAPI NtGetTickCount(void)
 {
-    LARGE_INTEGER now;
-
-    NtQuerySystemTime( &now );
-    return (now.QuadPart - server_start_time) / 10000;
+#ifdef HAVE_LIBRT_GETTIME
+    /* Since Linux 2.6.28 - Linux specific */
+    #ifdef CLOCK_MONOTONIC_RAW
+    clockid_t id = CLOCK_MONOTONIC_RAW;
+    /* Other *NIX systems */
+    #elif defined(CLOCK_MONOTONIC)
+    clockid_t id = CLOCK_MONOTONIC;
+    #else
+        #error Your platform does not have any monotonic clock source.
+    #endif
+
+    struct timespec ts;
+    clock_gettime(id, &ts);
+    return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) - server_start_time_mono;
+
+/* Mach kernel specific */
+#elif defined(__APPLE__)
+    ULONGLONG mach_now = mach_absolute_time();
+    if (mach_tbinfo.denom == 0) {
+        mach_timebase_info(&mach_tbinfo);
+	}
+    return ((mach_now * mach_tbinfo.numer / mach_tbinfo.denom) / 1000000) - server_start_time_mono;
+#else
+    #error We do not know how to get monotonic clock source of your platform.
+#endif
 }
 
 /* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
diff --git a/include/config.h.in b/include/config.h.in
index a00fc1c..4729899 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -353,6 +353,9 @@
 /* Define to 1 if you have the `kstat' library (-lkstat). */
 #undef HAVE_LIBKSTAT
 
+/* Define if you have clock_gettime() in `rt' library */
+#undef HAVE_LIBRT_GETTIME
+
 /* Define to 1 if you have the `ossaudio' library (-lossaudio). */
 #undef HAVE_LIBOSSAUDIO
 
diff --git a/server/object.h b/server/object.h
index a8cb327..9c4ec90 100644
--- a/server/object.h
+++ b/server/object.h
@@ -26,6 +26,10 @@
 #endif
 
 #include <sys/time.h>
+#ifdef __APPLE__
+#include <mach/mach_time.h>
+#endif
+
 #include "wine/server_protocol.h"
 #include "wine/list.h"
 
@@ -230,6 +234,11 @@ extern timeout_t master_socket_timeout;
 extern const char *server_argv0;
 
   /* server start time used for GetTickCount() */
+extern timeout_t server_start_time_mono;
+#ifdef __APPLE__
+extern mach_timebase_info_data_t mach_tbinfo;
+#endif
+  /* server start time NOT used for GetTickCount() */
 extern timeout_t server_start_time;
 
 #endif  /* __WINE_SERVER_OBJECT_H */
-- 
1.7.11.4



More information about the wine-patches mailing list