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
157
glib/gmain.c
157
glib/gmain.c
@ -189,7 +189,7 @@ struct _GMainContext
|
||||
GHashTable *sources; /* guint -> GSource */
|
||||
|
||||
GPtrArray *pending_dispatches;
|
||||
gint timeout; /* Timeout for current iteration */
|
||||
gint64 timeout_usec; /* Timeout for current iteration */
|
||||
|
||||
guint next_id;
|
||||
GQueue source_lists;
|
||||
@ -322,7 +322,7 @@ static gboolean g_main_context_prepare_unlocked (GMainContext *context,
|
||||
gint *priority);
|
||||
static gint g_main_context_query_unlocked (GMainContext *context,
|
||||
gint max_priority,
|
||||
gint *timeout,
|
||||
gint64 *timeout_usec,
|
||||
GPollFD *fds,
|
||||
gint n_fds);
|
||||
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);
|
||||
static void g_main_context_dispatch_unlocked (GMainContext *context);
|
||||
static void g_main_context_poll_unlocked (GMainContext *context,
|
||||
int timeout,
|
||||
gint64 timeout_usec,
|
||||
int priority,
|
||||
GPollFD *fds,
|
||||
int n_fds);
|
||||
@ -3633,6 +3633,45 @@ g_main_context_prepare (GMainContext *context,
|
||||
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
|
||||
g_main_context_prepare_unlocked (GMainContext *context,
|
||||
gint *priority)
|
||||
@ -3676,12 +3715,12 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
||||
|
||||
/* Prepare all sources */
|
||||
|
||||
context->timeout = -1;
|
||||
context->timeout_usec = -1;
|
||||
|
||||
g_source_iter_init (&iter, context, TRUE);
|
||||
while (g_source_iter_next (&iter, &source))
|
||||
{
|
||||
gint source_timeout = -1;
|
||||
gint64 source_timeout_usec = -1;
|
||||
|
||||
if (SOURCE_DESTROYED (source) || SOURCE_BLOCKED (source))
|
||||
continue;
|
||||
@ -3699,14 +3738,17 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
||||
if (prepare)
|
||||
{
|
||||
gint64 begin_time_nsec G_GNUC_UNUSED;
|
||||
int source_timeout_msec = -1;
|
||||
|
||||
context->in_check_or_prepare++;
|
||||
UNLOCK_CONTEXT (context);
|
||||
|
||||
begin_time_nsec = G_TRACE_CURRENT_TIME;
|
||||
|
||||
result = (* prepare) (source, &source_timeout);
|
||||
TRACE (GLIB_MAIN_AFTER_PREPARE (source, prepare, source_timeout));
|
||||
result = (*prepare) (source, &source_timeout_msec);
|
||||
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,
|
||||
"GLib", "GSource.prepare",
|
||||
@ -3730,18 +3772,13 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
||||
|
||||
if (source->priv->ready_time <= context->time)
|
||||
{
|
||||
source_timeout = 0;
|
||||
source_timeout_usec = 0;
|
||||
result = TRUE;
|
||||
}
|
||||
else
|
||||
else if (source_timeout_usec < 0 ||
|
||||
(source->priv->ready_time < context->time + source_timeout_usec))
|
||||
{
|
||||
gint64 timeout;
|
||||
|
||||
/* 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);
|
||||
source_timeout_usec = MAX (0, source->priv->ready_time - context->time);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3761,16 +3798,16 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
||||
{
|
||||
n_ready++;
|
||||
current_priority = source->priority;
|
||||
context->timeout = 0;
|
||||
}
|
||||
|
||||
if (source_timeout >= 0)
|
||||
{
|
||||
if (context->timeout < 0)
|
||||
context->timeout = source_timeout;
|
||||
else
|
||||
context->timeout = MIN (context->timeout, source_timeout);
|
||||
context->timeout_usec = 0;
|
||||
}
|
||||
|
||||
if (source_timeout_usec >= 0)
|
||||
{
|
||||
if (context->timeout_usec < 0)
|
||||
context->timeout_usec = source_timeout_usec;
|
||||
else
|
||||
context->timeout_usec = MIN (context->timeout_usec, source_timeout_usec);
|
||||
}
|
||||
}
|
||||
g_source_iter_clear (&iter);
|
||||
|
||||
@ -3807,28 +3844,32 @@ g_main_context_prepare_unlocked (GMainContext *context,
|
||||
gint
|
||||
g_main_context_query (GMainContext *context,
|
||||
gint max_priority,
|
||||
gint *timeout,
|
||||
gint *timeout_msec,
|
||||
GPollFD *fds,
|
||||
gint n_fds)
|
||||
{
|
||||
gint64 timeout_usec;
|
||||
gint n_poll;
|
||||
|
||||
if (context == NULL)
|
||||
context = g_main_context_default ();
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (timeout_msec != NULL)
|
||||
*timeout_msec = round_timeout_to_msec (timeout_usec);
|
||||
|
||||
return n_poll;
|
||||
}
|
||||
|
||||
static gint
|
||||
g_main_context_query_unlocked (GMainContext *context,
|
||||
gint max_priority,
|
||||
gint *timeout,
|
||||
gint64 *timeout_usec,
|
||||
GPollFD *fds,
|
||||
gint n_fds)
|
||||
{
|
||||
@ -3881,15 +3922,15 @@ g_main_context_query_unlocked (GMainContext *context,
|
||||
}
|
||||
|
||||
context->poll_changed = FALSE;
|
||||
|
||||
if (timeout)
|
||||
|
||||
if (timeout_usec)
|
||||
{
|
||||
*timeout = context->timeout;
|
||||
if (*timeout != 0)
|
||||
*timeout_usec = context->timeout_usec;
|
||||
if (*timeout_usec != 0)
|
||||
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));
|
||||
|
||||
return n_poll;
|
||||
@ -4163,7 +4204,7 @@ g_main_context_iterate_unlocked (GMainContext *context,
|
||||
GThread *self)
|
||||
{
|
||||
gint max_priority = 0;
|
||||
gint timeout;
|
||||
gint64 timeout_usec;
|
||||
gboolean some_ready;
|
||||
gint nfds, allocated_nfds;
|
||||
GPollFD *fds = NULL;
|
||||
@ -4196,10 +4237,10 @@ g_main_context_iterate_unlocked (GMainContext *context,
|
||||
fds = context->cached_poll_array;
|
||||
|
||||
g_main_context_prepare_unlocked (context, &max_priority);
|
||||
|
||||
|
||||
while ((nfds = g_main_context_query_unlocked (
|
||||
context, max_priority, &timeout, fds,
|
||||
allocated_nfds)) > allocated_nfds)
|
||||
context, max_priority, &timeout_usec, fds,
|
||||
allocated_nfds)) > allocated_nfds)
|
||||
{
|
||||
g_free (fds);
|
||||
context->cached_poll_array_size = allocated_nfds = nfds;
|
||||
@ -4207,10 +4248,10 @@ g_main_context_iterate_unlocked (GMainContext *context,
|
||||
}
|
||||
|
||||
if (!block)
|
||||
timeout = 0;
|
||||
|
||||
g_main_context_poll_unlocked (context, timeout, max_priority, fds, nfds);
|
||||
|
||||
timeout_usec = 0;
|
||||
|
||||
g_main_context_poll_unlocked (context, timeout_usec, max_priority, fds, nfds);
|
||||
|
||||
some_ready = g_main_context_check_unlocked (context, max_priority, fds, nfds);
|
||||
|
||||
if (dispatch)
|
||||
@ -4489,7 +4530,7 @@ g_main_loop_get_context (GMainLoop *loop)
|
||||
/* HOLDS: context's lock */
|
||||
static void
|
||||
g_main_context_poll_unlocked (GMainContext *context,
|
||||
int timeout,
|
||||
gint64 timeout_usec,
|
||||
int priority,
|
||||
GPollFD *fds,
|
||||
int n_fds)
|
||||
@ -4502,7 +4543,7 @@ g_main_context_poll_unlocked (GMainContext *context,
|
||||
|
||||
GPollFunc poll_func;
|
||||
|
||||
if (n_fds || timeout != 0)
|
||||
if (n_fds || timeout_usec != 0)
|
||||
{
|
||||
int ret, errsv;
|
||||
|
||||
@ -4510,16 +4551,20 @@ g_main_context_poll_unlocked (GMainContext *context,
|
||||
poll_timer = NULL;
|
||||
if (_g_main_poll_debug)
|
||||
{
|
||||
g_print ("polling context=%p n=%d timeout=%d\n",
|
||||
context, n_fds, timeout);
|
||||
poll_timer = g_timer_new ();
|
||||
g_print ("polling context=%p n=%d timeout_usec=%"G_GINT64_FORMAT"\n",
|
||||
context, n_fds, timeout_usec);
|
||||
poll_timer = g_timer_new ();
|
||||
}
|
||||
#endif
|
||||
poll_func = context->poll_func;
|
||||
|
||||
UNLOCK_CONTEXT (context);
|
||||
ret = (*poll_func) (fds, n_fds, timeout);
|
||||
LOCK_CONTEXT (context);
|
||||
{
|
||||
int timeout_msec = round_timeout_to_msec (timeout_usec);
|
||||
|
||||
UNLOCK_CONTEXT (context);
|
||||
ret = (*poll_func) (fds, n_fds, timeout_msec);
|
||||
LOCK_CONTEXT (context);
|
||||
}
|
||||
|
||||
errsv = errno;
|
||||
if (ret < 0 && errsv != EINTR)
|
||||
@ -4535,11 +4580,11 @@ g_main_context_poll_unlocked (GMainContext *context,
|
||||
#ifdef G_MAIN_POLL_DEBUG
|
||||
if (_g_main_poll_debug)
|
||||
{
|
||||
g_print ("g_main_poll(%d) timeout: %d - elapsed %12.10f seconds",
|
||||
n_fds,
|
||||
timeout,
|
||||
g_timer_elapsed (poll_timer, NULL));
|
||||
g_timer_destroy (poll_timer);
|
||||
g_print ("g_main_poll(%d) timeout_usec: %"G_GINT64_FORMAT" - elapsed %12.10f seconds",
|
||||
n_fds,
|
||||
timeout_usec,
|
||||
g_timer_elapsed (poll_timer, NULL));
|
||||
g_timer_destroy (poll_timer);
|
||||
pollrec = context->poll_records;
|
||||
|
||||
while (pollrec != NULL)
|
||||
@ -4573,7 +4618,7 @@ g_main_context_poll_unlocked (GMainContext *context,
|
||||
g_print ("\n");
|
||||
}
|
||||
#endif
|
||||
} /* if (n_fds || timeout != 0) */
|
||||
} /* if (n_fds || timeout_usec != 0) */
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user