g_get_monotonic_time: fix race condition
authorDan Winship <danw@gnome.org>
Tue, 16 Aug 2011 23:12:59 +0000 (19:12 -0400)
committerDan Winship <danw@gnome.org>
Wed, 31 Aug 2011 01:16:03 +0000 (21:16 -0400)
Since there was nothing guaranteeing synchronization of the
assignments to checked and clockid, it would be possible for one
thread to set clockid = CLOCK_MONOTONIC, and for another thread to see
checked = TRUE but still clockid = CLOCK_REALTIME.

https://bugzilla.gnome.org/show_bug.cgi?id=655129

glib/gmain.c

index 75c2c0e..a7bcc0f 100644 (file)
@@ -2042,25 +2042,24 @@ g_get_monotonic_time (void)
 #ifdef HAVE_CLOCK_GETTIME
   /* librt clock_gettime() is our first choice */
   {
-    static int clockid = CLOCK_REALTIME;
+#ifdef HAVE_MONOTONIC_CLOCK
+    static volatile gsize clockid = 0;
+#else
+    static clockid_t clockid = CLOCK_REALTIME;
+#endif
     struct timespec ts;
 
 #ifdef HAVE_MONOTONIC_CLOCK
-    /* We have to check if we actually have monotonic clock support.
-     *
-     * There is no thread safety issue here since there is no harm if we
-     * check twice.
-     */
-    {
-      static gboolean checked;
+    if (g_once_init_enter (&clockid))
+      {
+       clockid_t best_clockid;
 
-      if G_UNLIKELY (!checked)
-        {
-          if (sysconf (_SC_MONOTONIC_CLOCK) >= 0)
-            clockid = CLOCK_MONOTONIC;
-          checked = TRUE;
-        }
-    }
+       if (sysconf (_SC_MONOTONIC_CLOCK) >= 0)
+         best_clockid = CLOCK_MONOTONIC;
+       else
+         best_clockid = CLOCK_REALTIME;
+       g_once_init_leave (&clockid, (gsize)best_clockid);
+      }
 #endif
 
     clock_gettime (clockid, &ts);