X-Git-Url: http://git.demorecorder.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fxcb_in.c;h=3bf54f3b8f27c40a0a38a2335b5902ebd94e7a5a;hb=2a18842f0f93516ff726a2dfa44348410bb55626;hp=4ad4654b94b11adcc5e31569f32d0c769f0b2ebe;hpb=7667adbc631119ec39f3ef5a316aec42dbf5f393;p=free-sw%2Fxcb%2Flibxcb diff --git a/src/xcb_in.c b/src/xcb_in.c index 4ad4654..3bf54f3 100644 --- a/src/xcb_in.c +++ b/src/xcb_in.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "xcb.h" @@ -243,23 +244,33 @@ static int poll_for_reply(XCBConnection *c, unsigned int request, void **reply, { struct reply_list *head; + /* If an error occurred when issuing the request, fail immediately. */ if(!request) head = 0; - else if(c->in.request_completed >= request) + /* We've read requests past the one we want, so if it has replies we have + * them all and they're in the replies map. */ + else if(request < c->in.request_read) { head = _xcb_map_remove(c->in.replies, request); if(head && head->next) _xcb_map_put(c->in.replies, request, head->next); } - else if(c->in.request_read == request && c->in.current_reply) + /* We're currently processing the responses to the request we want, and we + * have a reply ready to return. So just return it without blocking. */ + else if(request == c->in.request_read && c->in.current_reply) { head = c->in.current_reply; c->in.current_reply = head->next; if(!head->next) c->in.current_reply_tail = &c->in.current_reply; } + /* We know this request can't have any more replies, and we've already + * established it doesn't have a reply now. Don't bother blocking. */ + else if(request == c->in.request_completed) + head = 0; + /* We may have more replies on the way for this request: block until we're + * sure. */ else - /* Would block: do nothing. */ return 0; if(error) @@ -288,81 +299,39 @@ static int poll_for_reply(XCBConnection *c, unsigned int request, void **reply, void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **e) { - pthread_cond_t cond = PTHREAD_COND_INITIALIZER; - reader_list reader; - reader_list **prev_reader; - struct reply_list *head; void *ret = 0; if(e) *e = 0; - /* If an error occurred when issuing the request, fail immediately. */ - if(!request) - return 0; - pthread_mutex_lock(&c->iolock); /* If this request has not been written yet, write it. */ - if(!_xcb_out_flush_to(c, request)) - goto done; /* error */ - - for(prev_reader = &c->in.readers; *prev_reader && (*prev_reader)->request <= request; prev_reader = &(*prev_reader)->next) - if((*prev_reader)->request == request) - goto done; /* error */ - - reader.request = request; - reader.data = &cond; - reader.next = *prev_reader; - *prev_reader = &reader; - - /* If this request has not completed yet and has no reply waiting, - * wait for one. */ - while(c->in.request_completed < request && - !(c->in.request_read == request && c->in.current_reply)) - if(!_xcb_conn_wait(c, &cond, 0, 0)) - goto done; - - if(c->in.request_read != request) + if(_xcb_out_flush_to(c, request)) { - head = _xcb_map_remove(c->in.replies, request); - if(head && head->next) - _xcb_map_put(c->in.replies, request, head->next); - } - else - { - head = c->in.current_reply; - if(head) - { - c->in.current_reply = head->next; - if(!head->next) - c->in.current_reply_tail = &c->in.current_reply; - } - } - - if(head) - { - ret = head->reply; - free(head); + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + reader_list reader; + reader_list **prev_reader; + + for(prev_reader = &c->in.readers; *prev_reader && (*prev_reader)->request <= request; prev_reader = &(*prev_reader)->next) + /* empty */; + reader.request = request; + reader.data = &cond; + reader.next = *prev_reader; + *prev_reader = &reader; + + while(!poll_for_reply(c, request, &ret, e)) + if(!_xcb_conn_wait(c, &cond, 0, 0)) + break; - if(((XCBGenericRep *) ret)->response_type == XCBError) - { - if(e) - *e = ret; - else - free(ret); - ret = 0; - } + for(prev_reader = &c->in.readers; *prev_reader && (*prev_reader)->request <= request; prev_reader = &(*prev_reader)->next) + if(*prev_reader == &reader) + { + *prev_reader = (*prev_reader)->next; + break; + } + pthread_cond_destroy(&cond); } -done: - for(prev_reader = &c->in.readers; *prev_reader && (*prev_reader)->request <= request; prev_reader = &(*prev_reader)->next) - if(*prev_reader == &reader) - { - *prev_reader = (*prev_reader)->next; - break; - } - pthread_cond_destroy(&cond); - wake_up_next_reader(c); pthread_mutex_unlock(&c->iolock); return ret; @@ -474,18 +443,16 @@ void _xcb_in_destroy(_xcb_in *in) int _xcb_in_expect_reply(XCBConnection *c, unsigned int request, enum workarounds workaround, int flags) { - if(workaround != WORKAROUND_NONE || flags != 0) - { - pending_reply *pend = malloc(sizeof(pending_reply)); - if(!pend) - return 0; - pend->request = request; - pend->workaround = workaround; - pend->flags = flags; - pend->next = 0; - *c->in.pending_replies_tail = pend; - c->in.pending_replies_tail = &pend->next; - } + pending_reply *pend = malloc(sizeof(pending_reply)); + assert(workaround != WORKAROUND_NONE || flags != 0); + if(!pend) + return 0; + pend->request = request; + pend->workaround = workaround; + pend->flags = flags; + pend->next = 0; + *c->in.pending_replies_tail = pend; + c->in.pending_replies_tail = &pend->next; return 1; }