[glib] Switch GTimeSpec users to int64 microseconds



commit c3a0d32ef1413f942890796aa20f7b1a54254eff
Author: Ryan Lortie <desrt desrt ca>
Date:   Mon Nov 1 15:46:35 2010 -0400

    Switch GTimeSpec users to int64 microseconds
    
    glib is trying to move toward using microseconds-in-gint64 as its
    universal time format.
    
    No real API breaks here since GTimeSpec is new this unstable release
    series.

 gio/gperiodic.c |   33 ++---------
 gio/gperiodic.h |    2 +-
 gio/gsocket.c   |   35 +++++------
 glib/gmain.c    |  183 +++++++++++++++++++++++--------------------------------
 glib/gmain.h    |    7 +-
 5 files changed, 101 insertions(+), 159 deletions(-)
---
diff --git a/gio/gperiodic.c b/gio/gperiodic.c
index 1e96f60..31a8bf2 100644
--- a/gio/gperiodic.c
+++ b/gio/gperiodic.c
@@ -113,17 +113,7 @@ static guint g_periodic_repair;
 static guint64
 g_periodic_get_microticks (GPeriodic *periodic)
 {
-  guint64 microticks;
-  GTimeSpec timespec;
-
-  g_source_get_time (periodic->source, &timespec);
-
-  microticks = timespec.tv_sec;
-  microticks *= 1000000;
-  microticks += timespec.tv_nsec / 1000;
-  microticks *= periodic->hz;
-
-  return microticks;
+  return g_source_get_time (periodic->source) * periodic->hz;
 }
 
 static void
@@ -397,7 +387,7 @@ g_periodic_block (GPeriodic *periodic)
 /**
  * g_periodic_unblock:
  * @periodic: a #GPeriodic clock
- * @unblock_time: the unblock time, or %NULL
+ * @unblock_time: the unblock time
  *
  * Reverses the effect of a previous call to g_periodic_block().
  *
@@ -406,8 +396,7 @@ g_periodic_block (GPeriodic *periodic)
  * damaged.
  *
  * @unblock_time is the monotonic time, as per g_get_monotonic_time(),
- * at which the event causing the unblock occured.  If it is %NULL then
- * g_get_monotonic_time() is called internally.
+ * at which the event causing the unblock occured.
  *
  * This function may not be called from handlers of any signal emitted
  * by @periodic.
@@ -416,7 +405,7 @@ g_periodic_block (GPeriodic *periodic)
  **/
 void
 g_periodic_unblock (GPeriodic       *periodic,
-                    const GTimeSpec *unblock_time)
+                    gint64           unblock_time)
 {
   g_return_if_fail (G_IS_PERIODIC (periodic));
   g_return_if_fail (!periodic->in_repair);
@@ -425,19 +414,7 @@ g_periodic_unblock (GPeriodic       *periodic,
 
   if (--periodic->blocked)
     {
-      GTimeSpec now;
-
-      if (unblock_time == NULL)
-        {
-          g_get_monotonic_time (&now);
-          unblock_time = &now;
-        }
-
-      periodic->last_run = unblock_time->tv_sec;
-      periodic->last_run *= 1000000;
-      periodic->last_run += unblock_time->tv_nsec / 1000;
-      periodic->last_run *= periodic->hz;
-
+      periodic->last_run = unblock_time * periodic->hz;
       g_periodic_run (periodic);
     }
 }
diff --git a/gio/gperiodic.h b/gio/gperiodic.h
index 636de3a..b48f60e 100644
--- a/gio/gperiodic.h
+++ b/gio/gperiodic.h
@@ -58,7 +58,7 @@ void                    g_periodic_remove                               (GPeriod
 
 void                    g_periodic_block                                (GPeriodic           *periodic);
 void                    g_periodic_unblock                              (GPeriodic           *periodic,
-                                                                         const GTimeSpec     *unblock_time);
+                                                                         gint64               unblock_time);
 
 void                    g_periodic_damaged                              (GPeriodic           *periodic,
                                                                          GPeriodicRepairFunc  callback,
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 637dcd4..ad0d940 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -2411,7 +2411,7 @@ typedef struct {
   GIOCondition  condition;
   GCancellable *cancellable;
   GPollFD       cancel_pollfd;
-  GTimeSpec     timeout_time;
+  gint64        timeout_time;
 } GSocketSource;
 
 static gboolean
@@ -2423,19 +2423,20 @@ socket_source_prepare (GSource *source,
   if (g_cancellable_is_cancelled (socket_source->cancellable))
     return TRUE;
 
-  if (socket_source->timeout_time.tv_sec)
+  if (socket_source->timeout_time)
     {
-      GTimeSpec now;
+      gint64 now;
 
-      g_source_get_time (source, &now);
-      *timeout = ((socket_source->timeout_time.tv_sec - now.tv_sec) * 1000 +
-		  (socket_source->timeout_time.tv_nsec - now.tv_nsec) / 1000000);
+      now = g_source_get_time (source);
+      /* Round up to ensure that we don't try again too early */
+      *timeout = (socket_source->timeout_time - now + 999) / 1000;
       if (*timeout < 0)
-	{
-	  socket_source->socket->priv->timed_out = TRUE;
-	  socket_source->pollfd.revents = socket_source->condition & (G_IO_IN | G_IO_OUT);
-	  return TRUE;
-	}
+        {
+          socket_source->socket->priv->timed_out = TRUE;
+          socket_source->pollfd.revents = socket_source->condition & (G_IO_IN | G_IO_OUT);
+          *timeout = 0;
+          return TRUE;
+        }
     }
   else
     *timeout = -1;
@@ -2546,15 +2547,11 @@ socket_source_new (GSocket      *socket,
   g_source_add_poll (source, &socket_source->pollfd);
 
   if (socket->priv->timeout)
-    {
-      g_get_monotonic_time (&socket_source->timeout_time);
-      socket_source->timeout_time.tv_sec += socket->priv->timeout;
-    }
+    socket_source->timeout_time = g_get_monotonic_time () +
+                                  socket->priv->timeout * 1000000;
+
   else
-    {
-      socket_source->timeout_time.tv_sec = 0;
-      socket_source->timeout_time.tv_nsec = 0;
-    }
+    socket_source->timeout_time = 0;
 
   return source;
 }
diff --git a/glib/gmain.c b/glib/gmain.c
index b0f352b..3194c37 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -264,7 +264,7 @@ struct _GMainContext
 
   GPollFunc poll_func;
 
-  GTimeSpec time;
+  gint64   time;
   gboolean time_is_fresh;
   GTimeVal current_time;
   gboolean current_time_is_fresh;
@@ -288,7 +288,7 @@ struct _GMainLoop
 struct _GTimeoutSource
 {
   GSource     source;
-  GTimeSpec   expiration;
+  gint64      expiration;
   guint       interval;
   gboolean    seconds;
 };
@@ -1825,7 +1825,6 @@ g_get_current_time (GTimeVal *result)
 
 /**
  * g_get_monotonic_time:
- * @result: #GTimeSpec structure in which to store the time
  *
  * Queries the system monotonic time, if available.
  *
@@ -1839,13 +1838,13 @@ g_get_current_time (GTimeVal *result)
  * the wall clock time is updated as infrequently as 64 times a second
  * (which is approximately every 16ms).
  *
+ * Returns: the monotonic time, in microseconds
+ *
  * Since: 2.28
  **/
-void
-g_get_monotonic_time (GTimeSpec *result)
+gint64
+g_get_monotonic_time (void)
 {
-  g_return_if_fail (result != NULL);
-
 #ifdef HAVE_CLOCK_GETTIME
   /* librt clock_gettime() is our first choice */
   {
@@ -1871,8 +1870,30 @@ g_get_monotonic_time (GTimeSpec *result)
 #endif
 
     clock_gettime (clockid, &ts);
-    result->tv_sec = ts.tv_sec;
-    result->tv_nsec = ts.tv_nsec;
+
+    /* In theory monotonic time can have any epoch.
+     *
+     * glib presently assumes the following:
+     *
+     *   1) The epoch comes some time after the birth of Jesus of Nazareth, but
+     *      not more than 10000 years later.
+     *
+     *   2) The current time also falls sometime within this range.
+     *
+     * These two reasonable assumptions leave us with a maximum deviation from
+     * the epoch of 10000 years, or 315569520000000000 seconds.
+     *
+     * If we restrict ourselves to this range then the number of microseconds
+     * will always fit well inside the constraints of a int64 (by a factor of
+     * about 29).
+     *
+     * If you actually hit the following assertion, probably you should file a
+     * bug against your operating system for being excessively silly.
+     **/
+    g_assert (G_GINT64_CONSTANT (-315569520000000000) < ts.tv_sec &&
+              ts.tv_sec < G_GINT64_CONSTANT (315569520000000000));
+
+    return (((gint64) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
   }
 #else
   /* It may look like we are discarding accuracy on Windows (since its
@@ -1884,8 +1905,8 @@ g_get_monotonic_time (GTimeSpec *result)
     GTimeVal tv;
 
     g_get_current_time (&tv);
-    result->tv_sec = tv.tv_sec;
-    result->tv_nsec = tv.tv_usec * 1000;
+
+    return (((gint64) tv.tv_sec) * 1000000) + tv.tv_usec;
   }
 #endif
 }
@@ -3395,7 +3416,6 @@ g_source_get_current_time (GSource  *source,
 /**
  * g_source_get_time:
  * @source: a #GSource
- * @timespec: #GTimeSpec structure in which to store the time
  *
  * Gets the time to be used when checking this source. The advantage of
  * calling this function over calling g_get_monotonic_time() directly is
@@ -3405,31 +3425,35 @@ g_source_get_current_time (GSource  *source,
  * The time here is the system monotonic time, if available, or some
  * other reasonable alternative otherwise.  See g_get_monotonic_time().
  *
+ * Returns: the monotonic time in microseconds
+ *
  * Since: 2.28
  **/
-void
-g_source_get_time (GSource   *source,
-                   GTimeSpec *timespec)
+gint64
+g_source_get_time (GSource *source)
 {
   GMainContext *context;
-  
-  g_return_if_fail (source->context != NULL);
- 
+  gint64 result;
+
+  g_return_val_if_fail (source->context != NULL, 0);
+
   context = source->context;
 
   LOCK_CONTEXT (context);
 
   if (!context->time_is_fresh)
     {
-      g_get_monotonic_time (&context->time);
+      context->time = g_get_monotonic_time ();
       context->time_is_fresh = TRUE;
     }
-  
-  *timespec = context->time;
-  
+
+  result = context->time;
+
   UNLOCK_CONTEXT (context);
+
+  return result;
 }
- 
+
 /**
  * g_main_context_set_poll_func:
  * @context: a #GMainContext
@@ -3561,18 +3585,10 @@ g_main_context_is_owner (GMainContext *context)
 
 static void
 g_timeout_set_expiration (GTimeoutSource *timeout_source,
-			  GTimeSpec      *current_time)
+                          gint64          current_time)
 {
-  guint seconds = timeout_source->interval / 1000;
-  guint msecs = timeout_source->interval - seconds * 1000;
+  timeout_source->expiration = current_time + timeout_source->interval * 1000;
 
-  timeout_source->expiration.tv_sec = current_time->tv_sec + seconds;
-  timeout_source->expiration.tv_nsec = current_time->tv_nsec + msecs * 1000000;
-  if (timeout_source->expiration.tv_nsec >= 1000000000)
-    {
-      timeout_source->expiration.tv_nsec -= 1000000000;
-      timeout_source->expiration.tv_sec++;
-    }
   if (timeout_source->seconds)
     {
       static gint timer_perturb = -1;
@@ -3599,104 +3615,62 @@ g_timeout_set_expiration (GTimeoutSource *timeout_source,
        * always only *increase* the expiration time by adding a full
        * second in the case that the microsecond portion decreases.
        */
-      if (timer_perturb * 1000 < timeout_source->expiration.tv_nsec)
-        timeout_source->expiration.tv_sec++;
+      if (timer_perturb < timeout_source->expiration % 1000000)
+        timeout_source->expiration += 1000000;
 
-      timeout_source->expiration.tv_nsec = timer_perturb * 1000;
+      timeout_source->expiration =
+        ((timeout_source->expiration / 1000000) * 1000000) + timer_perturb;
     }
 }
 
 static gboolean
 g_timeout_prepare (GSource *source,
-		   gint    *timeout)
+                   gint    *timeout)
 {
-  glong sec;
-  glong msec;
-  GTimeSpec now;
-  
-  GTimeoutSource *timeout_source = (GTimeoutSource *)source;
-
-  g_source_get_time (source, &now);
-
-  sec = timeout_source->expiration.tv_sec - now.tv_sec;
-  msec = (timeout_source->expiration.tv_nsec - now.tv_nsec) / 1000000;
+  GTimeoutSource *timeout_source = (GTimeoutSource *) source;
+  gint64 now = g_source_get_time (source);
 
-  /* We do the following in a rather convoluted fashion to deal with
-   * the fact that we don't have an integral type big enough to hold
-   * the difference of two timevals in millseconds.
-   */
-  if (sec < 0 || (sec == 0 && msec < 0))
-    msec = 0;
-  else
+  if (now < timeout_source->expiration)
     {
-      glong interval_sec = timeout_source->interval / 1000;
-      glong interval_msec = timeout_source->interval % 1000;
-
-      if (msec < 0)
-	{
-	  msec += 1000;
-	  sec -= 1;
-	}
-      
-      if (sec > interval_sec ||
-	  (sec == interval_sec && msec > interval_msec))
-	{
-	  /* The system time has been set backwards, so we
-	   * reset the expiration time to now + timeout_source->interval;
-	   * this at least avoids hanging for long periods of time.
-	   */
-	  g_timeout_set_expiration (timeout_source, &now);
-	  msec = MIN (G_MAXINT, timeout_source->interval);
-	}
-      else
-	{
-	  msec = MIN (G_MAXINT, (guint)msec + 1000 * (guint)sec);
-	}
+      /* Round up to ensure that we don't try again too early */
+      *timeout = (timeout_source->expiration - now + 999) / 1000;
+      return FALSE;
     }
 
-  *timeout = (gint)msec;
-  
-  return msec == 0;
+  *timeout = 0;
+  return TRUE;
 }
 
 static gboolean 
 g_timeout_check (GSource *source)
 {
-  GTimeSpec now;
-  GTimeoutSource *timeout_source = (GTimeoutSource *)source;
+  GTimeoutSource *timeout_source = (GTimeoutSource *) source;
+  gint64 now = g_source_get_time (source);
 
-  g_source_get_time (source, &now);
-  
-  return ((timeout_source->expiration.tv_sec < now.tv_sec) ||
-	  ((timeout_source->expiration.tv_sec == now.tv_sec) &&
-	   (timeout_source->expiration.tv_nsec <= now.tv_nsec)));
+  return timeout_source->expiration <= now;
 }
 
 static gboolean
 g_timeout_dispatch (GSource     *source,
-		    GSourceFunc  callback,
-		    gpointer     user_data)
+                    GSourceFunc  callback,
+                    gpointer     user_data)
 {
   GTimeoutSource *timeout_source = (GTimeoutSource *)source;
+  gboolean again;
 
   if (!callback)
     {
       g_warning ("Timeout source dispatched without callback\n"
-		 "You must call g_source_set_callback().");
+                 "You must call g_source_set_callback().");
       return FALSE;
     }
- 
-  if (callback (user_data))
-    {
-      GTimeSpec now;
 
-      g_source_get_time (source, &now);
-      g_timeout_set_expiration (timeout_source, &now);
+  again = callback (user_data);
 
-      return TRUE;
-    }
-  else
-    return FALSE;
+  if (again)
+    g_timeout_set_expiration (timeout_source, g_source_get_time (source));
+
+  return again;
 }
 
 /**
@@ -3716,13 +3690,10 @@ g_timeout_source_new (guint interval)
 {
   GSource *source = g_source_new (&g_timeout_funcs, sizeof (GTimeoutSource));
   GTimeoutSource *timeout_source = (GTimeoutSource *)source;
-  GTimeSpec now;
 
   timeout_source->interval = interval;
+  g_timeout_set_expiration (timeout_source, g_get_monotonic_time ());
 
-  g_get_monotonic_time (&now);
-  g_timeout_set_expiration (timeout_source, &now);
-  
   return source;
 }
 
@@ -3748,13 +3719,11 @@ g_timeout_source_new_seconds (guint interval)
 {
   GSource *source = g_source_new (&g_timeout_funcs, sizeof (GTimeoutSource));
   GTimeoutSource *timeout_source = (GTimeoutSource *)source;
-  GTimeSpec now;
 
   timeout_source->interval = 1000 * interval;
   timeout_source->seconds = TRUE;
 
-  g_get_monotonic_time (&now);
-  g_timeout_set_expiration (timeout_source, &now);
+  g_timeout_set_expiration (timeout_source, g_get_monotonic_time ());
 
   return source;
 }
diff --git a/glib/gmain.h b/glib/gmain.h
index 73c888d..c87a762 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -367,8 +367,7 @@ void     g_source_remove_poll      (GSource        *source,
 void     g_source_get_current_time (GSource        *source,
                                     GTimeVal       *timeval);
 #endif
-void     g_source_get_time         (GSource        *source,
-                                    GTimeSpec      *timespec);
+gint64   g_source_get_time         (GSource        *source);
 
  /* void g_source_connect_closure (GSource        *source,
                                   GClosure       *closure);
@@ -383,8 +382,8 @@ GSource *g_timeout_source_new_seconds (guint interval);
 
 /* Miscellaneous functions
  */
-void g_get_current_time                 (GTimeVal       *result);
-void g_get_monotonic_time               (GTimeSpec      *result);
+void   g_get_current_time                 (GTimeVal       *result);
+gint64 g_get_monotonic_time               (void);
 
 /* ============== Compat main loop stuff ================== */
 



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