mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 10:42:11 +01:00
Merge branch 'wip/chergert/gpoll-for-gmain' into 'main'
Use ppoll() when possible for more precise timeouts See merge request GNOME/glib!3958
This commit is contained in:
commit
1c5f5a6914
148
glib/gmain.c
148
glib/gmain.c
@ -69,6 +69,10 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL_H
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_PIDFD
|
#ifdef HAVE_PIDFD
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@ -189,7 +193,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 +326,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 +335,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 +3637,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 +3719,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 +3742,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 +3776,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 +3802,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 +3848,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 +3860,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 +3927,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 +4208,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 +4243,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 +4252,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 +4534,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 +4547,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 +4555,39 @@ 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;
|
||||||
|
|
||||||
|
#if defined(HAVE_PPOLL) && defined(HAVE_POLL)
|
||||||
|
if (poll_func == g_poll)
|
||||||
|
{
|
||||||
|
struct timespec spec;
|
||||||
|
struct timespec *spec_p = NULL;
|
||||||
|
|
||||||
|
if (timeout_usec > -1)
|
||||||
|
{
|
||||||
|
spec.tv_sec = timeout_usec / G_USEC_PER_SEC;
|
||||||
|
spec.tv_nsec = (timeout_usec % G_USEC_PER_SEC) * 1000L;
|
||||||
|
spec_p = &spec;
|
||||||
|
}
|
||||||
|
|
||||||
UNLOCK_CONTEXT (context);
|
UNLOCK_CONTEXT (context);
|
||||||
ret = (*poll_func) (fds, n_fds, timeout);
|
ret = ppoll ((struct pollfd *) fds, n_fds, spec_p, NULL);
|
||||||
LOCK_CONTEXT (context);
|
LOCK_CONTEXT (context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
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;
|
errsv = errno;
|
||||||
if (ret < 0 && errsv != EINTR)
|
if (ret < 0 && errsv != EINTR)
|
||||||
@ -4535,9 +4603,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 +4641,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) */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
13
meson.build
13
meson.build
@ -1008,6 +1008,19 @@ if cc.links('''#include <sys/eventfd.h>
|
|||||||
glib_conf.set('HAVE_EVENTFD', 1)
|
glib_conf.set('HAVE_EVENTFD', 1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Check for ppoll(2)
|
||||||
|
if cc.links('''#define _GNU_SOURCE
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
int main (int argc, char ** argv) {
|
||||||
|
struct pollfd fds[1] = {{0}};
|
||||||
|
struct timespec ts = {0};
|
||||||
|
ppoll (fds, 1, NULL, NULL);
|
||||||
|
return 0;
|
||||||
|
}''', name : 'ppoll(2) system call')
|
||||||
|
glib_conf.set('HAVE_PPOLL', 1)
|
||||||
|
endif
|
||||||
|
|
||||||
# Check for pidfd_open(2)
|
# Check for pidfd_open(2)
|
||||||
if cc.links('''#include <sys/syscall.h>
|
if cc.links('''#include <sys/syscall.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user