[glib] win32: Use timeGetTime as monotonic base



commit 8d023c2706c1aca43dd04e807dd7d78aee96f202
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Nov 4 15:42:38 2011 +0100

    win32: Use timeGetTime as monotonic base
    
    This allows apps that need it to increase timer accuracy
    using timeBeginPeriod

 configure.ac         |    2 +-
 glib/gmain.c         |   69 +++++++++++++++++++++++++++++++++++++++++++++++--
 glib/makefile.msc.in |    2 +-
 3 files changed, 68 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5ded3a0..847c4f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2652,7 +2652,7 @@ case $host in
 	G_LIBS_EXTRA="-luser32 -lkernel32"
     ;;
   *-*-mingw*)
-	G_LIBS_EXTRA="-lws2_32 -lole32"
+	G_LIBS_EXTRA="-lws2_32 -lole32 -lwinmm"
     ;;
   *)
 	G_LIBS_EXTRA=""
diff --git a/glib/gmain.c b/glib/gmain.c
index fbef349..6a3aaf4 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -2054,18 +2054,81 @@ g_get_monotonic_time (void)
 
 #elif defined (G_OS_WIN32)
   guint64 ticks;
+  guint32 ticks32;
+
+  /* There are four of sources for the monotonic on windows:
+   *
+   * Three are based on a (1 msec accuracy, but only read periodically) clock chip:
+   * - GetTickCount (GTC)
+   *    32bit msec counter, updated each ~15msec, wraps in ~50 days
+   * - GetTickCount64 (GTC64)
+   *    Same as GetTickCount, but extended to 64bit, so no wrap
+   *    Only availible in Vista or later
+   * - timeGetTime (TGT)
+   *    similar to GetTickCount by default: 15msec, 50 day wrap.
+   *    availible in winmm.dll (thus known as the multi media timers) 
+   *    However apps can raise the system timer clock frequency using timeBeginPeriod()
+   *    increasing the accuracy up to 1 msec, at a cost in general system performancs
+   *    and battery use.
+   *
+   * One is based on high precision clocks:
+   * - QueryPrecisionCounter (QPC)
+   *    This has much higher accuracy, but is not guaranteed monotonic, and
+   *    has lots of complications like clock jumps and different times on different
+   *    cpus. It also has lower long term accuracy (i.e. it will drift compared to
+   *    the low precision clocks.
+   *
+   * Additionally, the precision availible in the timer-based wakeup such as
+   * MsgWaitForMultipleObjectsEx (which is what the mainloop is based on) is based
+   * on the TGT resolution, so by default it is ~15msec, but can be increased by apps.
+   *
+   * The QPC timer has too many issues to be used as is. The only way it could be used
+   * is to use it to interpolate the lower precision clocks. Firefox does something like
+   * this:
+   *   https://bugzilla.mozilla.org/show_bug.cgi?id=363258
+   * 
+   * However this seems quite complicated, so we're not doing this right now.
+   *
+   * The approach we take instead is to use the TGT timer, extenting it to 64bit
+   * either by using the GTC64 value, or if that is not availible, a process local
+   * time epoch that we increment when we detect a timer wrap (assumes that we read
+   * the time at least once every 50 days).
+   *
+   * This means that:
+   *  - We have a globally consistent monotonic clock on Vista and later
+   *  - We have a locally monotonic clock on XP
+   *  - Apps that need higher precision in timeouts and clock reads can call 
+   *    timeBeginPeriod() to increase it as much as they want
+   */
 
   if (g_GetTickCount64 != NULL)
     {
+      guint32 ticks_as_32bit;
+
       ticks = g_GetTickCount64 ();
+      ticks32 = timeGetTime();
+
+      /* GTC64 and TGT are sampled at different times, however they 
+       * have the same base and source (msecs since system boot). 
+       * They can differ with as much as -16 to +16 msecs.
+       * We can't just inject the low bits into the 64bit counter 
+       * as one of the counters can have wrapped in 32bit space and
+       * the other not. Instead we calulate the signed differece
+       * in 32bit space and apply that difference to the 64bit counter.
+       */
+      ticks_as_32bit = (guint32)ticks;
+
+      /* We could do some 2s complement hack, but we play it safe */
+      if (ticks32 - ticks_as_32bit <= G_MAXINT32)
+	ticks += ticks32 - ticks_as_32bit;
+      else
+	ticks -= ticks_as_32bit - ticks32;
     }
   else
     {
-      guint32 ticks32;
-
       G_LOCK (g_win32_clock);
 
-      ticks32 = GetTickCount();
+      ticks32 = timeGetTime();
 
       /* We have wrapped the 32bit counter, increase the epoch.
        * This will work as long as this function is called at
diff --git a/glib/makefile.msc.in b/glib/makefile.msc.in
index 936d656..e45b1e5 100644
--- a/glib/makefile.msc.in
+++ b/glib/makefile.msc.in
@@ -126,7 +126,7 @@ glib- GLIB_MAJOR_VERSION@  GLIB_MINOR_VERSION@s.lib : $(glib_OBJECTS) gnulib\gnu
 
 libglib-2.0-0.dll : $(glib_OBJECTS) gnulib\gnulib.lib pcre\pcre.lib glib.def glib.res
 	$(CC) $(CFLAGS) -LD -Fe$@ $(glib_OBJECTS) glib.res $(INTL_LIBS) \
-	gnulib\gnulib.lib pcre\pcre.lib $(DIRENT_LIBS) user32.lib advapi32.lib shell32.lib wsock32.lib ole32.lib ws2_32.lib \
+	gnulib\gnulib.lib pcre\pcre.lib $(DIRENT_LIBS) user32.lib advapi32.lib shell32.lib wsock32.lib ole32.lib ws2_32.lib winmm.lib \
 	$(LDFLAGS) /implib:glib-2.0.lib /def:glib.def
 
 gspawn-win32-helper.exe : gspawn-win32-helper.c libglib-2 0- LT_CURRENT_MINUS_AGE@.dll



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]