Use Posix monotonic clocks instead of gettimeofday when available.
authorMatthias Clasen <mclasen@redhat.com>
Mon, 28 Aug 2006 03:01:33 +0000 (03:01 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Mon, 28 Aug 2006 03:01:33 +0000 (03:01 +0000)
2006-08-27  Matthias Clasen  <mclasen@redhat.com>

* glib/gtimer.c: Use Posix monotonic clocks instead of
gettimeofday when available.  (#336114, William Jon McCann)

ChangeLog
glib/gtimer.c

index 76899cad714f41ad4a98fa13789873dff8dbda87..d2ba26bd45ad662729cdae2cc8b07a4d97da5cf8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2006-08-27  Matthias Clasen  <mclasen@redhat.com>
+
+       * glib/gtimer.c: Use Posix monotonic clocks instead of 
+       gettimeofday when available.  (#336114, William Jon McCann)
+
 2006-08-26  Matthias Clasen  <mclasen@redhat.com>
 
        * glib/gutils.h: 
index 69b49571acdd82f92d5f6fa9dd125177620299d3..85688816bf51df0b0b3073b7256e842ce78aa063 100644 (file)
 #include "glib.h"
 #include "galias.h"
 
+#define G_NSEC_PER_SEC 1000000000
 
 struct _GTimer
 {
 #ifdef G_OS_WIN32
   guint64 start;
   guint64 end;
-#else /* !G_OS_WIN32 */
+#elif HAVE_CLOCK_GETTIME 
+  struct timespec start;
+  struct timespec end;
+  gint clock;
+#else /* uses gettimeofday */
   struct timeval start;
   struct timeval end;
-#endif /* !G_OS_WIN32 */
+#endif 
 
   guint active : 1;
 };
 
 #ifdef G_OS_WIN32
-#  define GETTIME(v) \
+#  define GETTIME(v)                           \
      GetSystemTimeAsFileTime ((FILETIME *)&v)
-#else /* !G_OS_WIN32 */
-#  define GETTIME(v) \
+#elif HAVE_CLOCK_GETTIME
+#  define GETTIME(v)                           \
+     clock_gettime (posix_clock, &v)
+#else
+#  define GETTIME(v)                           \
      gettimeofday (&v, NULL)
-#endif /* !G_OS_WIN32 */
+#endif
+
+#ifdef HAVE_CLOCK_GETTIME
+static gint posix_clock = 0;
+
+static void
+init_posix_clock (void)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      initialized = TRUE;
+#if !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK >= 0
+      if (sysconf (_SC_MONOTONIC_CLOCK) >= 0)
+       posix_clock = CLOCK_MONOTONIC;
+      else
+#endif
+       posix_clock = CLOCK_REALTIME;
+    }
+}
+#endif
 
 GTimer*
 g_timer_new (void)
@@ -80,6 +109,10 @@ g_timer_new (void)
   timer = g_new (GTimer, 1);
   timer->active = TRUE;
 
+#ifdef HAVE_CLOCK_GETTIME
+  init_posix_clock ();
+#endif
+
   GETTIME (timer->start);
 
   return timer;
@@ -126,9 +159,11 @@ g_timer_continue (GTimer *timer)
 {
 #ifdef G_OS_WIN32
   guint64 elapsed;
+#elif HAVE_CLOCK_GETTIME
+  struct timespec elapsed;
 #else
   struct timeval elapsed;
-#endif /* G_OS_WIN32 */
+#endif
 
   g_return_if_fail (timer != NULL);
   g_return_if_fail (timer->active == FALSE);
@@ -146,7 +181,29 @@ g_timer_continue (GTimer *timer)
 
   timer->start -= elapsed;
 
-#else /* !G_OS_WIN32 */
+#elif HAVE_CLOCK_GETTIME
+
+  if (timer->start.tv_nsec > timer->end.tv_nsec)
+    {
+      timer->end.tv_nsec += G_NSEC_PER_SEC;
+      timer->end.tv_sec--;
+    }
+
+  elapsed.tv_nsec = timer->end.tv_nsec - timer->start.tv_nsec;
+  elapsed.tv_sec = timer->end.tv_sec - timer->start.tv_sec;
+
+  GETTIME (timer->start);
+
+  if (timer->start.tv_nsec < elapsed.tv_nsec)
+    {
+      timer->start.tv_nsec += G_NSEC_PER_SEC;
+      timer->start.tv_sec--;
+    }
+
+  timer->start.tv_nsec -= elapsed.tv_nsec;
+  timer->start.tv_sec -= elapsed.tv_sec;
+
+#else
 
   if (timer->start.tv_usec > timer->end.tv_usec)
     {
@@ -180,9 +237,11 @@ g_timer_elapsed (GTimer *timer,
   gdouble total;
 #ifdef G_OS_WIN32
   gint64 elapsed;
+#elif HAVE_CLOCK_GETTIME
+  struct timespec elapsed;
 #else
   struct timeval elapsed;
-#endif /* G_OS_WIN32 */
+#endif 
 
   g_return_val_if_fail (timer != NULL, 0);
 
@@ -196,9 +255,33 @@ g_timer_elapsed (GTimer *timer,
 
   if (microseconds)
     *microseconds = (elapsed / 10) % 1000000;
-#else /* !G_OS_WIN32 */
+#elif HAVE_CLOCK_GETTIME
+  if (timer->active)
+    GETTIME (timer->end);
+
+  if (timer->start.tv_nsec > timer->end.tv_nsec)
+    {
+      timer->end.tv_nsec += G_NSEC_PER_SEC;
+      timer->end.tv_sec--;
+    }
+
+  elapsed.tv_nsec = timer->end.tv_nsec - timer->start.tv_nsec;
+  elapsed.tv_sec = timer->end.tv_sec - timer->start.tv_sec;
+
+  total = elapsed.tv_sec + ((gdouble) elapsed.tv_nsec / (gdouble) G_NSEC_PER_SEC);
+  if (total < 0)
+    {
+      total = 0;
+
+      if (microseconds)
+       *microseconds = 0;
+    }
+  else if (microseconds)
+    *microseconds = elapsed.tv_nsec / 1000;
+
+#else
   if (timer->active)
-    gettimeofday (&timer->end, NULL);
+    GETTIME (timer->end);
 
   if (timer->start.tv_usec > timer->end.tv_usec)
     {
@@ -209,7 +292,7 @@ g_timer_elapsed (GTimer *timer,
   elapsed.tv_usec = timer->end.tv_usec - timer->start.tv_usec;
   elapsed.tv_sec = timer->end.tv_sec - timer->start.tv_sec;
 
-  total = elapsed.tv_sec + ((gdouble) elapsed.tv_usec / 1e6);
+  total = elapsed.tv_sec + ((gdouble) elapsed.tv_usec / (gdouble) G_USEC_PER_SEC);
   if (total < 0)
     {
       total = 0;
@@ -220,7 +303,7 @@ g_timer_elapsed (GTimer *timer,
   else if (microseconds)
     *microseconds = elapsed.tv_usec;
 
-#endif /* !G_OS_WIN32 */
+#endif
 
   return total;
 }