mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-11 23:16:14 +01:00
glib/gmain: plumb timeout as microseconds
This gets access to the timeout as microseconds up until we are about to enter the GPollFunc. This is useful so that alternative means may be used to poll with more precision for timeout.
This commit is contained in:
parent
5b9dac546e
commit
c840d75395
125
glib/gmain.c
125
glib/gmain.c
@ -189,7 +189,7 @@ struct _GMainContext
|
|||||||
GHashTable *sources; /* guint -> GSource */
|
GHashTable *sources; /* guint -> GSource */
|
||||||
|
|
||||||
GPtrArray *pending_dispatches;
|
GPtrArray *pending_dispatches;
|
||||||
gint timeout; /* Timeout for current iteration */
|
gint64 timeout_usec; /* Timeout for current iteration */
|
||||||
|
|
||||||
guint next_id;
|
guint next_id;
|
||||||
GQueue source_lists;
|
GQueue source_lists;
|
||||||
@ -322,7 +322,7 @@ static gboolean g_main_context_prepare_unlocked (GMainContext *context,
|
|||||||
gint *priority);
|
gint *priority);
|
||||||
static gint g_main_context_query_unlocked (GMainContext *context,
|
static gint g_main_context_query_unlocked (GMainContext *context,
|
||||||
gint max_priority,
|
gint max_priority,
|
||||||
gint *timeout,
|
gint64 *timeout_usec,
|
||||||
GPollFD *fds,
|
GPollFD *fds,
|
||||||
gint n_fds);
|
gint n_fds);
|
||||||
static gboolean g_main_context_check_unlocked (GMainContext *context,
|
static gboolean g_main_context_check_unlocked (GMainContext *context,
|
||||||
@ -331,7 +331,7 @@ static gboolean g_main_context_check_unlocked (GMainContext *context,
|
|||||||
gint n_fds);
|
gint n_fds);
|
||||||
static void g_main_context_dispatch_unlocked (GMainContext *context);
|
static void g_main_context_dispatch_unlocked (GMainContext *context);
|
||||||
static void g_main_context_poll_unlocked (GMainContext *context,
|
static void g_main_context_poll_unlocked (GMainContext *context,
|
||||||
int timeout,
|
gint64 timeout_usec,
|
||||||
int priority,
|
int priority,
|
||||||
GPollFD *fds,
|
GPollFD *fds,
|
||||||
int n_fds);
|
int n_fds);
|
||||||
@ -3633,6 +3633,45 @@ g_main_context_prepare (GMainContext *context,
|
|||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
round_timeout_to_msec (gint64 timeout_usec)
|
||||||
|
{
|
||||||
|
/* We need to round to milliseconds from our internal microseconds for
|
||||||
|
* various external API and GPollFunc which requires milliseconds.
|
||||||
|
*
|
||||||
|
* However, we want to ensure a few invariants for this.
|
||||||
|
*
|
||||||
|
* Return == -1 if we have no timeout specified
|
||||||
|
* Return == 0 if we don't want to block at all
|
||||||
|
* Return > 0 if we have any timeout to avoid spinning the CPU
|
||||||
|
*
|
||||||
|
* This does cause jitter if the microsecond timeout is < 1000 usec
|
||||||
|
* because that is beyond our precision. However, using ppoll() instead
|
||||||
|
* of poll() (when available) avoids this jitter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (timeout_usec == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (timeout_usec > 0)
|
||||||
|
{
|
||||||
|
guint64 timeout_msec = (timeout_usec + 999) / 1000;
|
||||||
|
|
||||||
|
return (int) MIN (timeout_msec, G_MAXINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gint64
|
||||||
|
extend_timeout_to_usec (int timeout_msec)
|
||||||
|
{
|
||||||
|
if (timeout_msec >= 0)
|
||||||
|
return (gint64) timeout_msec * 1000;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
g_main_context_prepare_unlocked (GMainContext *context,
|
g_main_context_prepare_unlocked (GMainContext *context,
|
||||||
gint *priority)
|
gint *priority)
|
||||||
@ -3676,12 +3715,12 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
|||||||
|
|
||||||
/* Prepare all sources */
|
/* Prepare all sources */
|
||||||
|
|
||||||
context->timeout = -1;
|
context->timeout_usec = -1;
|
||||||
|
|
||||||
g_source_iter_init (&iter, context, TRUE);
|
g_source_iter_init (&iter, context, TRUE);
|
||||||
while (g_source_iter_next (&iter, &source))
|
while (g_source_iter_next (&iter, &source))
|
||||||
{
|
{
|
||||||
gint source_timeout = -1;
|
gint64 source_timeout_usec = -1;
|
||||||
|
|
||||||
if (SOURCE_DESTROYED (source) || SOURCE_BLOCKED (source))
|
if (SOURCE_DESTROYED (source) || SOURCE_BLOCKED (source))
|
||||||
continue;
|
continue;
|
||||||
@ -3699,14 +3738,17 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
|||||||
if (prepare)
|
if (prepare)
|
||||||
{
|
{
|
||||||
gint64 begin_time_nsec G_GNUC_UNUSED;
|
gint64 begin_time_nsec G_GNUC_UNUSED;
|
||||||
|
int source_timeout_msec = -1;
|
||||||
|
|
||||||
context->in_check_or_prepare++;
|
context->in_check_or_prepare++;
|
||||||
UNLOCK_CONTEXT (context);
|
UNLOCK_CONTEXT (context);
|
||||||
|
|
||||||
begin_time_nsec = G_TRACE_CURRENT_TIME;
|
begin_time_nsec = G_TRACE_CURRENT_TIME;
|
||||||
|
|
||||||
result = (* prepare) (source, &source_timeout);
|
result = (*prepare) (source, &source_timeout_msec);
|
||||||
TRACE (GLIB_MAIN_AFTER_PREPARE (source, prepare, source_timeout));
|
TRACE (GLIB_MAIN_AFTER_PREPARE (source, prepare, source_timeout_msec));
|
||||||
|
|
||||||
|
source_timeout_usec = extend_timeout_to_usec (source_timeout_msec);
|
||||||
|
|
||||||
g_trace_mark (begin_time_nsec, G_TRACE_CURRENT_TIME - begin_time_nsec,
|
g_trace_mark (begin_time_nsec, G_TRACE_CURRENT_TIME - begin_time_nsec,
|
||||||
"GLib", "GSource.prepare",
|
"GLib", "GSource.prepare",
|
||||||
@ -3730,18 +3772,13 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
|||||||
|
|
||||||
if (source->priv->ready_time <= context->time)
|
if (source->priv->ready_time <= context->time)
|
||||||
{
|
{
|
||||||
source_timeout = 0;
|
source_timeout_usec = 0;
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else if (source_timeout_usec < 0 ||
|
||||||
|
(source->priv->ready_time < context->time + source_timeout_usec))
|
||||||
{
|
{
|
||||||
gint64 timeout;
|
source_timeout_usec = MAX (0, source->priv->ready_time - context->time);
|
||||||
|
|
||||||
/* rounding down will lead to spinning, so always round up */
|
|
||||||
timeout = (source->priv->ready_time - context->time + 999) / 1000;
|
|
||||||
|
|
||||||
if (source_timeout < 0 || timeout < source_timeout)
|
|
||||||
source_timeout = MIN (timeout, G_MAXINT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3761,15 +3798,15 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
|||||||
{
|
{
|
||||||
n_ready++;
|
n_ready++;
|
||||||
current_priority = source->priority;
|
current_priority = source->priority;
|
||||||
context->timeout = 0;
|
context->timeout_usec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_timeout >= 0)
|
if (source_timeout_usec >= 0)
|
||||||
{
|
{
|
||||||
if (context->timeout < 0)
|
if (context->timeout_usec < 0)
|
||||||
context->timeout = source_timeout;
|
context->timeout_usec = source_timeout_usec;
|
||||||
else
|
else
|
||||||
context->timeout = MIN (context->timeout, source_timeout);
|
context->timeout_usec = MIN (context->timeout_usec, source_timeout_usec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_source_iter_clear (&iter);
|
g_source_iter_clear (&iter);
|
||||||
@ -3807,10 +3844,11 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
|||||||
gint
|
gint
|
||||||
g_main_context_query (GMainContext *context,
|
g_main_context_query (GMainContext *context,
|
||||||
gint max_priority,
|
gint max_priority,
|
||||||
gint *timeout,
|
gint *timeout_msec,
|
||||||
GPollFD *fds,
|
GPollFD *fds,
|
||||||
gint n_fds)
|
gint n_fds)
|
||||||
{
|
{
|
||||||
|
gint64 timeout_usec;
|
||||||
gint n_poll;
|
gint n_poll;
|
||||||
|
|
||||||
if (context == NULL)
|
if (context == NULL)
|
||||||
@ -3818,17 +3856,20 @@ g_main_context_query (GMainContext *context,
|
|||||||
|
|
||||||
LOCK_CONTEXT (context);
|
LOCK_CONTEXT (context);
|
||||||
|
|
||||||
n_poll = g_main_context_query_unlocked (context, max_priority, timeout, fds, n_fds);
|
n_poll = g_main_context_query_unlocked (context, max_priority, &timeout_usec, fds, n_fds);
|
||||||
|
|
||||||
UNLOCK_CONTEXT (context);
|
UNLOCK_CONTEXT (context);
|
||||||
|
|
||||||
|
if (timeout_msec != NULL)
|
||||||
|
*timeout_msec = round_timeout_to_msec (timeout_usec);
|
||||||
|
|
||||||
return n_poll;
|
return n_poll;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
g_main_context_query_unlocked (GMainContext *context,
|
g_main_context_query_unlocked (GMainContext *context,
|
||||||
gint max_priority,
|
gint max_priority,
|
||||||
gint *timeout,
|
gint64 *timeout_usec,
|
||||||
GPollFD *fds,
|
GPollFD *fds,
|
||||||
gint n_fds)
|
gint n_fds)
|
||||||
{
|
{
|
||||||
@ -3882,14 +3923,14 @@ g_main_context_query_unlocked (GMainContext *context,
|
|||||||
|
|
||||||
context->poll_changed = FALSE;
|
context->poll_changed = FALSE;
|
||||||
|
|
||||||
if (timeout)
|
if (timeout_usec)
|
||||||
{
|
{
|
||||||
*timeout = context->timeout;
|
*timeout_usec = context->timeout_usec;
|
||||||
if (*timeout != 0)
|
if (*timeout_usec != 0)
|
||||||
context->time_is_fresh = FALSE;
|
context->time_is_fresh = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE (GLIB_MAIN_CONTEXT_AFTER_QUERY (context, context->timeout,
|
TRACE (GLIB_MAIN_CONTEXT_AFTER_QUERY (context, context->timeout_usec,
|
||||||
fds, n_poll));
|
fds, n_poll));
|
||||||
|
|
||||||
return n_poll;
|
return n_poll;
|
||||||
@ -4163,7 +4204,7 @@ g_main_context_iterate_unlocked (GMainContext *context,
|
|||||||
GThread *self)
|
GThread *self)
|
||||||
{
|
{
|
||||||
gint max_priority = 0;
|
gint max_priority = 0;
|
||||||
gint timeout;
|
gint64 timeout_usec;
|
||||||
gboolean some_ready;
|
gboolean some_ready;
|
||||||
gint nfds, allocated_nfds;
|
gint nfds, allocated_nfds;
|
||||||
GPollFD *fds = NULL;
|
GPollFD *fds = NULL;
|
||||||
@ -4198,7 +4239,7 @@ g_main_context_iterate_unlocked (GMainContext *context,
|
|||||||
g_main_context_prepare_unlocked (context, &max_priority);
|
g_main_context_prepare_unlocked (context, &max_priority);
|
||||||
|
|
||||||
while ((nfds = g_main_context_query_unlocked (
|
while ((nfds = g_main_context_query_unlocked (
|
||||||
context, max_priority, &timeout, fds,
|
context, max_priority, &timeout_usec, fds,
|
||||||
allocated_nfds)) > allocated_nfds)
|
allocated_nfds)) > allocated_nfds)
|
||||||
{
|
{
|
||||||
g_free (fds);
|
g_free (fds);
|
||||||
@ -4207,9 +4248,9 @@ g_main_context_iterate_unlocked (GMainContext *context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!block)
|
if (!block)
|
||||||
timeout = 0;
|
timeout_usec = 0;
|
||||||
|
|
||||||
g_main_context_poll_unlocked (context, timeout, max_priority, fds, nfds);
|
g_main_context_poll_unlocked (context, timeout_usec, max_priority, fds, nfds);
|
||||||
|
|
||||||
some_ready = g_main_context_check_unlocked (context, max_priority, fds, nfds);
|
some_ready = g_main_context_check_unlocked (context, max_priority, fds, nfds);
|
||||||
|
|
||||||
@ -4489,7 +4530,7 @@ g_main_loop_get_context (GMainLoop *loop)
|
|||||||
/* HOLDS: context's lock */
|
/* HOLDS: context's lock */
|
||||||
static void
|
static void
|
||||||
g_main_context_poll_unlocked (GMainContext *context,
|
g_main_context_poll_unlocked (GMainContext *context,
|
||||||
int timeout,
|
gint64 timeout_usec,
|
||||||
int priority,
|
int priority,
|
||||||
GPollFD *fds,
|
GPollFD *fds,
|
||||||
int n_fds)
|
int n_fds)
|
||||||
@ -4502,7 +4543,7 @@ g_main_context_poll_unlocked (GMainContext *context,
|
|||||||
|
|
||||||
GPollFunc poll_func;
|
GPollFunc poll_func;
|
||||||
|
|
||||||
if (n_fds || timeout != 0)
|
if (n_fds || timeout_usec != 0)
|
||||||
{
|
{
|
||||||
int ret, errsv;
|
int ret, errsv;
|
||||||
|
|
||||||
@ -4510,16 +4551,20 @@ g_main_context_poll_unlocked (GMainContext *context,
|
|||||||
poll_timer = NULL;
|
poll_timer = NULL;
|
||||||
if (_g_main_poll_debug)
|
if (_g_main_poll_debug)
|
||||||
{
|
{
|
||||||
g_print ("polling context=%p n=%d timeout=%d\n",
|
g_print ("polling context=%p n=%d timeout_usec=%"G_GINT64_FORMAT"\n",
|
||||||
context, n_fds, timeout);
|
context, n_fds, timeout_usec);
|
||||||
poll_timer = g_timer_new ();
|
poll_timer = g_timer_new ();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
poll_func = context->poll_func;
|
poll_func = context->poll_func;
|
||||||
|
|
||||||
|
{
|
||||||
|
int timeout_msec = round_timeout_to_msec (timeout_usec);
|
||||||
|
|
||||||
UNLOCK_CONTEXT (context);
|
UNLOCK_CONTEXT (context);
|
||||||
ret = (*poll_func) (fds, n_fds, timeout);
|
ret = (*poll_func) (fds, n_fds, timeout_msec);
|
||||||
LOCK_CONTEXT (context);
|
LOCK_CONTEXT (context);
|
||||||
|
}
|
||||||
|
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (ret < 0 && errsv != EINTR)
|
if (ret < 0 && errsv != EINTR)
|
||||||
@ -4535,9 +4580,9 @@ g_main_context_poll_unlocked (GMainContext *context,
|
|||||||
#ifdef G_MAIN_POLL_DEBUG
|
#ifdef G_MAIN_POLL_DEBUG
|
||||||
if (_g_main_poll_debug)
|
if (_g_main_poll_debug)
|
||||||
{
|
{
|
||||||
g_print ("g_main_poll(%d) timeout: %d - elapsed %12.10f seconds",
|
g_print ("g_main_poll(%d) timeout_usec: %"G_GINT64_FORMAT" - elapsed %12.10f seconds",
|
||||||
n_fds,
|
n_fds,
|
||||||
timeout,
|
timeout_usec,
|
||||||
g_timer_elapsed (poll_timer, NULL));
|
g_timer_elapsed (poll_timer, NULL));
|
||||||
g_timer_destroy (poll_timer);
|
g_timer_destroy (poll_timer);
|
||||||
pollrec = context->poll_records;
|
pollrec = context->poll_records;
|
||||||
@ -4573,7 +4618,7 @@ g_main_context_poll_unlocked (GMainContext *context,
|
|||||||
g_print ("\n");
|
g_print ("\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} /* if (n_fds || timeout != 0) */
|
} /* if (n_fds || timeout_usec != 0) */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user