[glib] win32: Add a monotonic timer



commit 64dec8ad9ff3d9be7d66b11d5f2b22ce3e0954aa
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Nov 4 11:27:00 2011 +0100

    win32: Add a monotonic timer

 glib/glib-init.c |    1 +
 glib/glib-init.h |    1 +
 glib/gmain.c     |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 59 insertions(+), 2 deletions(-)
---
diff --git a/glib/glib-init.c b/glib/glib-init.c
index b86074b..f50793b 100644
--- a/glib/glib-init.c
+++ b/glib/glib-init.c
@@ -229,6 +229,7 @@ DllMain (HINSTANCE hinstDLL,
     {
     case DLL_PROCESS_ATTACH:
       glib_dll = hinstDLL;
+      g_clock_win32_init ();
       g_thread_win32_init ();
       glib_init ();
       break;
diff --git a/glib/glib-init.h b/glib/glib-init.h
index 79b6c26..bf1ecd0 100644
--- a/glib/glib-init.h
+++ b/glib/glib-init.h
@@ -33,6 +33,7 @@ GLIB_VAR gboolean g_mem_gc_friendly;
 
 G_GNUC_INTERNAL void g_thread_win32_thread_detach (void);
 G_GNUC_INTERNAL void g_thread_win32_init (void);
+G_GNUC_INTERNAL void g_clock_win32_init (void);
 G_GNUC_INTERNAL extern HMODULE glib_dll;
 #endif
 
diff --git a/glib/gmain.c b/glib/gmain.c
index 98e70e6..fbef349 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -1973,6 +1973,24 @@ g_get_real_time (void)
   return (((gint64) tv.tv_sec) * 1000000) + tv.tv_usec;
 }
 
+#ifdef G_OS_WIN32
+G_LOCK_DEFINE_STATIC (g_win32_clock);
+static ULONGLONG (*g_GetTickCount64) (void) = NULL;
+static guint32 g_win32_last_ticks32 = 0;
+static guint32 g_win32_tick_epoch = 0;
+G_GNUC_INTERNAL void
+g_clock_win32_init (void)
+{
+  HMODULE kernel32;
+
+  g_GetTickCount64 = NULL;
+  kernel32 = GetModuleHandle ("KERNEL32.DLL");
+  if (kernel32 != NULL)
+    g_GetTickCount64 = (void *) GetProcAddress (kernel32, "GetTickCount64");
+  g_win32_last_ticks32 = GetTickCount();
+}
+#endif
+
 /**
  * g_get_monotonic_time:
  *
@@ -1989,7 +2007,9 @@ g_get_real_time (void)
  * On Windows, "limitations of the OS kernel" is a rather substantial
  * statement.  Depending on the configuration of the system, the wall
  * clock time is updated as infrequently as 64 times a second (which
- * is approximately every 16ms).
+ * is approximately every 16ms). Also, the on XP (not on Vista or later)
+ * the monitonic clock is locally monotonic, but may differ in exact
+ * value between processes due to timer wrap handling.
  *
  * Returns: the monotonic time, in microseconds
  *
@@ -2032,7 +2052,42 @@ g_get_monotonic_time (void)
 
   return (((gint64) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
 
-#else /* !HAVE_CLOCK_GETTIME */
+#elif defined (G_OS_WIN32)
+  guint64 ticks;
+
+  if (g_GetTickCount64 != NULL)
+    {
+      ticks = g_GetTickCount64 ();
+    }
+  else
+    {
+      guint32 ticks32;
+
+      G_LOCK (g_win32_clock);
+
+      ticks32 = GetTickCount();
+
+      /* We have wrapped the 32bit counter, increase the epoch.
+       * This will work as long as this function is called at
+       * least once every ~50 days, which is the wrap time of 
+       * a 32bit msec counter. I think this is pretty likely.
+       *
+       * Note that g_win32_tick_epoch is a process local state,
+       * so the monotonic clock will not be the same between
+       * processes.
+       */
+      if (ticks32 < g_win32_last_ticks32)
+	g_win32_tick_epoch++;
+
+      ticks = (guint64)ticks32 | ((guint64)g_win32_tick_epoch) << 32;
+      g_win32_last_ticks32 = ticks32;
+
+      G_UNLOCK (g_win32_clock);
+    }
+
+  return ticks * 1000;
+
+#else /* !HAVE_CLOCK_GETTIME && ! G_OS_WIN32*/
 
   /* It may look like we are discarding accuracy on Windows (since its
    * current time is expressed in 100s of nanoseconds) but according to



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