poll_for_response: Call poll_for_event again if xcb_poll_for_reply fails

If xcb_poll_for_reply fails to find a reply, poll_for_response would
always return NULL. However, xcb_poll_for_reply may have read events
from the display connection while looking for a reply. In that case,
returning NULL from poll_for_response is wrong and can result in the
client hanging, e.g. because it returns to waiting for the display
connection file descriptor becoming readable after XPending incorrectly
returned 0 pending events.

The solution is to call poll_for_event again after xcb_poll_for_reply
returned 0. This will return the first of any events read by
xcb_poll_for_reply.

Fixes issue #79.

Reported-by: Yuxuan Shui <yshuiv7@gmail.com>
Bugzilla: https://bugs.freedesktop.org/108008
Bugzilla: https://bugs.freedesktop.org/107992
Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
Michel Dänzer 2018-09-25 17:10:58 +02:00 committed by Michel Dänzer
parent d0416863d5
commit 406afe4b0f

View file

@ -273,10 +273,19 @@ static xcb_generic_reply_t *poll_for_response(Display *dpy)
PendingRequest *req;
while(!(response = poll_for_event(dpy)) &&
(req = dpy->xcb->pending_requests) &&
!req->reply_waiter &&
xcb_poll_for_reply64(dpy->xcb->connection, req->sequence, &response, &error))
!req->reply_waiter)
{
uint64_t request = X_DPY_GET_REQUEST(dpy);
uint64_t request;
if(!xcb_poll_for_reply64(dpy->xcb->connection, req->sequence,
&response, &error)) {
/* xcb_poll_for_reply64 may have read events even if
* there is no reply. */
response = poll_for_event(dpy);
break;
}
request = X_DPY_GET_REQUEST(dpy);
if(XLIB_SEQUENCE_COMPARE(req->sequence, >, request))
{
throw_thread_fail_assert("Unknown sequence number "