summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Triplett <josh@freedesktop.org>2008-03-15 12:29:33 -0700
committerJosh Triplett <josh@freedesktop.org>2008-03-15 13:04:54 -0700
commit64325f38bab082a8e0e9ce779a8e582de5c8588e (patch)
tree58d3845b61a9198af54b50a29322b886e3bd7446
parenta5395563bbee15fabe1e8fd7aa86f9f314d8d30e (diff)
Fix fd.o bug 15023: make Xlib sync correctly given many void requests
If given many requests without replies, Xlib may not sync until it flushes the output buffer. Thus, if Xlib can fit enough requests in the buffer to pass by the number of requests it would normally sync after (65536 - BUFSIZE/sizeof(xReq)), it will sync too late. The test case in bug 15023 demonstrated this by issuing a request with a reply (ListExtensions) at just the right time to get confused with the GetInputFocus reply issued in response to the sync 65,536 requests later; the test case used an async handler to watch the replies, since otherwise it could not issue a request without waiting for the response. When the test case failed, Xlib's sync handler would eat the ListExtensions reply, and the test case's async handler would see the GetInputFocus reply. Fix this by replacing SEQLIMIT with a function sync_hazard() that uses the buffer size to figure out when the sequence numbers could potentially wrap before the next flush. With this commit, the test case consistently passed, and the async reply handler always saw the ListExtensions reply. Commit by Jamey Sharp and Josh Triplett.
-rw-r--r--src/XlibInt.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/src/XlibInt.c b/src/XlibInt.c
index d6e72204..f90f8511 100644
--- a/src/XlibInt.c
+++ b/src/XlibInt.c
@@ -201,8 +201,6 @@ static char *_XAsyncReply(
Bool discard);
#endif /* !USE_XCB */
-#define SEQLIMIT (65535 - (BUFSIZE / SIZEOF(xReq)) - 10)
-
/*
* The following routines are internal routines used by Xlib for protocol
* packet transmission and reception.
@@ -565,33 +563,42 @@ _XWaitForReadable(
}
#endif /* !USE_XCB */
+static int sync_hazard(Display *dpy)
+{
+ unsigned long span = dpy->request - dpy->last_request_read;
+ unsigned long hazard = min((dpy->bufmax - dpy->buffer) / SIZEOF(xReq), 65535 - 10);
+ return span >= 65535 - hazard - 10;
+}
+
static
int _XSeqSyncFunction(
register Display *dpy)
{
xGetInputFocusReply rep;
register xReq *req;
+ int sent_sync = 0;
LockDisplay(dpy);
- if ((dpy->request - dpy->last_request_read) >= (BUFSIZE / SIZEOF(xReq))) {
+ if ((dpy->request - dpy->last_request_read) >= (65535 - BUFSIZE/SIZEOF(xReq))) {
GetEmptyReq(GetInputFocus, req);
(void) _XReply (dpy, (xReply *)&rep, 0, xTrue);
+ sent_sync = 1;
}
/* could get XID handler while waiting for reply in MT env */
- if (dpy->synchandler == _XSeqSyncFunction) {
+ if (dpy->synchandler == _XSeqSyncFunction && !sync_hazard(dpy)) {
dpy->synchandler = dpy->savedsynchandler;
dpy->flags &= ~XlibDisplayPrivSync;
}
UnlockDisplay(dpy);
- SyncHandle();
+ if (sent_sync)
+ SyncHandle();
return 0;
}
void _XSetSeqSyncFunction(
register Display *dpy)
{
- if ((dpy->request - dpy->last_request_read) >= SEQLIMIT &&
- !(dpy->flags & XlibDisplayPrivSync)) {
+ if (!(dpy->flags & XlibDisplayPrivSync) && sync_hazard(dpy)) {
dpy->savedsynchandler = dpy->synchandler;
dpy->synchandler = _XSeqSyncFunction;
dpy->flags |= XlibDisplayPrivSync;