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

Huw Davies huw at codeweavers.com
Tue Nov 26 03:07:10 CST 2019


On Mon, Nov 25, 2019 at 05:45:25PM -0600, Chip Davis wrote:
> Inspired by a patch by Andrew Eikum.
> 
> macOS's mach_absolute_time() stops counting when the computer goes to
> sleep/suspend/hibernate/etc. However, Windows's GetTickCount() does not
> stop counting. mach_continuous_time() matches Windows's behavior.
> 
> BSD's CLOCK_MONOTONIC already counts asleep time.
> 
> Unfortunately, there is no clock source on Linux which does exactly what
> we want. CLOCK_MONOTONIC_RAW is unaffected by NTP adjustment, but like
> mach_absolute_time() doesn't keep ticking when the computer is asleep.
> CLOCK_BOOTTIME does keep ticking, but it is affected by NTP adjustments.
> CLOCK_MONOTONIC has both problems. What's needed is a
> CLOCK_BOOTTIME_RAW, which would not be slewed by adjtimex(2) and would
> count time spent asleep.
> 
> 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 | 4 ++++
>  2 files changed, 5 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..4e3d5583c7b 100644
> --- a/dlls/ntdll/time.c
> +++ b/dlls/ntdll/time.c
> @@ -111,6 +111,10 @@ 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;

I should have mentioned this before, but note that for performance reasons there's
a second implementation of monotonic_counter() in kernel32.  Additionally there's
get_tick_count() in the wineserver.

Did you check that all of the other calls serviced by
monotonic_counter() (e.g. NtQueryPerformanceCounter() and
RtlQueryUnbiasedInterruptTime()) continue to count during a suspend?

Huw.



More information about the wine-devel mailing list