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