Refactor the code that passes requests down to XCB into a separate issue_complete_request function.

This commit is contained in:
Jamey Sharp 2006-02-21 21:25:41 -08:00
parent 67d06e0fe4
commit 41c0121a87

View file

@ -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;
}