[PATCH] ntdll: Fix tick count calculation on Linux and Mac.

Chip Davis cdavis at codeweavers.com
Sun Nov 24 19:39:58 CST 2019


Based on a patch by Andrew Eikum.

Linux's CLOCK_MONOTONIC(_RAW) and macOS's mach_absolute_time all stop
counting when the computer goes to sleep/suspend/hibernate/etc. However,
Windows's GetTickCount does not stop counting. Linux's CLOCK_BOOTTIME
matches Windows's behavior, as does macOS's mach_continuous_time.

BSD's CLOCK_MONOTONIC already counts asleep time.

To avoid issues with skew and performance, this patch falls back to
mach_absolute_time on macOS if mach_continuous_time is unavailable. Note
that mach_continuous_time was introduced in macOS 10.12, meaning that if
the minimum version required is less than that, it will be linked
weakly. Therefore we must check that it is nonnull before attempting to
call it.

Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---
 configure.ac      | 1 +
 dlls/ntdll/time.c | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/configure.ac b/configure.ac
index 754dbe8b36e..2a049909a65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2206,6 +2206,7 @@ AC_CHECK_FUNCS(\
 	getopt_long_only \
 	kqueue \
 	lstat \
+	mach_continuous_time \
 	pipe2 \
 	poll \
 	port_create \
diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c
index 91e5887b879..92415d50b04 100644
--- a/dlls/ntdll/time.c
+++ b/dlls/ntdll/time.c
@@ -111,9 +111,17 @@ static inline ULONGLONG monotonic_counter(void)
     static mach_timebase_info_data_t timebase;
 
     if (!timebase.denom) mach_timebase_info( &timebase );
+#ifdef HAVE_MACH_CONTINUOUS_TIME
+    if (mach_continuous_time != NULL)
+        return mach_continuous_time() * timebase.numer / timebase.denom / 100;
+#endif
     return mach_absolute_time() * timebase.numer / timebase.denom / 100;
 #elif defined(HAVE_CLOCK_GETTIME)
     struct timespec ts;
+#ifdef CLOCK_BOOTTIME
+    if (!clock_gettime( CLOCK_BOOTTIME, &ts ))
+        return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
+#endif
 #ifdef CLOCK_MONOTONIC_RAW
     if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
         return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
-- 
2.21.0




More information about the wine-devel mailing list