summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamey Sharp <jamey@minilop.net>2011-03-14 14:45:35 -0700
committerJamey Sharp <jamey@minilop.net>2011-03-14 14:45:35 -0700
commitfd85aca7a616c595fc17b2520f84316a11e8906f (patch)
tree14a6d95e76074a06552a31f883dbfac3ee4bcdc0
parent690f8bffd48a4e7e74298360ddd0431dc95dcd3f (diff)
Ignore user locks after sleeping in _XReply and _XReadEvents.
This bug appears as a hang in applications that wait for replies from multiple threads, where one such thread has taken a user lock using XLockDisplay. Prior to this fix, the code could deadlock in this way: If thread 1 goes to sleep waiting for a reply, and then thread 2 takes a user lock and waits for a reply, then thread 2 will wait for thread 1 to process its reply (because responses must be processed in order), but thread 1 will wait for thread 2 to drop its user lock. Fixed by making thread 1 not wait for thread 2 to drop its user lock. This makes the semantics of user locks hard to define, but they were already hard to define. The new behavior appears to be consistent with the way Xlib worked historically, anyway. Fixes: http://lists.freedesktop.org/archives/xcb/2011-March/006802.html There was a similar potential for deadlock in _XReadEvents, fixed the same way, with the same caveats about user-lock semantics. Signed-off-by: Jamey Sharp <jamey@minilop.net>
-rw-r--r--src/xcb_io.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/src/xcb_io.c b/src/xcb_io.c
index 7e685de..8930736 100644
--- a/src/xcb_io.c
+++ b/src/xcb_io.c
@@ -340,7 +340,15 @@ void _XReadEvents(Display *dpy)
dpy->xcb->event_waiter = 1;
UnlockDisplay(dpy);
event = xcb_wait_for_event(dpy->xcb->connection);
- InternalLockDisplay(dpy, /* don't skip user locks */ 0);
+ /* It appears that classic Xlib respected user
+ * locks when waking up after waiting for
+ * events. However, if this thread did not have
+ * any user locks, and another thread takes a
+ * user lock and tries to read events, then we'd
+ * deadlock. So we'll choose to let the thread
+ * that got in first consume events, despite the
+ * later thread's user locks. */
+ InternalLockDisplay(dpy, /* ignore user locks */ 1);
dpy->xcb->event_waiter = 0;
ConditionBroadcast(dpy, dpy->xcb->event_notify);
if(!event)
@@ -531,7 +539,10 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
req->reply_waiter = 1;
UnlockDisplay(dpy);
response = xcb_wait_for_reply(c, req->sequence, &error);
- InternalLockDisplay(dpy, /* don't skip user locks */ 0);
+ /* Any user locks on another thread must have been taken
+ * while we slept in xcb_wait_for_reply. Classic Xlib
+ * ignored those user locks in this case, so we do too. */
+ InternalLockDisplay(dpy, /* ignore user locks */ 1);
/* We have the response we're looking for. Now, before
* letting anyone else process this sequence number, we