diff --git a/ChangeLog b/ChangeLog index 0a9ecb86f6e24d00327a97a0da77866255b1cf18..7cf3e9d99a31b93f9f9ddb24e5d329cf2652b61b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2006-09-10 Matthias Clasen + * glib/glib.symbols: + * glib/gmain.[hc]: Add functions to create approximate + timeouts. (#353942, Arjan van de Ven) + * glib/gstdio.c (g_rename): Initialize save_errno. (#355206, Mike Edenfield) diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 26ea4420869bb3c47e654a742a4b55b4f9b5fcd4..073401ec1b6fbd576c7a2a602302137455ed27d2 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,7 @@ +2006-09-10 Matthias Clasen + + * glib/glib-sections.txt: Add new functions + 2006-08-28 Matthias Clasen * glib/compiling.sgml: Add a note about G_DISABLE_DEPRECATED. diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 62e34804bc994cbd801f0ee206570bc33b1de368..24ab1898b6f59d49065494f422f38c6b6660dca3 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -437,8 +437,10 @@ g_main_set_poll_func g_timeout_source_new +g_timeout_source_new_seconds g_timeout_add g_timeout_add_full +g_timeout_add_seconds g_idle_source_new diff --git a/glib/glib.symbols b/glib/glib.symbols index 0058353a0447da7d82f4da9aaa464715b6c39fe6..1411e6fdf951e8347b36353e8f8c8112e5a819bf 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -617,8 +617,10 @@ g_idle_add_full g_idle_remove_by_data g_idle_source_new g_timeout_add +g_timeout_add_seconds g_timeout_add_full g_timeout_source_new +g_timeout_source_new_seconds #endif #endif diff --git a/glib/gmain.c b/glib/gmain.c index ed2083745d312d3d3088e16e9d0bdacb55dbbcdd..5b3359ad9b5c2aa82dd64f2113af6887b1b87779 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -41,6 +41,7 @@ #include #include #include +#include #ifdef HAVE_SYS_TIME_H #include #endif /* HAVE_SYS_TIME_H */ @@ -179,6 +180,7 @@ struct _GTimeoutSource GSource source; GTimeVal expiration; guint interval; + guint granularity; }; struct _GChildWatchSource @@ -281,6 +283,8 @@ static gint child_watch_wake_up_pipe[2] = {0, 0}; G_LOCK_DEFINE_STATIC (main_context_list); static GSList *main_context_list = NULL; +static gint timer_perturb = -1; + GSourceFuncs g_timeout_funcs = { g_timeout_prepare, @@ -3337,6 +3341,55 @@ g_timeout_set_expiration (GTimeoutSource *timeout_source, timeout_source->expiration.tv_usec -= 1000000; timeout_source->expiration.tv_sec++; } + if (timer_perturb==-1) + { + /* + * we want a per machine/session unique 'random' value; try the dbus + * address first, that has a UUID in it. If there is no dbus, use the + * hostname for hashing. + */ + const char *session_bus_address = getenv("DBUS_SESSION_BUS_ADDRESS"); + if (!session_bus_address) + session_bus_address = getenv("HOSTNAME"); + if (session_bus_address) + timer_perturb = g_str_hash(session_bus_address); + else + timer_perturb = 0; + } + if (timeout_source->granularity) + { + gint remainder; + gint gran; /* in usecs */ + gint perturb; + + gran = timeout_source->granularity * 1000; + perturb = timer_perturb % gran; + /* + * We want to give each machine a per machine pertubation; + * shift time back first, and forward later after the rounding + */ + + timeout_source->expiration.tv_usec -= perturb; + if (timeout_source->expiration.tv_usec < 0) + { + timeout_source->expiration.tv_usec += 1000000; + timeout_source->expiration.tv_sec--; + } + + remainder = timeout_source->expiration.tv_usec % gran; + if (remainder >= gran/4) /* round up */ + timeout_source->expiration.tv_usec += gran; + timeout_source->expiration.tv_usec -= remainder; + /* shift back */ + timeout_source->expiration.tv_usec += perturb; + + /* the rounding may have overflown tv_usec */ + while (timeout_source->expiration.tv_usec > 1000000) + { + timeout_source->expiration.tv_usec -= 1000000; + timeout_source->expiration.tv_sec++; + } + } } static gboolean @@ -3459,6 +3512,39 @@ g_timeout_source_new (guint interval) return source; } +/** + * g_timeout_source_new_seconds: + * @interval: the timeout interval in seconds + * + * Creates a new timeout source. + * + * The source will not initially be associated with any #GMainContext + * and must be added to one with g_source_attach() before it will be + * executed. + * The scheduling granularity/accuracy of this timeout source will be + * in seconds. + * + * Return value: the newly-created timeout source + * + * Since: 2.14 + **/ +GSource * +g_timeout_source_new_seconds (guint interval) +{ + GSource *source = g_source_new (&g_timeout_funcs, sizeof (GTimeoutSource)); + GTimeoutSource *timeout_source = (GTimeoutSource *)source; + GTimeVal current_time; + + timeout_source->interval = 1000*interval; + timeout_source->granularity = 1000; + + g_get_current_time (¤t_time); + g_timeout_set_expiration (timeout_source, ¤t_time); + + return source; +} + + /** * g_timeout_add_full: * @priority: the priority of the idle source. Typically this will be in the @@ -3526,10 +3612,15 @@ g_timeout_add_full (gint priority, * After each call to the timeout function, the time of the next * timeout is recalculated based on the current time and the given interval * (it does not try to 'catch up' time lost in delays). - * + * + * If you want to have a timer in the "seconds" range and do not care + * about the exact time of the first call of the timer, use the + * g_timeout_add_seconds() function; this function allows for more + * optimizations and more efficient system power usage. + * * Return value: the ID (greater than 0) of the event source. **/ -guint +guint g_timeout_add (guint32 interval, GSourceFunc function, gpointer data) @@ -3538,6 +3629,62 @@ g_timeout_add (guint32 interval, interval, function, data, NULL); } +/** + * g_timeout_add_seconds: + * @interval: the time between calls to the function, in seconds + * @function: function to call + * @data: data to pass to @function + * + * Sets a function to be called at regular intervals, with the default + * priority, #G_PRIORITY_DEFAULT. The function is called repeatedly + * until it returns %FALSE, at which point the timeout is automatically + * destroyed and the function will not be called again. + * + * Unlike g_timeout_add(), this function operates at whole second granularity. + * The initial starting point of the timer is determined by the implementation + * and the implementation is expected to group multiple timers together so that + * they fire all at the same time. + * To allow this grouping, the @interval to the first timer is rounded + * and can deviate up to one second from the specified interval. + * Subsequent timer iterations will generally run at the specified interval. + * + * Note that timeout functions may be delayed, due to the processing of other + * event sources. Thus they should not be relied on for precise timing. + * After each call to the timeout function, the time of the next + * timeout is recalculated based on the current time and the given @interval + * + * If you want timing more precise than whole seconds, use g_timeout_add() + * instead. + * + * The grouping of timers to fire at the same time results in a more power + * and CPU efficient behavior so if your timer is in multiples of seconds + * and you don't require the first timer exactly 1 second from now, the + * use of g_timeout_add_second() is prefered over g_timeout_add(). + * + * Return value: the ID (greater than 0) of the event source. + * + * Since: 2.14 + **/ +guint +g_timeout_add_seconds (guint32 interval, + GSourceFunc function, + gpointer data) +{ + GSource *source; + guint id; + + g_return_val_if_fail (function != NULL, 0); + + source = g_timeout_source_new_seconds (interval); + + g_source_set_callback (source, function, data, NULL); + id = g_source_attach (source, NULL); + g_source_unref (source); + + return id; +} + + /* Child watch functions */ #ifdef G_OS_WIN32 diff --git a/glib/gmain.h b/glib/gmain.h index 035b61524ffb468bf16a074121977f58ac0eca5a..8e8dd3fe409701da0a1e5b200bda4b7ab9c5d838 100644 --- a/glib/gmain.h +++ b/glib/gmain.h @@ -256,6 +256,7 @@ void g_source_get_current_time (GSource *source, GSource *g_idle_source_new (void); GSource *g_child_watch_source_new (GPid pid); GSource *g_timeout_source_new (guint interval); +GSource *g_timeout_source_new_seconds (guint interval); /* Miscellaneous functions */ @@ -298,6 +299,9 @@ guint g_timeout_add_full (gint priority, guint g_timeout_add (guint interval, GSourceFunc function, gpointer data); +guint g_timeout_add_seconds (guint interval, + GSourceFunc function, + gpointer data); guint g_child_watch_add_full (gint priority, GPid pid, GChildWatchFunc function,