From 971bf15f26a774593d894f143cc7ef20a43c643a Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 5 Sep 2024 11:10:12 -0700 Subject: [PATCH] x11: Reduce chances XPending does recvmsg() syscall XPending() will do a recvmsg() syscall if there are no items in the queue. In most cases, this is unnecessary because we know that there is data to be read of the connection or there are items already read which simply need to be processed. Discovering both of those conditions can be done without recvmsg() in the hot paths. Before this path, every iteration of the main loop had the potential to submit a recvmsg() syscall. This reduces that overhead drastically. XFlush() on the other-hand knows if it needs to write data or not and will do no IO in the case the buffer is empty. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3653 Part-of: --- src/x11/meta-x11-event-source.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/x11/meta-x11-event-source.c b/src/x11/meta-x11-event-source.c index dee9b2f01..ebd7bf4ed 100644 --- a/src/x11/meta-x11-event-source.c +++ b/src/x11/meta-x11-event-source.c @@ -33,7 +33,9 @@ meta_x11_event_source_prepare (GSource *source, *timeout = -1; - return XPending (event_source->xdisplay); + XFlush (event_source->xdisplay); + + return XEventsQueued (event_source->xdisplay, QueuedAlready) > 0; } static gboolean @@ -41,7 +43,8 @@ meta_x11_event_source_check (GSource *source) { MetaX11EventSource *event_source = (MetaX11EventSource *) source; - return XPending (event_source->xdisplay); + return (event_source->event_poll_fd.revents & G_IO_IN) != 0 || + XEventsQueued (event_source->xdisplay, QueuedAlready) > 0; } static gboolean @@ -52,12 +55,16 @@ meta_x11_event_source_dispatch (GSource *source, MetaX11EventSource *event_source = (MetaX11EventSource *) source; MetaX11EventFunc event_func = (MetaX11EventFunc) callback; gboolean retval = G_SOURCE_CONTINUE; + int pending; - while (retval == G_SOURCE_CONTINUE && - XPending (event_source->xdisplay)) + pending = XPending (event_source->xdisplay); + + while (retval == G_SOURCE_CONTINUE && pending > 0) { XEvent xevent; + pending--; + XNextEvent (event_source->xdisplay, &xevent); retval = event_func (&xevent, user_data); }