xcb_io.c revision 38ae11fc
11ab64890Smrg/* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett 21ab64890Smrg * This file is licensed under the MIT license. See the file COPYING. */ 31ab64890Smrg 4b4ee4795Smrg#ifdef HAVE_CONFIG_H 5b4ee4795Smrg#include <config.h> 6b4ee4795Smrg#endif 7b4ee4795Smrg 81ab64890Smrg#include "Xlibint.h" 91ab64890Smrg#include "locking.h" 1061b2299dSmrg#include "Xprivate.h" 111ab64890Smrg#include "Xxcbint.h" 121ab64890Smrg#include <xcb/xcbext.h> 131ab64890Smrg 141ab64890Smrg#include <assert.h> 1588de56ccSmrg#ifdef HAVE_INTTYPES_H 1661b2299dSmrg#include <inttypes.h> 1788de56ccSmrg#endif 186cc2b21fSmrg#include <stdio.h> 1961b2299dSmrg#include <stdint.h> 201ab64890Smrg#include <stdlib.h> 211ab64890Smrg#include <string.h> 22eb411b4bSmrg#include <limits.h> 23b4ee4795Smrg#ifdef HAVE_SYS_SELECT_H 24b4ee4795Smrg#include <sys/select.h> 25b4ee4795Smrg#endif 261ab64890Smrg 276cc2b21fSmrg#define xcb_fail_assert(_message, _var) { \ 286cc2b21fSmrg unsigned int _var = 1; \ 296cc2b21fSmrg fprintf(stderr, "[xcb] Aborting, sorry about that.\n"); \ 306cc2b21fSmrg assert(!_var); \ 316cc2b21fSmrg} 326cc2b21fSmrg 336cc2b21fSmrg#define throw_thread_fail_assert(_message, _var) { \ 346cc2b21fSmrg fprintf(stderr, "[xcb] " _message "\n"); \ 356cc2b21fSmrg fprintf(stderr, "[xcb] Most likely this is a multi-threaded client " \ 366cc2b21fSmrg "and XInitThreads has not been called\n"); \ 376cc2b21fSmrg xcb_fail_assert(_message, _var); \ 386cc2b21fSmrg} 396cc2b21fSmrg 406cc2b21fSmrg/* XXX: It would probably be most useful if we stored the last-processed 416cc2b21fSmrg * request, so we could find the offender from the message. */ 426cc2b21fSmrg#define throw_extlib_fail_assert(_message, _var) { \ 436cc2b21fSmrg fprintf(stderr, "[xcb] " _message "\n"); \ 446cc2b21fSmrg fprintf(stderr, "[xcb] This is most likely caused by a broken X " \ 456cc2b21fSmrg "extension library\n"); \ 466cc2b21fSmrg xcb_fail_assert(_message, _var); \ 476cc2b21fSmrg} 486cc2b21fSmrg 4961b2299dSmrgstatic void return_socket(void *closure) 5061b2299dSmrg{ 5161b2299dSmrg Display *dpy = closure; 5288de56ccSmrg InternalLockDisplay(dpy, /* don't skip user locks */ 0); 5361b2299dSmrg _XSend(dpy, NULL, 0); 5461b2299dSmrg dpy->bufmax = dpy->buffer; 5561b2299dSmrg UnlockDisplay(dpy); 5661b2299dSmrg} 5761b2299dSmrg 5861b2299dSmrgstatic void require_socket(Display *dpy) 5961b2299dSmrg{ 6061b2299dSmrg if(dpy->bufmax == dpy->buffer) 6161b2299dSmrg { 6261b2299dSmrg uint64_t sent; 6361b2299dSmrg int flags = 0; 6461b2299dSmrg /* if we don't own the event queue, we have to ask XCB 6561b2299dSmrg * to set our errors aside for us. */ 6661b2299dSmrg if(dpy->xcb->event_owner != XlibOwnsEventQueue) 6761b2299dSmrg flags = XCB_REQUEST_CHECKED; 6861b2299dSmrg if(!xcb_take_socket(dpy->xcb->connection, return_socket, dpy, 6961b2299dSmrg flags, &sent)) 7061b2299dSmrg _XIOError(dpy); 712d67cb4fSmrg dpy->xcb->last_flushed = sent; 722d67cb4fSmrg X_DPY_SET_REQUEST(dpy, sent); 7361b2299dSmrg dpy->bufmax = dpy->xcb->real_bufmax; 7461b2299dSmrg } 7561b2299dSmrg} 7661b2299dSmrg 771ab64890Smrg/* Call internal connection callbacks for any fds that are currently 781ab64890Smrg * ready to read. This function will not block unless one of the 791ab64890Smrg * callbacks blocks. 801ab64890Smrg * 811ab64890Smrg * This code borrowed from _XWaitForReadable. Inverse call tree: 821ab64890Smrg * _XRead 831ab64890Smrg * _XWaitForWritable 841ab64890Smrg * _XFlush 851ab64890Smrg * _XSend 861ab64890Smrg * _XEventsQueued 871ab64890Smrg * _XReadEvents 881ab64890Smrg * _XRead[0-9]+ 891ab64890Smrg * _XAllocIDs 901ab64890Smrg * _XReply 911ab64890Smrg * _XEatData 921ab64890Smrg * _XReadPad 931ab64890Smrg */ 941ab64890Smrgstatic void check_internal_connections(Display *dpy) 951ab64890Smrg{ 9661b2299dSmrg struct _XConnectionInfo *ilist; 971ab64890Smrg fd_set r_mask; 981ab64890Smrg struct timeval tv; 991ab64890Smrg int result; 1001ab64890Smrg int highest_fd = -1; 1011ab64890Smrg 1021ab64890Smrg if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info) 1031ab64890Smrg return; 1041ab64890Smrg 1051ab64890Smrg FD_ZERO(&r_mask); 1061ab64890Smrg for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next) 1071ab64890Smrg { 1081ab64890Smrg assert(ilist->fd >= 0); 1091ab64890Smrg FD_SET(ilist->fd, &r_mask); 1101ab64890Smrg if(ilist->fd > highest_fd) 1111ab64890Smrg highest_fd = ilist->fd; 1121ab64890Smrg } 1131ab64890Smrg assert(highest_fd >= 0); 1141ab64890Smrg 1151ab64890Smrg tv.tv_sec = 0; 1161ab64890Smrg tv.tv_usec = 0; 1171ab64890Smrg result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv); 1181ab64890Smrg 1191ab64890Smrg if(result == -1) 1201ab64890Smrg { 1211ab64890Smrg if(errno == EINTR) 1221ab64890Smrg return; 1231ab64890Smrg _XIOError(dpy); 1241ab64890Smrg } 1251ab64890Smrg 1261ab64890Smrg for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next) 1271ab64890Smrg if(FD_ISSET(ilist->fd, &r_mask)) 1281ab64890Smrg { 1291ab64890Smrg _XProcessInternalConnection(dpy, ilist); 1301ab64890Smrg --result; 1311ab64890Smrg } 1321ab64890Smrg} 1331ab64890Smrg 1342d67cb4fSmrgstatic PendingRequest *append_pending_request(Display *dpy, uint64_t sequence) 1351ab64890Smrg{ 13688de56ccSmrg PendingRequest *node = malloc(sizeof(PendingRequest)); 13788de56ccSmrg assert(node); 13888de56ccSmrg node->next = NULL; 13988de56ccSmrg node->sequence = sequence; 14088de56ccSmrg node->reply_waiter = 0; 14188de56ccSmrg if(dpy->xcb->pending_requests_tail) 1421ab64890Smrg { 1436cc2b21fSmrg if (XLIB_SEQUENCE_COMPARE(dpy->xcb->pending_requests_tail->sequence, 1446cc2b21fSmrg >=, node->sequence)) 1456cc2b21fSmrg throw_thread_fail_assert("Unknown sequence number " 1466cc2b21fSmrg "while appending request", 1476cc2b21fSmrg xcb_xlib_unknown_seq_number); 1486cc2b21fSmrg if (dpy->xcb->pending_requests_tail->next != NULL) 1496cc2b21fSmrg throw_thread_fail_assert("Unknown request in queue " 1506cc2b21fSmrg "while appending request", 1516cc2b21fSmrg xcb_xlib_unknown_req_pending); 15288de56ccSmrg dpy->xcb->pending_requests_tail->next = node; 1531ab64890Smrg } 15488de56ccSmrg else 15588de56ccSmrg dpy->xcb->pending_requests = node; 15688de56ccSmrg dpy->xcb->pending_requests_tail = node; 15788de56ccSmrg return node; 1581ab64890Smrg} 1591ab64890Smrg 16088de56ccSmrgstatic void dequeue_pending_request(Display *dpy, PendingRequest *req) 1611ab64890Smrg{ 1626cc2b21fSmrg if (req != dpy->xcb->pending_requests) 1636cc2b21fSmrg throw_thread_fail_assert("Unknown request in queue while " 1646cc2b21fSmrg "dequeuing", 1656cc2b21fSmrg xcb_xlib_unknown_req_in_deq); 1666cc2b21fSmrg 16788de56ccSmrg dpy->xcb->pending_requests = req->next; 16888de56ccSmrg if(!dpy->xcb->pending_requests) 1691ab64890Smrg { 1706cc2b21fSmrg if (req != dpy->xcb->pending_requests_tail) 1716cc2b21fSmrg throw_thread_fail_assert("Unknown request in queue " 1726cc2b21fSmrg "while dequeuing", 1736cc2b21fSmrg xcb_xlib_unknown_req_in_deq); 17488de56ccSmrg dpy->xcb->pending_requests_tail = NULL; 1751ab64890Smrg } 1766cc2b21fSmrg else if (XLIB_SEQUENCE_COMPARE(req->sequence, >=, 1776cc2b21fSmrg dpy->xcb->pending_requests->sequence)) 1786cc2b21fSmrg throw_thread_fail_assert("Unknown sequence number while " 1796cc2b21fSmrg "dequeuing request", 1806cc2b21fSmrg xcb_xlib_threads_sequence_lost); 1816cc2b21fSmrg 18288de56ccSmrg free(req); 18388de56ccSmrg} 18488de56ccSmrg 18588de56ccSmrgstatic int handle_error(Display *dpy, xError *err, Bool in_XReply) 18688de56ccSmrg{ 18788de56ccSmrg _XExtension *ext; 18888de56ccSmrg int ret_code; 18988de56ccSmrg /* Oddly, Xlib only allows extensions to suppress errors when 19088de56ccSmrg * those errors were seen by _XReply. */ 19188de56ccSmrg if(in_XReply) 19288de56ccSmrg /* 19388de56ccSmrg * we better see if there is an extension who may 19488de56ccSmrg * want to suppress the error. 19588de56ccSmrg */ 19688de56ccSmrg for(ext = dpy->ext_procs; ext; ext = ext->next) 19788de56ccSmrg if(ext->error && (*ext->error)(dpy, err, &ext->codes, &ret_code)) 19888de56ccSmrg return ret_code; 19988de56ccSmrg _XError(dpy, err); 20088de56ccSmrg return 0; 2011ab64890Smrg} 2021ab64890Smrg 2032d67cb4fSmrg/* Widen a 32-bit sequence number into a 64bit (uint64_t) sequence number. 2042d67cb4fSmrg * Treating the comparison as a 1 and shifting it avoids a conditional branch. 2052d67cb4fSmrg */ 2062d67cb4fSmrgstatic void widen(uint64_t *wide, unsigned int narrow) 20761b2299dSmrg{ 2082d67cb4fSmrg uint64_t new = (*wide & ~((uint64_t)0xFFFFFFFFUL)) | narrow; 2092d67cb4fSmrg *wide = new + (((uint64_t)(new < *wide)) << 32); 21061b2299dSmrg} 21161b2299dSmrg 21288de56ccSmrg/* Thread-safety rules: 21388de56ccSmrg * 21488de56ccSmrg * At most one thread can be reading from XCB's event queue at a time. 21588de56ccSmrg * If you are not the current event-reading thread and you need to find 21688de56ccSmrg * out if an event is available, you must wait. 21788de56ccSmrg * 21888de56ccSmrg * The same rule applies for reading replies. 21988de56ccSmrg * 22088de56ccSmrg * A single thread cannot be both the the event-reading and the 22188de56ccSmrg * reply-reading thread at the same time. 22288de56ccSmrg * 22388de56ccSmrg * We always look at both the current event and the first pending reply 22488de56ccSmrg * to decide which to process next. 22588de56ccSmrg * 22688de56ccSmrg * We always process all responses in sequence-number order, which may 22788de56ccSmrg * mean waiting for another thread (either the event_waiter or the 22888de56ccSmrg * reply_waiter) to handle an earlier response before we can process or 22988de56ccSmrg * return a later one. If so, we wait on the corresponding condition 23088de56ccSmrg * variable for that thread to process the response and wake us up. 23188de56ccSmrg */ 2321ab64890Smrg 23338ae11fcSmrgstatic xcb_generic_reply_t *poll_for_event(Display *dpy, Bool queued_only) 23488de56ccSmrg{ 23588de56ccSmrg /* Make sure the Display's sequence numbers are valid */ 23661b2299dSmrg require_socket(dpy); 23761b2299dSmrg 23888de56ccSmrg /* Precondition: This thread can safely get events from XCB. */ 23988de56ccSmrg assert(dpy->xcb->event_owner == XlibOwnsEventQueue && !dpy->xcb->event_waiter); 24088de56ccSmrg 24138ae11fcSmrg if(!dpy->xcb->next_event) { 24238ae11fcSmrg if(queued_only) 24338ae11fcSmrg dpy->xcb->next_event = xcb_poll_for_queued_event(dpy->xcb->connection); 24438ae11fcSmrg else 24538ae11fcSmrg dpy->xcb->next_event = xcb_poll_for_event(dpy->xcb->connection); 24638ae11fcSmrg } 24788de56ccSmrg 24888de56ccSmrg if(dpy->xcb->next_event) 2491ab64890Smrg { 2501ab64890Smrg PendingRequest *req = dpy->xcb->pending_requests; 25188de56ccSmrg xcb_generic_event_t *event = dpy->xcb->next_event; 2522d67cb4fSmrg uint64_t event_sequence = X_DPY_GET_LAST_REQUEST_READ(dpy); 25388de56ccSmrg widen(&event_sequence, event->full_sequence); 25488de56ccSmrg if(!req || XLIB_SEQUENCE_COMPARE(event_sequence, <, req->sequence) 25588de56ccSmrg || (event->response_type != X_Error && event_sequence == req->sequence)) 2561ab64890Smrg { 2572d67cb4fSmrg uint64_t request = X_DPY_GET_REQUEST(dpy); 2582d67cb4fSmrg if (XLIB_SEQUENCE_COMPARE(event_sequence, >, request)) 2596cc2b21fSmrg { 2606cc2b21fSmrg throw_thread_fail_assert("Unknown sequence " 2616cc2b21fSmrg "number while " 2626cc2b21fSmrg "processing queue", 2636cc2b21fSmrg xcb_xlib_threads_sequence_lost); 2646cc2b21fSmrg } 2652d67cb4fSmrg X_DPY_SET_LAST_REQUEST_READ(dpy, event_sequence); 26688de56ccSmrg dpy->xcb->next_event = NULL; 26788de56ccSmrg return (xcb_generic_reply_t *) event; 2681ab64890Smrg } 26988de56ccSmrg } 27088de56ccSmrg return NULL; 27188de56ccSmrg} 27288de56ccSmrg 27388de56ccSmrgstatic xcb_generic_reply_t *poll_for_response(Display *dpy) 27488de56ccSmrg{ 27588de56ccSmrg void *response; 27688de56ccSmrg xcb_generic_error_t *error; 27788de56ccSmrg PendingRequest *req; 27838ae11fcSmrg while(!(response = poll_for_event(dpy, False)) && 27988de56ccSmrg (req = dpy->xcb->pending_requests) && 28038ae11fcSmrg !req->reply_waiter) 28188de56ccSmrg { 28238ae11fcSmrg uint64_t request; 28338ae11fcSmrg 28438ae11fcSmrg if(!xcb_poll_for_reply64(dpy->xcb->connection, req->sequence, 28538ae11fcSmrg &response, &error)) { 28638ae11fcSmrg /* xcb_poll_for_reply64 may have read events even if 28738ae11fcSmrg * there is no reply. */ 28838ae11fcSmrg response = poll_for_event(dpy, True); 28938ae11fcSmrg break; 29038ae11fcSmrg } 29138ae11fcSmrg 29238ae11fcSmrg request = X_DPY_GET_REQUEST(dpy); 2932d67cb4fSmrg if(XLIB_SEQUENCE_COMPARE(req->sequence, >, request)) 2946cc2b21fSmrg { 2956cc2b21fSmrg throw_thread_fail_assert("Unknown sequence number " 2966cc2b21fSmrg "while awaiting reply", 2976cc2b21fSmrg xcb_xlib_threads_sequence_lost); 2986cc2b21fSmrg } 2992d67cb4fSmrg X_DPY_SET_LAST_REQUEST_READ(dpy, req->sequence); 300e9fcaa8aSmrg if(response) 301e9fcaa8aSmrg break; 302e9fcaa8aSmrg dequeue_pending_request(dpy, req); 30388de56ccSmrg if(error) 30488de56ccSmrg return (xcb_generic_reply_t *) error; 30588de56ccSmrg } 30688de56ccSmrg return response; 30788de56ccSmrg} 30888de56ccSmrg 30988de56ccSmrgstatic void handle_response(Display *dpy, xcb_generic_reply_t *response, Bool in_XReply) 31088de56ccSmrg{ 31188de56ccSmrg _XAsyncHandler *async, *next; 31288de56ccSmrg switch(response->response_type) 31388de56ccSmrg { 31488de56ccSmrg case X_Reply: 31588de56ccSmrg for(async = dpy->async_handlers; async; async = next) 3161ab64890Smrg { 31788de56ccSmrg next = async->next; 31888de56ccSmrg if(async->handler(dpy, (xReply *) response, (char *) response, sizeof(xReply) + (response->length << 2), async->data)) 31988de56ccSmrg break; 3201ab64890Smrg } 32188de56ccSmrg break; 32288de56ccSmrg 32388de56ccSmrg case X_Error: 32488de56ccSmrg handle_error(dpy, (xError *) response, in_XReply); 32588de56ccSmrg break; 32688de56ccSmrg 32788de56ccSmrg default: /* event */ 32888de56ccSmrg /* GenericEvents may be > 32 bytes. In this case, the 32988de56ccSmrg * event struct is trailed by the additional bytes. the 33088de56ccSmrg * xcb_generic_event_t struct uses 4 bytes for internal 33188de56ccSmrg * numbering, so we need to shift the trailing data to 33288de56ccSmrg * be after the first 32 bytes. */ 33388de56ccSmrg if(response->response_type == GenericEvent && ((xcb_ge_event_t *) response)->length) 3341ab64890Smrg { 33588de56ccSmrg xcb_ge_event_t *event = (xcb_ge_event_t *) response; 33688de56ccSmrg memmove(&event->full_sequence, &event[1], event->length * 4); 3371ab64890Smrg } 33888de56ccSmrg _XEnq(dpy, (xEvent *) response); 33988de56ccSmrg break; 3401ab64890Smrg } 34188de56ccSmrg free(response); 3421ab64890Smrg} 3431ab64890Smrg 3441ab64890Smrgint _XEventsQueued(Display *dpy, int mode) 3451ab64890Smrg{ 34688de56ccSmrg xcb_generic_reply_t *response; 3471ab64890Smrg if(dpy->flags & XlibDisplayIOError) 3481ab64890Smrg return 0; 3491ab64890Smrg if(dpy->xcb->event_owner != XlibOwnsEventQueue) 3501ab64890Smrg return 0; 3511ab64890Smrg 3521ab64890Smrg if(mode == QueuedAfterFlush) 35361b2299dSmrg _XSend(dpy, NULL, 0); 3541ab64890Smrg else 3551ab64890Smrg check_internal_connections(dpy); 35688de56ccSmrg 35788de56ccSmrg /* If another thread is blocked waiting for events, then we must 35888de56ccSmrg * let that thread pick up the next event. Since it blocked, we 35988de56ccSmrg * can reasonably claim there are no new events right now. */ 36088de56ccSmrg if(!dpy->xcb->event_waiter) 36188de56ccSmrg { 36288de56ccSmrg while((response = poll_for_response(dpy))) 36388de56ccSmrg handle_response(dpy, response, False); 36488de56ccSmrg if(xcb_connection_has_error(dpy->xcb->connection)) 36588de56ccSmrg _XIOError(dpy); 36688de56ccSmrg } 3671ab64890Smrg return dpy->qlen; 3681ab64890Smrg} 3691ab64890Smrg 3701ab64890Smrg/* _XReadEvents - Flush the output queue, 3711ab64890Smrg * then read as many events as possible (but at least 1) and enqueue them 3721ab64890Smrg */ 3731ab64890Smrgvoid _XReadEvents(Display *dpy) 3741ab64890Smrg{ 37588de56ccSmrg xcb_generic_reply_t *response; 37688de56ccSmrg unsigned long serial; 37788de56ccSmrg 3781ab64890Smrg if(dpy->flags & XlibDisplayIOError) 3791ab64890Smrg return; 38061b2299dSmrg _XSend(dpy, NULL, 0); 3811ab64890Smrg if(dpy->xcb->event_owner != XlibOwnsEventQueue) 3821ab64890Smrg return; 3831ab64890Smrg check_internal_connections(dpy); 38488de56ccSmrg 38588de56ccSmrg serial = dpy->next_event_serial_num; 38688de56ccSmrg while(serial == dpy->next_event_serial_num || dpy->qlen == 0) 38788de56ccSmrg { 38888de56ccSmrg if(dpy->xcb->event_waiter) 38988de56ccSmrg { 39088de56ccSmrg ConditionWait(dpy, dpy->xcb->event_notify); 39188de56ccSmrg /* Maybe the other thread got us an event. */ 39288de56ccSmrg continue; 39388de56ccSmrg } 39488de56ccSmrg 39588de56ccSmrg if(!dpy->xcb->next_event) 39688de56ccSmrg { 39788de56ccSmrg xcb_generic_event_t *event; 39888de56ccSmrg dpy->xcb->event_waiter = 1; 39988de56ccSmrg UnlockDisplay(dpy); 40088de56ccSmrg event = xcb_wait_for_event(dpy->xcb->connection); 40157f47464Smrg /* It appears that classic Xlib respected user 40257f47464Smrg * locks when waking up after waiting for 40357f47464Smrg * events. However, if this thread did not have 40457f47464Smrg * any user locks, and another thread takes a 40557f47464Smrg * user lock and tries to read events, then we'd 40657f47464Smrg * deadlock. So we'll choose to let the thread 40757f47464Smrg * that got in first consume events, despite the 40857f47464Smrg * later thread's user locks. */ 40957f47464Smrg InternalLockDisplay(dpy, /* ignore user locks */ 1); 41088de56ccSmrg dpy->xcb->event_waiter = 0; 41188de56ccSmrg ConditionBroadcast(dpy, dpy->xcb->event_notify); 41288de56ccSmrg if(!event) 41388de56ccSmrg _XIOError(dpy); 41488de56ccSmrg dpy->xcb->next_event = event; 41588de56ccSmrg } 41688de56ccSmrg 41788de56ccSmrg /* We've established most of the conditions for 41888de56ccSmrg * poll_for_response to return non-NULL. The exceptions 41988de56ccSmrg * are connection shutdown, and finding that another 42088de56ccSmrg * thread is waiting for the next reply we'd like to 42188de56ccSmrg * process. */ 42288de56ccSmrg 42388de56ccSmrg response = poll_for_response(dpy); 42488de56ccSmrg if(response) 42588de56ccSmrg handle_response(dpy, response, False); 42688de56ccSmrg else if(dpy->xcb->pending_requests->reply_waiter) 42788de56ccSmrg { /* need braces around ConditionWait */ 42888de56ccSmrg ConditionWait(dpy, dpy->xcb->reply_notify); 42988de56ccSmrg } 43088de56ccSmrg else 43188de56ccSmrg _XIOError(dpy); 43288de56ccSmrg } 43388de56ccSmrg 43488de56ccSmrg /* The preceding loop established that there is no 43588de56ccSmrg * event_waiter--unless we just called ConditionWait because of 43688de56ccSmrg * a reply_waiter, in which case another thread may have become 43788de56ccSmrg * the event_waiter while we slept unlocked. */ 43888de56ccSmrg if(!dpy->xcb->event_waiter) 43988de56ccSmrg while((response = poll_for_response(dpy))) 44088de56ccSmrg handle_response(dpy, response, False); 44188de56ccSmrg if(xcb_connection_has_error(dpy->xcb->connection)) 44288de56ccSmrg _XIOError(dpy); 4431ab64890Smrg} 4441ab64890Smrg 4451ab64890Smrg/* 4461ab64890Smrg * _XSend - Flush the buffer and send the client data. 32 bit word aligned 4471ab64890Smrg * transmission is used, if size is not 0 mod 4, extra bytes are transmitted. 4481ab64890Smrg * 4491ab64890Smrg * Note that the connection must not be read from once the data currently 4501ab64890Smrg * in the buffer has been written. 4511ab64890Smrg */ 4521ab64890Smrgvoid _XSend(Display *dpy, const char *data, long size) 4531ab64890Smrg{ 45461b2299dSmrg static const xReq dummy_request; 45561b2299dSmrg static char const pad[3]; 45661b2299dSmrg struct iovec vec[3]; 45761b2299dSmrg uint64_t requests; 4582d67cb4fSmrg uint64_t dpy_request; 45961b2299dSmrg _XExtension *ext; 4601ab64890Smrg xcb_connection_t *c = dpy->xcb->connection; 4611ab64890Smrg if(dpy->flags & XlibDisplayIOError) 4621ab64890Smrg return; 4631ab64890Smrg 46461b2299dSmrg if(dpy->bufptr == dpy->buffer && !size) 46561b2299dSmrg return; 4661ab64890Smrg 4672d67cb4fSmrg /* append_pending_request does not alter the dpy request number 4682d67cb4fSmrg * therefore we can get it outside of the loop and the if 4692d67cb4fSmrg */ 4702d67cb4fSmrg dpy_request = X_DPY_GET_REQUEST(dpy); 47161b2299dSmrg /* iff we asked XCB to set aside errors, we must pick those up 47261b2299dSmrg * eventually. iff there are async handlers, we may have just 47361b2299dSmrg * issued requests that will generate replies. in either case, 47461b2299dSmrg * we need to remember to check later. */ 47561b2299dSmrg if(dpy->xcb->event_owner != XlibOwnsEventQueue || dpy->async_handlers) 47661b2299dSmrg { 4772e9c7c8cSmrg uint64_t sequence; 4782d67cb4fSmrg for(sequence = dpy->xcb->last_flushed + 1; sequence <= dpy_request; ++sequence) 47988de56ccSmrg append_pending_request(dpy, sequence); 48061b2299dSmrg } 4812d67cb4fSmrg requests = dpy_request - dpy->xcb->last_flushed; 4822d67cb4fSmrg dpy->xcb->last_flushed = dpy_request; 4831ab64890Smrg 48461b2299dSmrg vec[0].iov_base = dpy->buffer; 48561b2299dSmrg vec[0].iov_len = dpy->bufptr - dpy->buffer; 486eb411b4bSmrg vec[1].iov_base = (char *)data; 48761b2299dSmrg vec[1].iov_len = size; 488eb411b4bSmrg vec[2].iov_base = (char *)pad; 48961b2299dSmrg vec[2].iov_len = -size & 3; 49061b2299dSmrg 49161b2299dSmrg for(ext = dpy->flushes; ext; ext = ext->next_flush) 49261b2299dSmrg { 49361b2299dSmrg int i; 49461b2299dSmrg for(i = 0; i < 3; ++i) 49561b2299dSmrg if(vec[i].iov_len) 49661b2299dSmrg ext->before_flush(dpy, &ext->codes, vec[i].iov_base, vec[i].iov_len); 49761b2299dSmrg } 4981ab64890Smrg 49961b2299dSmrg if(xcb_writev(c, vec, 3, requests) < 0) 50061b2299dSmrg _XIOError(dpy); 50161b2299dSmrg dpy->bufptr = dpy->buffer; 50261b2299dSmrg dpy->last_req = (char *) &dummy_request; 5031ab64890Smrg 5041ab64890Smrg check_internal_connections(dpy); 5051ab64890Smrg 50661b2299dSmrg _XSetSeqSyncFunction(dpy); 5071ab64890Smrg} 5081ab64890Smrg 5091ab64890Smrg/* 5101ab64890Smrg * _XFlush - Flush the X request buffer. If the buffer is empty, no 5111ab64890Smrg * action is taken. 5121ab64890Smrg */ 5131ab64890Smrgvoid _XFlush(Display *dpy) 5141ab64890Smrg{ 51561b2299dSmrg require_socket(dpy); 51661b2299dSmrg _XSend(dpy, NULL, 0); 5171ab64890Smrg 5181ab64890Smrg _XEventsQueued(dpy, QueuedAfterReading); 5191ab64890Smrg} 5201ab64890Smrg 52161b2299dSmrgstatic const XID inval_id = ~0UL; 52261b2299dSmrg 52388de56ccSmrgvoid _XIDHandler(Display *dpy) 5241ab64890Smrg{ 52588de56ccSmrg if (dpy->xcb->next_xid == inval_id) 52688de56ccSmrg _XAllocIDs(dpy, &dpy->xcb->next_xid, 1); 5271ab64890Smrg} 5281ab64890Smrg 5291ab64890Smrg/* _XAllocID - resource ID allocation routine. */ 5301ab64890SmrgXID _XAllocID(Display *dpy) 5311ab64890Smrg{ 5321ab64890Smrg XID ret = dpy->xcb->next_xid; 53361b2299dSmrg assert (ret != inval_id); 53461b2299dSmrg dpy->xcb->next_xid = inval_id; 53561b2299dSmrg _XSetPrivSyncFunction(dpy); 5361ab64890Smrg return ret; 5371ab64890Smrg} 5381ab64890Smrg 5391ab64890Smrg/* _XAllocIDs - multiple resource ID allocation routine. */ 5401ab64890Smrgvoid _XAllocIDs(Display *dpy, XID *ids, int count) 5411ab64890Smrg{ 5421ab64890Smrg int i; 54361b2299dSmrg#ifdef XTHREADS 54461b2299dSmrg if (dpy->lock) 54561b2299dSmrg (*dpy->lock->user_lock_display)(dpy); 54661b2299dSmrg UnlockDisplay(dpy); 54761b2299dSmrg#endif 5481ab64890Smrg for (i = 0; i < count; i++) 5491ab64890Smrg ids[i] = xcb_generate_id(dpy->xcb->connection); 55061b2299dSmrg#ifdef XTHREADS 55188de56ccSmrg InternalLockDisplay(dpy, /* don't skip user locks */ 0); 55261b2299dSmrg if (dpy->lock) 55361b2299dSmrg (*dpy->lock->user_unlock_display)(dpy); 55461b2299dSmrg#endif 5551ab64890Smrg} 5561ab64890Smrg 5571ab64890Smrgstatic void _XFreeReplyData(Display *dpy, Bool force) 5581ab64890Smrg{ 5591ab64890Smrg if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length) 5601ab64890Smrg return; 5611ab64890Smrg free(dpy->xcb->reply_data); 56261b2299dSmrg dpy->xcb->reply_data = NULL; 5631ab64890Smrg} 5641ab64890Smrg 5651ab64890Smrg/* 5661ab64890Smrg * _XReply - Wait for a reply packet and copy its contents into the 5671ab64890Smrg * specified rep. 5681ab64890Smrg * extra: number of 32-bit words expected after the reply 5691ab64890Smrg * discard: should I discard data following "extra" words? 5701ab64890Smrg */ 5711ab64890SmrgStatus _XReply(Display *dpy, xReply *rep, int extra, Bool discard) 5721ab64890Smrg{ 5731ab64890Smrg xcb_generic_error_t *error; 5741ab64890Smrg xcb_connection_t *c = dpy->xcb->connection; 5751ab64890Smrg char *reply; 5761ab64890Smrg PendingRequest *current; 5772d67cb4fSmrg uint64_t dpy_request; 5781ab64890Smrg 5796cc2b21fSmrg if (dpy->xcb->reply_data) 5806cc2b21fSmrg throw_extlib_fail_assert("Extra reply data still left in queue", 5816cc2b21fSmrg xcb_xlib_extra_reply_data_left); 5821ab64890Smrg 5831ab64890Smrg if(dpy->flags & XlibDisplayIOError) 5841ab64890Smrg return 0; 5851ab64890Smrg 58661b2299dSmrg _XSend(dpy, NULL, 0); 5872d67cb4fSmrg dpy_request = X_DPY_GET_REQUEST(dpy); 5882d67cb4fSmrg if(dpy->xcb->pending_requests_tail 5892d67cb4fSmrg && dpy->xcb->pending_requests_tail->sequence == dpy_request) 59088de56ccSmrg current = dpy->xcb->pending_requests_tail; 59188de56ccSmrg else 5922d67cb4fSmrg current = append_pending_request(dpy, dpy_request); 59388de56ccSmrg /* Don't let any other thread get this reply. */ 59488de56ccSmrg current->reply_waiter = 1; 59588de56ccSmrg 59688de56ccSmrg while(1) 59788de56ccSmrg { 59888de56ccSmrg PendingRequest *req = dpy->xcb->pending_requests; 59988de56ccSmrg xcb_generic_reply_t *response; 6001ab64890Smrg 60188de56ccSmrg if(req != current && req->reply_waiter) 60288de56ccSmrg { 60388de56ccSmrg ConditionWait(dpy, dpy->xcb->reply_notify); 60488de56ccSmrg /* Another thread got this reply. */ 60588de56ccSmrg continue; 60688de56ccSmrg } 60788de56ccSmrg req->reply_waiter = 1; 60888de56ccSmrg UnlockDisplay(dpy); 6092d67cb4fSmrg response = xcb_wait_for_reply64(c, req->sequence, &error); 61057f47464Smrg /* Any user locks on another thread must have been taken 6112d67cb4fSmrg * while we slept in xcb_wait_for_reply64. Classic Xlib 61257f47464Smrg * ignored those user locks in this case, so we do too. */ 61357f47464Smrg InternalLockDisplay(dpy, /* ignore user locks */ 1); 61488de56ccSmrg 61588de56ccSmrg /* We have the response we're looking for. Now, before 61688de56ccSmrg * letting anyone else process this sequence number, we 61788de56ccSmrg * need to process any events that should have come 61888de56ccSmrg * earlier. */ 61988de56ccSmrg 62088de56ccSmrg if(dpy->xcb->event_owner == XlibOwnsEventQueue) 62188de56ccSmrg { 62288de56ccSmrg xcb_generic_reply_t *event; 62388de56ccSmrg /* If some thread is already waiting for events, 62488de56ccSmrg * it will get the first one. That thread must 62588de56ccSmrg * process that event before we can continue. */ 62688de56ccSmrg /* FIXME: That event might be after this reply, 62788de56ccSmrg * and might never even come--or there might be 62888de56ccSmrg * multiple threads trying to get events. */ 62988de56ccSmrg while(dpy->xcb->event_waiter) 63088de56ccSmrg { /* need braces around ConditionWait */ 63188de56ccSmrg ConditionWait(dpy, dpy->xcb->event_notify); 63288de56ccSmrg } 63338ae11fcSmrg while((event = poll_for_event(dpy, True))) 63488de56ccSmrg handle_response(dpy, event, True); 63588de56ccSmrg } 63688de56ccSmrg 63788de56ccSmrg req->reply_waiter = 0; 63888de56ccSmrg ConditionBroadcast(dpy, dpy->xcb->reply_notify); 6392d67cb4fSmrg dpy_request = X_DPY_GET_REQUEST(dpy); 6402d67cb4fSmrg if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy_request)) { 6416cc2b21fSmrg throw_thread_fail_assert("Unknown sequence number " 6426cc2b21fSmrg "while processing reply", 6436cc2b21fSmrg xcb_xlib_threads_sequence_lost); 6446cc2b21fSmrg } 6452d67cb4fSmrg X_DPY_SET_LAST_REQUEST_READ(dpy, req->sequence); 64688de56ccSmrg if(!response) 64788de56ccSmrg dequeue_pending_request(dpy, req); 64888de56ccSmrg 64988de56ccSmrg if(req == current) 65088de56ccSmrg { 65188de56ccSmrg reply = (char *) response; 65288de56ccSmrg break; 65388de56ccSmrg } 65488de56ccSmrg 65588de56ccSmrg if(error) 65688de56ccSmrg handle_response(dpy, (xcb_generic_reply_t *) error, True); 65788de56ccSmrg else if(response) 65888de56ccSmrg handle_response(dpy, response, True); 65988de56ccSmrg } 6601ab64890Smrg check_internal_connections(dpy); 66188de56ccSmrg 66288de56ccSmrg if(dpy->xcb->next_event && dpy->xcb->next_event->response_type == X_Error) 66388de56ccSmrg { 66488de56ccSmrg xcb_generic_event_t *event = dpy->xcb->next_event; 6652d67cb4fSmrg uint64_t last_request_read = X_DPY_GET_LAST_REQUEST_READ(dpy); 6662d67cb4fSmrg uint64_t event_sequence = last_request_read; 66788de56ccSmrg widen(&event_sequence, event->full_sequence); 6682d67cb4fSmrg if(event_sequence == last_request_read) 66988de56ccSmrg { 67088de56ccSmrg error = (xcb_generic_error_t *) event; 67188de56ccSmrg dpy->xcb->next_event = NULL; 67288de56ccSmrg } 67388de56ccSmrg } 6741ab64890Smrg 6751ab64890Smrg if(error) 6761ab64890Smrg { 6771ab64890Smrg int ret_code; 6781ab64890Smrg 6791ab64890Smrg /* Xlib is evil and assumes that even errors will be 6801ab64890Smrg * copied into rep. */ 6811ab64890Smrg memcpy(rep, error, 32); 6821ab64890Smrg 6831ab64890Smrg /* do not die on "no such font", "can't allocate", 6841ab64890Smrg "can't grab" failures */ 68588de56ccSmrg switch(error->error_code) 6861ab64890Smrg { 6871ab64890Smrg case BadName: 68888de56ccSmrg switch(error->major_code) 6891ab64890Smrg { 6901ab64890Smrg case X_LookupColor: 6911ab64890Smrg case X_AllocNamedColor: 69261b2299dSmrg free(error); 6931ab64890Smrg return 0; 6941ab64890Smrg } 6951ab64890Smrg break; 6961ab64890Smrg case BadFont: 69788de56ccSmrg if(error->major_code == X_QueryFont) { 69861b2299dSmrg free(error); 6991ab64890Smrg return 0; 70061b2299dSmrg } 7011ab64890Smrg break; 7021ab64890Smrg case BadAlloc: 7031ab64890Smrg case BadAccess: 70461b2299dSmrg free(error); 7051ab64890Smrg return 0; 7061ab64890Smrg } 7071ab64890Smrg 70888de56ccSmrg ret_code = handle_error(dpy, (xError *) error, True); 70961b2299dSmrg free(error); 71088de56ccSmrg return ret_code; 7111ab64890Smrg } 7121ab64890Smrg 7131ab64890Smrg /* it's not an error, but we don't have a reply, so it's an I/O 7141ab64890Smrg * error. */ 7151ab64890Smrg if(!reply) 7161ab64890Smrg _XIOError(dpy); 7171ab64890Smrg 7181ab64890Smrg /* there's no error and we have a reply. */ 7191ab64890Smrg dpy->xcb->reply_data = reply; 7201ab64890Smrg dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4); 7211ab64890Smrg dpy->xcb->reply_length = sizeof(xReply); 7221ab64890Smrg if(dpy->xcb->reply_data[0] == 1) 7231ab64890Smrg dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4); 7241ab64890Smrg 7251ab64890Smrg /* error: Xlib asks too much. give them what we can anyway. */ 7261ab64890Smrg if(dpy->xcb->reply_length < dpy->xcb->reply_consumed) 7271ab64890Smrg dpy->xcb->reply_consumed = dpy->xcb->reply_length; 7281ab64890Smrg 7291ab64890Smrg memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed); 7301ab64890Smrg _XFreeReplyData(dpy, discard); 7311ab64890Smrg return 1; 7321ab64890Smrg} 7331ab64890Smrg 7341ab64890Smrgint _XRead(Display *dpy, char *data, long size) 7351ab64890Smrg{ 7361ab64890Smrg assert(size >= 0); 7371ab64890Smrg if(size == 0) 7381ab64890Smrg return 0; 7396cc2b21fSmrg if(dpy->xcb->reply_data == NULL || 7406cc2b21fSmrg dpy->xcb->reply_consumed + size > dpy->xcb->reply_length) 7416cc2b21fSmrg throw_extlib_fail_assert("Too much data requested from _XRead", 7426cc2b21fSmrg xcb_xlib_too_much_data_requested); 7431ab64890Smrg memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size); 7441ab64890Smrg dpy->xcb->reply_consumed += size; 7451ab64890Smrg _XFreeReplyData(dpy, False); 7461ab64890Smrg return 0; 7471ab64890Smrg} 7481ab64890Smrg 7491ab64890Smrg/* 7501ab64890Smrg * _XReadPad - Read bytes from the socket taking into account incomplete 7511ab64890Smrg * reads. If the number of bytes is not 0 mod 4, read additional pad 7521ab64890Smrg * bytes. 7531ab64890Smrg */ 7541ab64890Smrgvoid _XReadPad(Display *dpy, char *data, long size) 7551ab64890Smrg{ 7561ab64890Smrg _XRead(dpy, data, size); 7571ab64890Smrg dpy->xcb->reply_consumed += -size & 3; 7581ab64890Smrg _XFreeReplyData(dpy, False); 7591ab64890Smrg} 7601ab64890Smrg 7611ab64890Smrg/* Read and discard "n" 8-bit bytes of data */ 7621ab64890Smrgvoid _XEatData(Display *dpy, unsigned long n) 7631ab64890Smrg{ 7641ab64890Smrg dpy->xcb->reply_consumed += n; 7651ab64890Smrg _XFreeReplyData(dpy, False); 7661ab64890Smrg} 767eb411b4bSmrg 768eb411b4bSmrg/* 769eb411b4bSmrg * Read and discard "n" 32-bit words of data 770eb411b4bSmrg * Matches the units of the length field in X protocol replies, and provides 771eb411b4bSmrg * a single implementation of overflow checking to avoid having to replicate 772eb411b4bSmrg * those checks in every caller. 773eb411b4bSmrg */ 774eb411b4bSmrgvoid _XEatDataWords(Display *dpy, unsigned long n) 775eb411b4bSmrg{ 776eb411b4bSmrg if (n < ((INT_MAX - dpy->xcb->reply_consumed) >> 2)) 777eb411b4bSmrg dpy->xcb->reply_consumed += (n << 2); 778eb411b4bSmrg else 779eb411b4bSmrg /* Overflow would happen, so just eat the rest of the reply */ 780eb411b4bSmrg dpy->xcb->reply_consumed = dpy->xcb->reply_length; 781eb411b4bSmrg _XFreeReplyData(dpy, False); 782eb411b4bSmrg} 7830f8248bfSmrg 7840f8248bfSmrgunsigned long 7850f8248bfSmrg_XNextRequest(Display *dpy) 7860f8248bfSmrg{ 7870f8248bfSmrg /* This will update dpy->request. The assumption is that the next thing 7880f8248bfSmrg * that the application will do is make a request so there's little 7890f8248bfSmrg * overhead. 7900f8248bfSmrg */ 7910f8248bfSmrg require_socket(dpy); 7920f8248bfSmrg return NextRequest(dpy); 7930f8248bfSmrg} 794