[PATCH] ntdll: Use boot time to calculate tick count

Andrew Eikum aeikum at codeweavers.com
Thu Aug 25 14:55:31 CDT 2016


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, and macOS's KERN_BOOTTIME sysctl is updated
along with changes to gettimeofday's result, so the difference between
them provides a reliable timer.

Two catches with the macOS behavior: First, this implementation is much
more expensive than one system call in a very frequently called
function. It's an open question whether fixing behavior on sleep is
worth the cost. Second, the boot time has precision only to the nearest
second. This could cause skew if the current time is updated in <~1
second intervals.

Reading manpages, I believe BSD's CLOCK_MONOTONIC already counts asleep
time, but I didn't verify this.

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
 dlls/ntdll/time.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c
index 96ffcfa..526f7d9 100644
--- a/dlls/ntdll/time.c
+++ b/dlls/ntdll/time.c
@@ -39,7 +39,8 @@
 # include <unistd.h>
 #endif
 #ifdef __APPLE__
-# include <mach/mach_time.h>
+# include <mach/mach.h>
+# include <sys/sysctl.h>
 #endif
 
 #include "ntstatus.h"
@@ -102,6 +103,10 @@ static ULONGLONG monotonic_counter(void)
 
 #ifdef 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;
@@ -109,10 +114,20 @@ static ULONGLONG monotonic_counter(void)
     if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
         return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
 #elif defined(__APPLE__)
-    static mach_timebase_info_data_t timebase;
+    {
+        static int ctl[] = {CTL_KERN, KERN_BOOTTIME}, ret;
+        struct timeval boot, diff;
+        size_t sz = sizeof(boot);
 
-    if (!timebase.denom) mach_timebase_info( &timebase );
-    return mach_absolute_time() * timebase.numer / timebase.denom / 100;
+        ret = sysctl(ctl, 2, &boot, &sz, NULL, 0);
+        if(ret == 0){
+            ret = gettimeofday(&now, NULL);
+            if(ret == 0){
+                timersub(&now, &boot, &diff);
+                return diff.tv_sec * (ULONGLONG)TICKSPERSEC + diff.tv_usec * 10;
+            }
+        }
+    }
 #endif
 
     gettimeofday( &now, 0 );
-- 
2.9.3




More information about the wine-patches mailing list