Add functions for approximate timeouts

This commit is contained in:
Matthias Clasen 2006-09-10 05:44:46 +00:00
parent 4a7aeef16f
commit f8c1c1f9e0
6 changed files with 165 additions and 2 deletions

View File

@ -1,5 +1,9 @@
2006-09-10 Matthias Clasen <mclasen@redhat.com>
* 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)

View File

@ -1,3 +1,7 @@
2006-09-10 Matthias Clasen <mclasen@redhat.com>
* glib/glib-sections.txt: Add new functions
2006-08-28 Matthias Clasen <mclasen@redhat.com>
* glib/compiling.sgml: Add a note about G_DISABLE_DEPRECATED.

View File

@ -437,8 +437,10 @@ g_main_set_poll_func
<SUBSECTION>
g_timeout_source_new
g_timeout_source_new_seconds
g_timeout_add
g_timeout_add_full
g_timeout_add_seconds
<SUBSECTION>
g_idle_source_new

View File

@ -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

View File

@ -41,6 +41,7 @@
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <stdlib.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#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 (&current_time);
g_timeout_set_expiration (timeout_source, &current_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

View File

@ -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,