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

Arkadiusz Hiler ahiler at codeweavers.com
Tue Aug 25 02:54:01 CDT 2020


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