diff --git a/gio/gperiodic.c b/gio/gperiodic.c index 1e96f6053..31a8bf217 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, ×pec); - - 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 636de3a36..b48f60eee 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 637dcd4e5..ad0d94033 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 b0f352b5e..3194c3777 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; + GTimeoutSource *timeout_source = (GTimeoutSource *) source; + gint64 now = g_source_get_time (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; - - /* 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 73c888d12..c87a76204 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 ================== */