From 53c471c6a835d5cedeca99f2c97058d196a3fd7e Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Thu, 23 Feb 2006 11:46:09 -0800 Subject: [PATCH 01/11] XCBFlush used to return non-positive on failure, and this test did not catch 0. Now it returns boolean: 0 or 1. Testing <= 0 covers both cases. I probably want to switch to a boolean test eventually. --- src/xcl/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcl/io.c b/src/xcl/io.c index 6b675af2..e4ad9d32 100644 --- a/src/xcl/io.c +++ b/src/xcl/io.c @@ -132,7 +132,7 @@ void _XSend(Display *dpy, const char *data, long size) /* give dpy->buffer to XCB */ _XPutXCBBuffer(dpy); - if(XCBFlush(c) < 0) + if(XCBFlush(c) <= 0) _XIOError(dpy); /* get a new dpy->buffer */ From ec30a27341b97620b07dd886f98d1d7664a67685 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Thu, 23 Feb 2006 18:01:46 -0800 Subject: [PATCH 02/11] Minor performance fix: Access dpy->xcl->connection directly instead of calling XCBConnectionOfDisplay. It happens a lot. --- src/xcl/io.c | 12 ++++++------ src/xcl/xcblock.c | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/xcl/io.c b/src/xcl/io.c index e4ad9d32..4d84eb03 100644 --- a/src/xcl/io.c +++ b/src/xcl/io.c @@ -90,7 +90,7 @@ int _XEventsQueued(Display *dpy, int mode) if(dpy->xcl->event_owner != XlibOwnsEventQueue) return 0; - c = XCBConnectionOfDisplay(dpy); + c = dpy->xcl->connection; if(mode == QueuedAfterFlush) _XSend(dpy, 0, 0); else @@ -110,7 +110,7 @@ void _XReadEvents(Display *dpy) _XSend(dpy, 0, 0); if(dpy->xcl->event_owner != XlibOwnsEventQueue) return; - handle_event(dpy, XCBWaitForEvent(XCBConnectionOfDisplay(dpy))); + handle_event(dpy, XCBWaitForEvent(dpy->xcl->connection)); _XEventsQueued(dpy, QueuedAfterReading); } @@ -123,7 +123,7 @@ void _XReadEvents(Display *dpy) */ void _XSend(Display *dpy, const char *data, long size) { - XCBConnection *c = XCBConnectionOfDisplay(dpy); + XCBConnection *c = dpy->xcl->connection; assert(!dpy->xcl->request_extra); dpy->xcl->request_extra = data; @@ -163,7 +163,7 @@ void _XFlush(Display *dpy) /* _XAllocID - resource ID allocation routine. */ XID _XAllocID(Display *dpy) { - return XCBGenerateID(XCBConnectionOfDisplay(dpy)); + return XCBGenerateID(dpy->xcl->connection); } /* _XAllocIDs - multiple resource ID allocation routine. */ @@ -186,7 +186,7 @@ void _XAllocIDs(Display *dpy, XID *ids, int count) unsigned long _XSetLastRequestRead(Display *dpy, xGenericReply *rep) { unsigned long newseq; - unsigned int xcb_seqnum = XCBGetRequestRead(XCBConnectionOfDisplay(dpy)); + unsigned int xcb_seqnum = XCBGetRequestRead(dpy->xcl->connection); /* * KeymapNotify has no sequence number, but is always guaranteed @@ -230,7 +230,7 @@ static void _XFreeReplyData(Display *dpy, Bool force) Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard) { XCBGenericError *error; - XCBConnection *c = XCBConnectionOfDisplay(dpy); + XCBConnection *c = dpy->xcl->connection; char *reply; assert(!dpy->xcl->reply_data); diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index 2ecc22ef..fa0331af 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -20,7 +20,7 @@ static void _XLockDisplay(Display *dpy) { - pthread_mutex_lock(XCBGetIOLock(XCBConnectionOfDisplay(dpy))); + pthread_mutex_lock(XCBGetIOLock(dpy->xcl->connection)); _XGetXCBBufferIf(dpy, _XBufferUnlocked); ++dpy->xcl->lock_count; } @@ -46,14 +46,14 @@ static void _XUnlockDisplay(Display *dpy) * invariants hold. */ if(!dpy->xcl->lock_count) { - assert(XCBGetRequestSent(XCBConnectionOfDisplay(dpy)) == dpy->request); + assert(XCBGetRequestSent(dpy->xcl->connection) == dpy->request); /* Traditional Xlib does this in _XSend; see the Xlib/XCB version * of that function for why we do it here instead. */ _XSetSeqSyncFunction(dpy); } - pthread_mutex_unlock(XCBGetIOLock(XCBConnectionOfDisplay(dpy))); + pthread_mutex_unlock(XCBGetIOLock(dpy->xcl->connection)); } void XUnlockDisplay(Display* dpy) @@ -67,12 +67,12 @@ int _XInitDisplayLock(Display *dpy) { #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; - *XCBGetIOLock(XCBConnectionOfDisplay(dpy)) = lock; + *XCBGetIOLock(dpy->xcl->connection) = lock; #else pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(XCBGetIOLock(XCBConnectionOfDisplay(dpy)), &attr); + pthread_mutex_init(XCBGetIOLock(dpy->xcl->connection), &attr); pthread_mutexattr_destroy(&attr); #endif @@ -114,7 +114,7 @@ void _XGetXCBBuffer(Display *dpy) { static const xReq dummy_request; - XCBConnection *c = XCBConnectionOfDisplay(dpy); + XCBConnection *c = dpy->xcl->connection; dpy->last_req = (char *) &dummy_request; @@ -214,7 +214,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec } /* send the accumulated request. */ - XCBSendRequest(XCBConnectionOfDisplay(dpy), &sequence, vec, &xcb_req); + XCBSendRequest(dpy->xcl->connection, &sequence, vec, &xcb_req); /* update the iovecs to refer only to data not yet sent. */ vec[i].iov_base = (char *) vec[i].iov_base + vec[i].iov_len; @@ -243,7 +243,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec void _XPutXCBBuffer(Display *dpy) { - XCBConnection *c = XCBConnectionOfDisplay(dpy); + XCBConnection *c = dpy->xcl->connection; _XExtension *ext; struct iovec iov[2]; From 409a08cff8347d39e0e6c53c9f380d21f221f5ac Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Thu, 23 Feb 2006 18:12:31 -0800 Subject: [PATCH 03/11] Performance fix: Replace calls to XCBGetRequestRead with the new XCBGetQueuedRequestRead. Cuts a lot of syscalls. --- src/xcl/io.c | 3 ++- src/xcl/xcblock.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/xcl/io.c b/src/xcl/io.c index 4d84eb03..b125fbea 100644 --- a/src/xcl/io.c +++ b/src/xcl/io.c @@ -4,6 +4,7 @@ #include "Xlibint.h" #include "xclint.h" #include +#include #include #include @@ -186,7 +187,7 @@ void _XAllocIDs(Display *dpy, XID *ids, int count) unsigned long _XSetLastRequestRead(Display *dpy, xGenericReply *rep) { unsigned long newseq; - unsigned int xcb_seqnum = XCBGetRequestRead(dpy->xcl->connection); + unsigned int xcb_seqnum = XCBGetQueuedRequestRead(dpy->xcl->connection); /* * KeymapNotify has no sequence number, but is always guaranteed diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index fa0331af..46fc4d59 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -127,7 +127,7 @@ void _XGetXCBBuffer(Display *dpy) PendingRequest *req = dpy->xcl->pending_requests; /* If this request hasn't been read off the wire yet, save the * rest for later. */ - if((signed int) (XCBGetRequestRead(c) - req->sequence) <= 0) + if((signed int) (XCBGetQueuedRequestRead(c) - req->sequence) <= 0) break; dpy->xcl->pending_requests = req->next; /* This can't block due to the above test, but it could "fail" @@ -145,7 +145,7 @@ void _XGetXCBBuffer(Display *dpy) if(!dpy->xcl->pending_requests) dpy->xcl->pending_requests_tail = &dpy->xcl->pending_requests; - dpy->last_request_read = XCBGetRequestRead(c); + dpy->last_request_read = XCBGetQueuedRequestRead(c); assert_sequence_less(dpy->last_request_read, dpy->request); } From 07bdf1fbbf2418f866df1a2140d514dd3f035139 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Sun, 26 Feb 2006 15:46:01 -0800 Subject: [PATCH 04/11] Update for new XCBSendRequest API. --- src/xcl/xcblock.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index 46fc4d59..709fb67f 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -153,6 +153,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec { XCBProtocolRequest xcb_req = { 0 }; unsigned int sequence; + int flags = 0; int bigreq = 0; int i; CARD32 len; @@ -213,8 +214,13 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec vec[0].iov_len -= 4; } + /* if we don't own the event queue, we have to ask XCB to set our + * errors aside for us. */ + if(dpy->xcl->event_owner != XlibOwnsEventQueue) + flags |= XCB_REQUEST_CHECKED; + /* send the accumulated request. */ - XCBSendRequest(dpy->xcl->connection, &sequence, vec, &xcb_req); + XCBSendRequest(dpy->xcl->connection, &sequence, flags, vec, &xcb_req); /* update the iovecs to refer only to data not yet sent. */ vec[i].iov_base = (char *) vec[i].iov_base + vec[i].iov_len; @@ -222,14 +228,11 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec while(--i >= 0) vec[i].iov_len = 0; - /* For requests we issue, we need to get back replies and - * errors. That's true even if we don't own the event queue, and - * also if there are async handlers registered. If we do own the - * event queue then errors can be handled elsewhere more - * cheaply; and if there aren't any async handlers (but the - * pure-Xlib code was correct) then there won't be any replies - * so we needn't look for them. */ - if(dpy->xcl->event_owner != XlibOwnsEventQueue || dpy->async_handlers) + /* iff we asked XCB to set aside errors, we must pick those up + * eventually. iff there are async handlers, we may have just + * issued requests that will generate replies. in either case, + * we need to remember to check later. */ + if(flags & XCB_REQUEST_CHECKED || dpy->async_handlers) { PendingRequest *req = malloc(sizeof(PendingRequest)); assert(req); From 8356ba37d307a9eda895a6bf41ef727bbfc9a695 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Mon, 27 Feb 2006 11:51:47 -0800 Subject: [PATCH 05/11] Use the new XCBSendRequest flag, XCB_REQUEST_RAW, to hand a bag-o-bytes down uninterpreted. --- src/xcl/xcblock.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index 709fb67f..56decd65 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -153,8 +153,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec { XCBProtocolRequest xcb_req = { 0 }; unsigned int sequence; - int flags = 0; - int bigreq = 0; + int flags = XCB_REQUEST_RAW; int i; CARD32 len; size_t rem; @@ -170,11 +169,8 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec * fixed-length request parts. */ len = ((CARD16 *) vec[0].iov_base)[1]; if(len == 0) - { /* it's a bigrequest. dig out the *real* length field. */ len = ((CARD32 *) vec[0].iov_base)[1]; - bigreq = 1; - } /* do we have enough data for a complete request? how many iovec * elements does it span? */ @@ -205,15 +201,6 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec xcb_req.count = i + 1; xcb_req.opcode = ((CARD8 *) vec[0].iov_base)[0]; - /* undo bigrequest formatting. XCBSendRequest will redo it. */ - if(bigreq) - { - CARD32 *p = vec[0].iov_base; - p[1] = p[0]; - vec[0].iov_base = (char *) vec[0].iov_base + 4; - vec[0].iov_len -= 4; - } - /* if we don't own the event queue, we have to ask XCB to set our * errors aside for us. */ if(dpy->xcl->event_owner != XlibOwnsEventQueue) From fb590c15a740264ee867d15a2547072e43b21eed Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Thu, 2 Mar 2006 12:06:04 -0800 Subject: [PATCH 06/11] Handle errors correctly when Xlib owns the event queue and XCB has the checked error feature. --- src/xcl/io.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/xcl/io.c b/src/xcl/io.c index b125fbea..e57cafe2 100644 --- a/src/xcl/io.c +++ b/src/xcl/io.c @@ -232,6 +232,7 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard) { XCBGenericError *error; XCBConnection *c = dpy->xcl->connection; + unsigned long request = dpy->request; char *reply; assert(!dpy->xcl->reply_data); @@ -239,11 +240,30 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard) UnlockDisplay(dpy); /* release buffer if UnlockDisplay didn't already */ _XPutXCBBufferIf(dpy, _XBufferLocked); - reply = XCBWaitForReply(c, dpy->request, &error); + reply = XCBWaitForReply(c, request, &error); /* re-acquire buffer if LockDisplay won't otherwise */ _XGetXCBBufferIf(dpy, _XBufferLocked); LockDisplay(dpy); + check_internal_connections(dpy); + + if(dpy->xcl->event_owner == XlibOwnsEventQueue) + { + XCBGenericEvent *e; + int ret; + while((e = XCBPollForEvent(c, &ret))) + { + /* FIXME: This should use _XSetLastRequestRead + * to decide if the sequence number is the one + * we're looking for, or XCB should provide the + * 32-bit sequence with every event. */ + if(e->response_type == 0 && e->sequence == (request & 0xffff)) + error = (XCBGenericError *) e; + else + handle_event(dpy, e); + } + } + if(error) { _XExtension *ext; @@ -308,8 +328,6 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard) memcpy(rep, dpy->xcl->reply_data, dpy->xcl->reply_consumed); _XFreeReplyData(dpy, discard); - - _XEventsQueued(dpy, QueuedAfterReading); return 1; } From d3512ef3aae5b036a8ce6579318108f1ec20ee22 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Thu, 2 Mar 2006 15:58:52 -0800 Subject: [PATCH 07/11] Quit relying on XCBSendRequest to pad to 4-byte boundaries and do it ourselves. --- src/xcl/xcblock.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index 56decd65..ee48608c 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -155,8 +155,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec unsigned int sequence; int flags = XCB_REQUEST_RAW; int i; - CARD32 len; - size_t rem; + size_t len; /* skip empty iovecs. if no iovecs remain, we're done. */ while(veclen > 0 && vec[0].iov_len == 0) @@ -171,13 +170,14 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec if(len == 0) /* it's a bigrequest. dig out the *real* length field. */ len = ((CARD32 *) vec[0].iov_base)[1]; + len <<= 2; /* do we have enough data for a complete request? how many iovec * elements does it span? */ for(i = 0; i < veclen; ++i) { - CARD32 oldlen = len; - len -= (vec[i].iov_len + 3) >> 2; + size_t oldlen = len; + len -= vec[i].iov_len; /* if len is now 0 or has wrapped, we have enough data. */ if((len - 1) > oldlen) break; @@ -188,16 +188,9 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec /* we have enough data to issue one complete request. the remaining * code can't fail. */ - /* len says how far we overshot our data needs in 4-byte units. - * (it's negative if we actually overshot, or 0 if we're right on.) - * rem is overshoot in 1-byte units, so it needs to have trailing - * padding subtracted off if we're not using that padding in this - * request. */ - if(len) - rem = (-len << 2) - (-vec[i].iov_len & 3); - else - rem = 0; - vec[i].iov_len -= rem; + /* len says how far we overshot our data needs. (it's "negative" if + * we actually overshot, or 0 if we're right on.) */ + vec[i].iov_len += len; xcb_req.count = i + 1; xcb_req.opcode = ((CARD8 *) vec[0].iov_base)[0]; @@ -211,7 +204,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec /* update the iovecs to refer only to data not yet sent. */ vec[i].iov_base = (char *) vec[i].iov_base + vec[i].iov_len; - vec[i].iov_len = rem; + vec[i].iov_len = -len; while(--i >= 0) vec[i].iov_len = 0; @@ -233,9 +226,11 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec void _XPutXCBBuffer(Display *dpy) { + static char const pad[3]; + const int padsize = -dpy->xcl->request_extra_size & 3; XCBConnection *c = dpy->xcl->connection; _XExtension *ext; - struct iovec iov[2]; + struct iovec iov[5]; assert_sequence_less(dpy->last_request_read, dpy->request); assert_sequence_less(XCBGetRequestSent(c), dpy->request); @@ -245,8 +240,6 @@ void _XPutXCBBuffer(Display *dpy) ext->before_flush(dpy, &ext->codes, dpy->buffer, dpy->bufptr - dpy->buffer); if(dpy->xcl->request_extra) { - static char const pad[3]; - int padsize = -dpy->xcl->request_extra_size & 3; ext->before_flush(dpy, &ext->codes, dpy->xcl->request_extra, dpy->xcl->request_extra_size); if(padsize) ext->before_flush(dpy, &ext->codes, pad, padsize); @@ -257,11 +250,13 @@ void _XPutXCBBuffer(Display *dpy) iov[0].iov_len = dpy->bufptr - dpy->buffer; iov[1].iov_base = (caddr_t) dpy->xcl->request_extra; iov[1].iov_len = dpy->xcl->request_extra_size; + iov[2].iov_base = (caddr_t) pad; + iov[2].iov_len = padsize; - while(issue_complete_request(dpy, 2, iov)) + while(issue_complete_request(dpy, 3, iov)) /* empty */; - assert(iov[0].iov_len == 0 && iov[1].iov_len == 0); + assert(iov[0].iov_len == 0 && iov[1].iov_len == 0 && iov[2].iov_len == 0); dpy->xcl->request_extra = 0; dpy->xcl->request_extra_size = 0; From f9afb5a54435c30961306080e9358d4240ecb844 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Thu, 2 Mar 2006 23:34:19 -0800 Subject: [PATCH 08/11] assert() that we will not infinite loop or read uninitialized memory. --- src/xcl/xcblock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index ee48608c..c0a2db91 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -158,6 +158,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec size_t len; /* skip empty iovecs. if no iovecs remain, we're done. */ + assert(veclen >= 0); while(veclen > 0 && vec[0].iov_len == 0) --veclen, ++vec; if(!veclen) @@ -166,10 +167,14 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec /* we have at least part of a request. dig out the length field. * note that length fields are always in vec[0]: Xlib doesn't split * fixed-length request parts. */ + assert(vec[0].iov_len >= 4); len = ((CARD16 *) vec[0].iov_base)[1]; if(len == 0) + { /* it's a bigrequest. dig out the *real* length field. */ + assert(vec[0].iov_len >= 8); len = ((CARD32 *) vec[0].iov_base)[1]; + } len <<= 2; /* do we have enough data for a complete request? how many iovec From d8ba4ae7045b227f8b675628b9094dded02f1c08 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Thu, 2 Mar 2006 23:43:26 -0800 Subject: [PATCH 09/11] Bugfix: Rely on XCBSendRequest to leave iov in a well-defined state, and place the spare iovecs at the beginning of the array. --- src/xcl/xcblock.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index c0a2db91..1909f2d0 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -208,10 +208,7 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec XCBSendRequest(dpy->xcl->connection, &sequence, flags, vec, &xcb_req); /* update the iovecs to refer only to data not yet sent. */ - vec[i].iov_base = (char *) vec[i].iov_base + vec[i].iov_len; vec[i].iov_len = -len; - while(--i >= 0) - vec[i].iov_len = 0; /* iff we asked XCB to set aside errors, we must pick those up * eventually. iff there are async handlers, we may have just @@ -251,17 +248,17 @@ void _XPutXCBBuffer(Display *dpy) } } - iov[0].iov_base = dpy->buffer; - iov[0].iov_len = dpy->bufptr - dpy->buffer; - iov[1].iov_base = (caddr_t) dpy->xcl->request_extra; - iov[1].iov_len = dpy->xcl->request_extra_size; - iov[2].iov_base = (caddr_t) pad; - iov[2].iov_len = padsize; + iov[2].iov_base = dpy->buffer; + iov[2].iov_len = dpy->bufptr - dpy->buffer; + iov[3].iov_base = (caddr_t) dpy->xcl->request_extra; + iov[3].iov_len = dpy->xcl->request_extra_size; + iov[4].iov_base = (caddr_t) pad; + iov[4].iov_len = padsize; - while(issue_complete_request(dpy, 3, iov)) + while(issue_complete_request(dpy, 3, iov + 2)) /* empty */; - assert(iov[0].iov_len == 0 && iov[1].iov_len == 0 && iov[2].iov_len == 0); + assert(iov[2].iov_len == 0 && iov[3].iov_len == 0 && iov[4].iov_len == 0); dpy->xcl->request_extra = 0; dpy->xcl->request_extra_size = 0; From a11d1b0ae674320cf9897f6a83ec08c65eca8d9b Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Fri, 3 Mar 2006 01:42:49 -0800 Subject: [PATCH 10/11] Use the full_sequence from XCBGenericError/Event for setting last_request_read, and quit replacing _XSetLastRequestRead with an XCB-specific version. --- src/XlibInt.c | 2 ++ src/xcl/io.c | 52 ++++++----------------------------------------- src/xcl/xcblock.c | 6 ++++-- 3 files changed, 12 insertions(+), 48 deletions(-) diff --git a/src/XlibInt.c b/src/XlibInt.c index 82737f89..d1229155 100644 --- a/src/XlibInt.c +++ b/src/XlibInt.c @@ -1622,6 +1622,7 @@ void _XAllocIDs( for (i = grep.count; i < count; i++) ids[i] = XAllocID(dpy); } +#endif /* !USE_XCB */ /* * The hard part about this is that we only get 16 bits from a reply. @@ -1666,6 +1667,7 @@ _XSetLastRequestRead( return(newseq); } +#if !USE_XCB /* * _XReply - Wait for a reply packet and copy its contents into the * specified rep. Meanwhile we must handle error and event packets that diff --git a/src/xcl/io.c b/src/xcl/io.c index e57cafe2..6f3936d7 100644 --- a/src/xcl/io.c +++ b/src/xcl/io.c @@ -71,6 +71,7 @@ static void handle_event(Display *dpy, XCBGenericEvent *e) { if(!e) _XIOError(dpy); + dpy->last_request_read = e->full_sequence; if(e->response_type == X_Error) _XError(dpy, (xError *) e); else @@ -175,45 +176,6 @@ void _XAllocIDs(Display *dpy, XID *ids, int count) ids[i] = XAllocID(dpy); } -/* - * The hard part about this is that we only get 16 bits from a reply. - * We have three values that will march along, with the following invariant: - * dpy->last_request_read <= rep->sequenceNumber <= dpy->request - * We have to keep - * dpy->request - dpy->last_request_read < 2^16 - * or else we won't know for sure what value to use in events. We do this - * by forcing syncs when we get close. - */ -unsigned long _XSetLastRequestRead(Display *dpy, xGenericReply *rep) -{ - unsigned long newseq; - unsigned int xcb_seqnum = XCBGetQueuedRequestRead(dpy->xcl->connection); - - /* - * KeymapNotify has no sequence number, but is always guaranteed - * to immediately follow another event, except when generated via - * SendEvent (hmmm). - */ - if ((rep->type & 0x7f) == KeymapNotify) - return(dpy->last_request_read); - - newseq = (xcb_seqnum & ~((unsigned long)0xffff)) | rep->sequenceNumber; - - /* We're always trailing XCB's processing of responses here: - * when we see a response, it's always one that XCB has already - * counted in its sequence number stream. So we ensure that the - * 32-bit sequence number that we pick is, in fact, less than or - * equal to the last thing XCB processed, taking wrap into - * account. */ - if (newseq > xcb_seqnum) - newseq -= 0x10000; - assert_sequence_less(newseq, dpy->request); - - dpy->last_request_read = newseq; - assert_sequence_less(dpy->last_request_read, xcb_seqnum); - return(newseq); -} - static void _XFreeReplyData(Display *dpy, Bool force) { if(!force && dpy->xcl->reply_consumed < dpy->xcl->reply_length) @@ -252,16 +214,10 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard) XCBGenericEvent *e; int ret; while((e = XCBPollForEvent(c, &ret))) - { - /* FIXME: This should use _XSetLastRequestRead - * to decide if the sequence number is the one - * we're looking for, or XCB should provide the - * 32-bit sequence with every event. */ - if(e->response_type == 0 && e->sequence == (request & 0xffff)) + if(e->response_type == 0 && e->full_sequence == request) error = (XCBGenericError *) e; else handle_event(dpy, e); - } } if(error) @@ -270,6 +226,8 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard) xError *err = (xError *) error; int ret_code; + dpy->last_request_read = error->full_sequence; + /* Xlib is evil and assumes that even errors will be * copied into rep. */ memcpy(rep, error, 32); @@ -315,6 +273,8 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard) return 0; } + dpy->last_request_read = request; + /* there's no error and we have a reply. */ dpy->xcl->reply_data = reply; dpy->xcl->reply_consumed = sizeof(xReply) + (extra * 4); diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index 1909f2d0..5a057241 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -99,7 +99,6 @@ void _XFreeDisplayLock(Display *dpy) static void call_handlers(Display *dpy, XCBGenericRep *buf) { _XAsyncHandler *async, *next; - _XSetLastRequestRead(dpy, (xGenericReply *) buf); for(async = dpy->async_handlers; async; async = next) { next = async->next; @@ -135,11 +134,14 @@ void _XGetXCBBuffer(Display *dpy) * don't care. In any failure cases, we must not have wanted * an entry in the reply queue for this request after all. */ reply = XCBWaitForReply(c, req->sequence, &error); - free(req); if(!reply) reply = (XCBGenericRep *) error; if(reply) + { + dpy->last_request_read = req->sequence; call_handlers(dpy, reply); + } + free(req); free(reply); } if(!dpy->xcl->pending_requests) From f71ea0bc737c5a42e9e022b86e7ec3b4f846d31c Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Fri, 3 Mar 2006 11:08:41 -0800 Subject: [PATCH 11/11] Update for XCBSendRequest sequence number API changes. --- src/xcl/xcblock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index 5a057241..1a5eb4f8 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -207,7 +207,9 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec flags |= XCB_REQUEST_CHECKED; /* send the accumulated request. */ - XCBSendRequest(dpy->xcl->connection, &sequence, flags, vec, &xcb_req); + sequence = XCBSendRequest(dpy->xcl->connection, flags, vec, &xcb_req); + if(!sequence) + _XIOError(dpy); /* update the iovecs to refer only to data not yet sent. */ vec[i].iov_len = -len;