diff options
author | Josh Triplett <josh@freedesktop.org> | 2008-03-15 12:29:33 -0700 |
---|---|---|
committer | Josh Triplett <josh@freedesktop.org> | 2008-03-15 13:04:54 -0700 |
commit | 64325f38bab082a8e0e9ce779a8e582de5c8588e (patch) | |
tree | 58d3845b61a9198af54b50a29322b886e3bd7446 | |
parent | a5395563bbee15fabe1e8fd7aa86f9f314d8d30e (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.c | 21 |
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; |