Merge branch 'master' of git+ssh://herrb@git.freedesktop.org/git/xorg/lib/libX11

This commit is contained in:
Matthieu Herrb 2006-03-11 15:40:35 +01:00
commit e876efb8aa
3 changed files with 77 additions and 105 deletions

View file

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

View file

@ -4,6 +4,7 @@
#include "Xlibint.h"
#include "xclint.h"
#include <X11/XCB/xcbext.h>
#include <X11/XCB/xcbxlib.h>
#include <assert.h>
#include <stdlib.h>
@ -70,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
@ -90,7 +92,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 +112,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 +125,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;
@ -132,7 +134,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 */
@ -163,7 +165,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. */
@ -174,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 = XCBGetRequestRead(XCBConnectionOfDisplay(dpy));
/*
* 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)
@ -230,7 +193,8 @@ 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;
unsigned long request = dpy->request;
char *reply;
assert(!dpy->xcl->reply_data);
@ -238,17 +202,32 @@ 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)))
if(e->response_type == 0 && e->full_sequence == request)
error = (XCBGenericError *) e;
else
handle_event(dpy, e);
}
if(error)
{
_XExtension *ext;
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);
@ -294,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);
@ -307,8 +288,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;
}

View file

@ -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
@ -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;
@ -114,7 +113,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;
@ -127,7 +126,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"
@ -135,17 +134,20 @@ 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)
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);
}
@ -153,12 +155,12 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec
{
XCBProtocolRequest xcb_req = { 0 };
unsigned int sequence;
int bigreq = 0;
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. */
assert(veclen >= 0);
while(veclen > 0 && vec[0].iov_len == 0)
--veclen, ++vec;
if(!veclen)
@ -167,20 +169,22 @@ 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];
bigreq = 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;
@ -191,45 +195,30 @@ 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];
/* 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)
flags |= XCB_REQUEST_CHECKED;
/* send the accumulated request. */
XCBSendRequest(XCBConnectionOfDisplay(dpy), &sequence, 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_base = (char *) vec[i].iov_base + vec[i].iov_len;
vec[i].iov_len = rem;
while(--i >= 0)
vec[i].iov_len = 0;
vec[i].iov_len = -len;
/* 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);
@ -243,9 +232,11 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec
void _XPutXCBBuffer(Display *dpy)
{
XCBConnection *c = XCBConnectionOfDisplay(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);
@ -255,23 +246,23 @@ 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);
}
}
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 = 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, 2, iov))
while(issue_complete_request(dpy, 3, iov + 2))
/* empty */;
assert(iov[0].iov_len == 0 && iov[1].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;