[PATCH 2/2] winmm: Default to 1ms resolution like we used to.

Andrew Eikum aeikum at codeweavers.com
Thu Aug 27 09:27:41 CDT 2020


Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>

On Tue, Aug 25, 2020 at 10:54:01AM +0300, Arkadiusz Hiler wrote:
> Wine's winmm is built on the assumption that we default to 1ms timer
> resolution without ever calling timeBeginPeriod(1).
> 
> For simplicity timeGetTime() was using GetTickCount() which recently has
> changed its implementation and, in worst case scenario, returns a new value
> each ~16ms. This breaks the mentioned assumption.
> 
> This patch changes timeGetTime() so that it uses QueryPerformanceCounter().
> 
> The "observations" comment was updated with the latest findings.
> 
> Fixes: cd215bb49bc2 ("kernel32: Use the user shared data to implement GetTickCount().")
> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49564
> Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
> ---
>  dlls/winmm/time.c | 31 +++++++++++++++++++++++++------
>  1 file changed, 25 insertions(+), 6 deletions(-)
> 
> diff --git a/dlls/winmm/time.c b/dlls/winmm/time.c
> index de2a3fbc61e..9bb948efbdd 100644
> --- a/dlls/winmm/time.c
> +++ b/dlls/winmm/time.c
> @@ -74,17 +74,30 @@ static inline void link_timer( WINE_TIMERENTRY *timer )
>  
>  /*
>   * Some observations on the behavior of winmm on Windows.
> - * First, the call to timeBeginPeriod(xx) can never be used
> - * to raise the timer resolution, only lower it.
> + *
> + * First, the call to timeBeginPeriod(xx) can never be used to
> + * lower the timer resolution (i.e. increase the update
> + * interval), only to increase the timer resolution (i.e. lower
> + * the update interval).
>   *
>   * Second, a brief survey of a variety of Win 2k and Win X
>   * machines showed that a 'standard' (aka default) timer
>   * resolution was 1 ms (Win9x is documented as being 1).  However, one 
>   * machine had a standard timer resolution of 10 ms.
>   *
> - * Further, if we set our default resolution to 1,
> - * the implementation of timeGetTime becomes GetTickCount(),
> - * and we can optimize the code to reduce overhead.
> + * Further, timeBeginPeriod(xx) also affects the resolution of
> + * wait calls such as NtDelayExecution() and
> + * NtWaitForMultipleObjects() which by default round up their
> + * timeout to the nearest multiple of 15.625ms across all Windows
> + * versions. In Wine all of those currently work with sub-1ms
> + * accuracy.
> + *
> + * Effective time resolution is a global value that is the max
> + * of the resolutions (i.e. min of update intervals) requested by
> + * all the processes. A lot of programs seem to do
> + * timeBeginPeriod(1) forcing it onto everyone else.
> + *
> + * Defaulting to 1ms accuracy in winmm should be safe.
>   *
>   * Additionally, a survey of Event behaviors shows that
>   * if we request a Periodic event every 50 ms, then Windows
> @@ -97,6 +110,7 @@ static inline void link_timer( WINE_TIMERENTRY *timer )
>   * no delays.
>   *
>   *   Jeremy White, October 2004
> + *   Arkadiusz Hiler, August 2020
>   */
>  #define MMSYSTIME_MININTERVAL (1)
>  #define MMSYSTIME_MAXINTERVAL (65535)
> @@ -255,7 +269,12 @@ MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize)
>   */
>  DWORD WINAPI timeGetTime(void)
>  {
> -    return GetTickCount();
> +    LARGE_INTEGER now, freq;
> +
> +    QueryPerformanceCounter(&now);
> +    QueryPerformanceFrequency(&freq);
> +
> +    return (now.QuadPart * 1000) / freq.QuadPart;
>  }
>  
>  /**************************************************************************
> -- 
> 2.28.0
> 
> 



More information about the wine-devel mailing list