wait_for_reply() & _xcb_conn_wait() can end up in an infinite loop on Mac
I have been using a tweaked Qt5 that accepts to build the XCB platform plugin on Mac, for a number of years now. This works very nicely on the local XQuartz server, but less so remotely. When the mouse position is queried too frequently (idem for other operations requiring a reply from the server?) the code ends up in an infinite loop between wait_for_reply()
and the underlying _xcb_conn_wait()
.
I started looking into this and added trace output to both functions. Trying to be explicitly certain not to print stale values I added a reset of the errno variable in _xcb_conn_wait()
... because I'm never confident that functions reset that variable. (It actually make sense not to, for performance reasons.)
I think that simple reset fixed the issue, I haven't been able to trigger it in any case. Simply out-commenting the reset in the attached patch immediately causes a continues stream of trace output where each non-zero errno value is printed multiple times. That does support my suspicion that the variable has to be reset explicitly.
The function Qt uses to obtain the current mouse position:
void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
{
if (pos)
*pos = QPoint();
xcb_window_t root = c->primaryVirtualDesktop()->root();
xcb_query_pointer_cookie_t cookie = xcb_query_pointer(c->xcb_connection(), root);
xcb_generic_error_t *err = 0;
xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c->xcb_connection(), cookie, &err);
if (!err && reply) {
if (virtualDesktop) {
const auto virtualDesktops = c->virtualDesktops();
for (QXcbVirtualDesktop *vd : virtualDesktops) {
if (vd->root() == reply->root) {
*virtualDesktop = vd;
break;
}
}
}
if (pos)
*pos = QPoint(reply->root_x, reply->root_y);
if (keybMask)
*keybMask = reply->mask;
free(reply);
return;
}
free(err);
free(reply);
}
My current patch: patch-xcbwaitreply-hang.diff
The trace output in wait_for_reply()
is probably pointless because the looping while _xcb_conn_wait() == 1
probably corresponds to reading from the server until there is no more to read?