From 41c0121a8718b530feaf7fe315b673d9b8defce2 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Tue, 21 Feb 2006 21:25:41 -0800 Subject: [PATCH] Refactor the code that passes requests down to XCB into a separate issue_complete_request function. --- src/xcl/xcblock.c | 148 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 46 deletions(-) diff --git a/src/xcl/xcblock.c b/src/xcl/xcblock.c index fc0564b8..2ecc22ef 100644 --- a/src/xcl/xcblock.c +++ b/src/xcl/xcblock.c @@ -149,12 +149,103 @@ void _XGetXCBBuffer(Display *dpy) assert_sequence_less(dpy->last_request_read, dpy->request); } +static inline int issue_complete_request(Display *dpy, int veclen, struct iovec *vec) +{ + XCBProtocolRequest xcb_req = { 0 }; + unsigned int sequence; + int bigreq = 0; + int i; + CARD32 len; + size_t rem; + + /* skip empty iovecs. if no iovecs remain, we're done. */ + while(veclen > 0 && vec[0].iov_len == 0) + --veclen, ++vec; + if(!veclen) + return 0; + + /* 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. */ + 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? */ + for(i = 0; i < veclen; ++i) + { + CARD32 oldlen = len; + len -= (vec[i].iov_len + 3) >> 2; + /* if len is now 0 or has wrapped, we have enough data. */ + if((len - 1) > oldlen) + break; + } + if(i == veclen) + return 0; + + /* 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; + 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; + } + + /* send the accumulated request. */ + XCBSendRequest(XCBConnectionOfDisplay(dpy), &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; + vec[i].iov_len = rem; + 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) + { + PendingRequest *req = malloc(sizeof(PendingRequest)); + assert(req); + req->next = 0; + req->sequence = sequence; + *dpy->xcl->pending_requests_tail = req; + dpy->xcl->pending_requests_tail = &req->next; + } + return 1; +} + void _XPutXCBBuffer(Display *dpy) { XCBConnection *c = XCBConnectionOfDisplay(dpy); _XExtension *ext; - XCBProtocolRequest xcb_req = { /* count */ 1 }; - char *bufptr = dpy->buffer; + struct iovec iov[2]; assert_sequence_less(dpy->last_request_read, dpy->request); assert_sequence_less(XCBGetRequestSent(c), dpy->request); @@ -172,53 +263,18 @@ void _XPutXCBBuffer(Display *dpy) } } - while(bufptr < dpy->bufptr) - { - struct iovec iov[2]; - unsigned int sequence; - CARD32 len = ((CARD16 *) bufptr)[1]; - if(len == 0) - len = ((CARD32 *) bufptr)[1]; + 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; - xcb_req.opcode = bufptr[0]; - iov[0].iov_base = (caddr_t) bufptr; - iov[0].iov_len = len << 2; + while(issue_complete_request(dpy, 2, iov)) + /* empty */; - /* if we have extra request data and this is the last request - * in the buffer, send the extra data along with this request. */ - if(bufptr == dpy->last_req && dpy->xcl->request_extra && dpy->xcl->request_extra_size) - { - xcb_req.count = 2; - iov[1].iov_base = (void *) dpy->xcl->request_extra; - iov[1].iov_len = dpy->xcl->request_extra_size; - iov[0].iov_len -= iov[1].iov_len; - iov[0].iov_len &= ~3; - dpy->xcl->request_extra = 0; - assert(bufptr + iov[0].iov_len == dpy->bufptr); - } + assert(iov[0].iov_len == 0 && iov[1].iov_len == 0); - bufptr += iov[0].iov_len; - assert(bufptr <= dpy->bufptr); - - XCBSendRequest(c, &sequence, iov, &xcb_req); - - /* 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) - { - PendingRequest *req = malloc(sizeof(PendingRequest)); - assert(req); - req->next = 0; - req->sequence = sequence; - *dpy->xcl->pending_requests_tail = req; - dpy->xcl->pending_requests_tail = &req->next; - } - } + dpy->xcl->request_extra = 0; + dpy->xcl->request_extra_size = 0; dpy->bufptr = dpy->buffer; }