Support xcb_discard_reply
This function is useful for dynamic language garbage collectors. Frequently a GC cycle may run before you want to block wainting for a reply. This function is also marginally useful for libxcb apps that issue speculative requests (eg. xlsclients). Reviewed-by: Jamey Sharp <jamey@minilop.net> Tested-by: Eamon Walsh <efw@eamonwalsh.com> Signed-off-by: Peter Harris <pharris@opentext.com>
This commit is contained in:
parent
be7e528eae
commit
367882fa32
16
src/xcb.h
16
src/xcb.h
|
@ -285,6 +285,22 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c);
|
||||||
*/
|
*/
|
||||||
xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie);
|
xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Discards the reply for a request.
|
||||||
|
* @param c: The connection to the X server.
|
||||||
|
* @param sequence: The request sequence number from a cookie.
|
||||||
|
*
|
||||||
|
* Discards the reply for a request. Additionally, any error generated
|
||||||
|
* by the request is also discarded (unless it was an _unchecked request
|
||||||
|
* and the error has already arrived).
|
||||||
|
*
|
||||||
|
* This function will not block even if the reply is not yet available.
|
||||||
|
*
|
||||||
|
* Note that the sequence really does have to come from an xcb cookie;
|
||||||
|
* this function is not designed to operate on socket-handoff replies.
|
||||||
|
*/
|
||||||
|
void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
|
||||||
|
|
||||||
|
|
||||||
/* xcb_ext.c */
|
/* xcb_ext.c */
|
||||||
|
|
||||||
|
|
110
src/xcb_in.c
110
src/xcb_in.c
|
@ -409,6 +409,116 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_next, uint64_t seq)
|
||||||
|
{
|
||||||
|
pending_reply *pend;
|
||||||
|
pend = malloc(sizeof(*pend));
|
||||||
|
if(!pend)
|
||||||
|
{
|
||||||
|
_xcb_conn_shutdown(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pend->first_request = seq;
|
||||||
|
pend->last_request = seq;
|
||||||
|
pend->workaround = 0;
|
||||||
|
pend->flags = XCB_REQUEST_DISCARD_REPLY;
|
||||||
|
pend->next = *prev_next;
|
||||||
|
*prev_next = pend;
|
||||||
|
|
||||||
|
if(!pend->next)
|
||||||
|
c->in.pending_replies_tail = &pend->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void discard_reply(xcb_connection_t *c, unsigned int request)
|
||||||
|
{
|
||||||
|
pending_reply *pend = 0;
|
||||||
|
pending_reply **prev_pend;
|
||||||
|
uint64_t widened_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. */
|
||||||
|
if(XCB_SEQUENCE_COMPARE_32(request, <, c->in.request_read))
|
||||||
|
{
|
||||||
|
struct reply_list *head;
|
||||||
|
head = _xcb_map_remove(c->in.replies, request);
|
||||||
|
while (head)
|
||||||
|
{
|
||||||
|
struct reply_list *next = head->next;
|
||||||
|
free(head->reply);
|
||||||
|
free(head);
|
||||||
|
head = next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're currently processing the responses to the request we want, and we
|
||||||
|
* have a reply ready to return. Free it, and mark the pend to free any further
|
||||||
|
* replies. */
|
||||||
|
if(XCB_SEQUENCE_COMPARE_32(request, ==, c->in.request_read) && c->in.current_reply)
|
||||||
|
{
|
||||||
|
struct reply_list *head;
|
||||||
|
head = c->in.current_reply;
|
||||||
|
c->in.current_reply = NULL;
|
||||||
|
c->in.current_reply_tail = &c->in.current_reply;
|
||||||
|
while (head)
|
||||||
|
{
|
||||||
|
struct reply_list *next = head->next;
|
||||||
|
free(head->reply);
|
||||||
|
free(head);
|
||||||
|
head = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pend = c->in.pending_replies;
|
||||||
|
if(pend &&
|
||||||
|
!(XCB_SEQUENCE_COMPARE(pend->first_request, <=, c->in.request_read) &&
|
||||||
|
(pend->workaround == WORKAROUND_EXTERNAL_SOCKET_OWNER ||
|
||||||
|
XCB_SEQUENCE_COMPARE(c->in.request_read, <=, pend->last_request))))
|
||||||
|
pend = 0;
|
||||||
|
if(pend)
|
||||||
|
pend->flags |= XCB_REQUEST_DISCARD_REPLY;
|
||||||
|
else
|
||||||
|
insert_pending_discard(c, &c->in.pending_replies, c->in.request_read);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walk the list of pending requests. Mark the first match for deletion. */
|
||||||
|
for(prev_pend = &c->in.pending_replies; *prev_pend; prev_pend = &(*prev_pend)->next)
|
||||||
|
{
|
||||||
|
if(XCB_SEQUENCE_COMPARE_32((*prev_pend)->first_request, >, request))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(XCB_SEQUENCE_COMPARE_32((*prev_pend)->first_request, ==, request))
|
||||||
|
{
|
||||||
|
/* Pending reply found. Mark for discard: */
|
||||||
|
(*prev_pend)->flags |= XCB_REQUEST_DISCARD_REPLY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pending reply not found (likely due to _unchecked request). Create one: */
|
||||||
|
widened_request = (c->out.request & UINT64_C(0xffffffff00000000)) | request;
|
||||||
|
if(widened_request > c->out.request)
|
||||||
|
widened_request -= UINT64_C(1) << 32;
|
||||||
|
|
||||||
|
insert_pending_discard(c, prev_pend, widened_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence)
|
||||||
|
{
|
||||||
|
if(c->has_error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If an error occurred when issuing the request, fail immediately. */
|
||||||
|
if(!sequence)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&c->iolock);
|
||||||
|
discard_reply(c, sequence);
|
||||||
|
pthread_mutex_unlock(&c->iolock);
|
||||||
|
}
|
||||||
|
|
||||||
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error)
|
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
Loading…
Reference in New Issue