[Xcb] [PATCH libX11 3/3] Avoid excessive reads and waiting of events in _XReply.

Rami Ylimäki rami.ylimaki at vincit.fi
Thu Oct 7 08:43:21 PDT 2010


Previously Xlib executed a vain non-blocking read in XCB whenever
checking for events to handle.

Also Xlib prevented reply handling from advancing if there were no
events and other threads were waiting for events.

Signed-off-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
---
 src/xcb_io.c |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/src/xcb_io.c b/src/xcb_io.c
index 7e685de..2b31480 100644
--- a/src/xcb_io.c
+++ b/src/xcb_io.c
@@ -227,6 +227,64 @@ static xcb_generic_reply_t *poll_for_event(Display *dpy)
 	return NULL;
 }
 
+/**
+ * Check if we have read events from XCB or whether XCB has some
+ * events in its buffers.
+ *
+ * @param[in]: dpy Connection to X server.
+ * 
+ * @param[out]: header Header that is filled with contens of next
+ *                     available event. If there are no events, header
+ *                     contents are not modified.
+ *
+ * @return Zero if there are no events available, non-zero otherwise.
+ */
+static Bool peek_for_event(Display *dpy, xcb_generic_event_t *header)
+{
+    require_socket(dpy);
+
+    /* Check if we have already read an event from XCB. */
+    if (dpy->xcb->next_event)
+    {
+        *header = *dpy->xcb->next_event;
+        return True;
+    }
+
+    /* Check if XCB has any events in its buffers. */
+    return xcb_peek_for_event(dpy->xcb->connection, header);
+}
+
+/**
+ * Check if there are events available that should be handled before
+ * the reply to a given request is handled.
+ *
+ * @param[in]: dpy Connection to X server.
+ *
+ * @param[in]: request_sequence Sequence number for a request. The
+ *                              reply to this request should have been
+ *                              received from XCB before this function
+ *                              is called.
+ *
+ * @return Zero if reply to a request can be handled immediately,
+ *         non-zero otherwise.
+ */
+static Bool events_exist(Display *dpy, unsigned long request_sequence)
+{
+    xcb_generic_event_t header;
+    /* Check if there are events that should be processed before the
+     * reply to given request. */
+    if (peek_for_event(dpy, &header))
+    {
+        unsigned long header_sequence = dpy->last_request_read;
+        widen(&header_sequence, header.full_sequence);
+        /* If there are no events, or the events came after the
+         * request reply, we don't have to worry about them. */
+        return XLIB_SEQUENCE_COMPARE(header_sequence, <=, request_sequence);
+    }
+
+    return False;
+}
+
 static xcb_generic_reply_t *poll_for_response(Display *dpy)
 {
 	void *response;
@@ -541,18 +599,20 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
 		if(dpy->xcb->event_owner == XlibOwnsEventQueue)
 		{
 			xcb_generic_reply_t *event;
+			Bool early_events_exist = events_exist(dpy, req->sequence);
 			/* If some thread is already waiting for events,
 			 * it will get the first one. That thread must
 			 * process that event before we can continue. */
-			/* FIXME: That event might be after this reply,
-			 * and might never even come--or there might be
-			 * multiple threads trying to get events. */
-			while(dpy->xcb->event_waiter)
+			while(early_events_exist && dpy->xcb->event_waiter)
 			{ /* need braces around ConditionWait */
 				ConditionWait(dpy, dpy->xcb->event_notify);
+				early_events_exist = events_exist(dpy, req->sequence);
 			}
-			while((event = poll_for_event(dpy)))
+			while(early_events_exist && (event = poll_for_event(dpy)))
+			{
 				handle_response(dpy, event, True);
+				early_events_exist = events_exist(dpy, req->sequence);
+			}
 		}
 
 		req->reply_waiter = 0;
-- 
1.6.3.3



More information about the Xcb mailing list