xcb_io.c revision eb411b4b
1/* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett
2 * This file is licensed under the MIT license. See the file COPYING. */
3
4#ifdef HAVE_CONFIG_H
5#include <config.h>
6#endif
7
8#include "Xlibint.h"
9#include "locking.h"
10#include "Xprivate.h"
11#include "Xxcbint.h"
12#include <xcb/xcbext.h>
13
14#include <assert.h>
15#ifdef HAVE_INTTYPES_H
16#include <inttypes.h>
17#endif
18#include <stdio.h>
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <limits.h>
23#ifdef HAVE_SYS_SELECT_H
24#include <sys/select.h>
25#endif
26
27#define xcb_fail_assert(_message, _var) { \
28	unsigned int _var = 1; \
29	fprintf(stderr, "[xcb] Aborting, sorry about that.\n"); \
30	assert(!_var); \
31}
32
33#define throw_thread_fail_assert(_message, _var) { \
34	fprintf(stderr, "[xcb] " _message "\n"); \
35	fprintf(stderr, "[xcb] Most likely this is a multi-threaded client " \
36	                "and XInitThreads has not been called\n"); \
37	xcb_fail_assert(_message, _var); \
38}
39
40/* XXX: It would probably be most useful if we stored the last-processed
41 *      request, so we could find the offender from the message. */
42#define throw_extlib_fail_assert(_message, _var) { \
43	fprintf(stderr, "[xcb] " _message "\n"); \
44	fprintf(stderr, "[xcb] This is most likely caused by a broken X " \
45	                "extension library\n"); \
46	xcb_fail_assert(_message, _var); \
47}
48
49static void return_socket(void *closure)
50{
51	Display *dpy = closure;
52	InternalLockDisplay(dpy, /* don't skip user locks */ 0);
53	_XSend(dpy, NULL, 0);
54	dpy->bufmax = dpy->buffer;
55	UnlockDisplay(dpy);
56}
57
58static void require_socket(Display *dpy)
59{
60	if(dpy->bufmax == dpy->buffer)
61	{
62		uint64_t sent;
63		int flags = 0;
64		/* if we don't own the event queue, we have to ask XCB
65		 * to set our errors aside for us. */
66		if(dpy->xcb->event_owner != XlibOwnsEventQueue)
67			flags = XCB_REQUEST_CHECKED;
68		if(!xcb_take_socket(dpy->xcb->connection, return_socket, dpy,
69		                    flags, &sent))
70			_XIOError(dpy);
71		/* Xlib uses unsigned long for sequence numbers.  XCB
72		 * uses 64-bit internally, but currently exposes an
73		 * unsigned int API.  If these differ, Xlib cannot track
74		 * the full 64-bit sequence number if 32-bit wrap
75		 * happens while Xlib does not own the socket.  A
76		 * complete fix would be to make XCB's public API use
77		 * 64-bit sequence numbers. */
78		if (sizeof(unsigned long) > sizeof(unsigned int) &&
79		    dpy->xcb->event_owner == XlibOwnsEventQueue &&
80		    (sent - dpy->last_request_read >= (UINT64_C(1) << 32))) {
81			throw_thread_fail_assert("Sequence number wrapped "
82			                         "beyond 32 bits while Xlib "
83						 "did not own the socket",
84			                         xcb_xlib_seq_number_wrapped);
85		}
86		dpy->xcb->last_flushed = dpy->request = sent;
87		dpy->bufmax = dpy->xcb->real_bufmax;
88	}
89}
90
91/* Call internal connection callbacks for any fds that are currently
92 * ready to read. This function will not block unless one of the
93 * callbacks blocks.
94 *
95 * This code borrowed from _XWaitForReadable. Inverse call tree:
96 * _XRead
97 *  _XWaitForWritable
98 *   _XFlush
99 *   _XSend
100 *  _XEventsQueued
101 *  _XReadEvents
102 *  _XRead[0-9]+
103 *   _XAllocIDs
104 *  _XReply
105 *  _XEatData
106 * _XReadPad
107 */
108static void check_internal_connections(Display *dpy)
109{
110	struct _XConnectionInfo *ilist;
111	fd_set r_mask;
112	struct timeval tv;
113	int result;
114	int highest_fd = -1;
115
116	if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info)
117		return;
118
119	FD_ZERO(&r_mask);
120	for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next)
121	{
122		assert(ilist->fd >= 0);
123		FD_SET(ilist->fd, &r_mask);
124		if(ilist->fd > highest_fd)
125			highest_fd = ilist->fd;
126	}
127	assert(highest_fd >= 0);
128
129	tv.tv_sec = 0;
130	tv.tv_usec = 0;
131	result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv);
132
133	if(result == -1)
134	{
135		if(errno == EINTR)
136			return;
137		_XIOError(dpy);
138	}
139
140	for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next)
141		if(FD_ISSET(ilist->fd, &r_mask))
142		{
143			_XProcessInternalConnection(dpy, ilist);
144			--result;
145		}
146}
147
148static PendingRequest *append_pending_request(Display *dpy, unsigned long sequence)
149{
150	PendingRequest *node = malloc(sizeof(PendingRequest));
151	assert(node);
152	node->next = NULL;
153	node->sequence = sequence;
154	node->reply_waiter = 0;
155	if(dpy->xcb->pending_requests_tail)
156	{
157		if (XLIB_SEQUENCE_COMPARE(dpy->xcb->pending_requests_tail->sequence,
158		                          >=, node->sequence))
159			throw_thread_fail_assert("Unknown sequence number "
160			                         "while appending request",
161			                         xcb_xlib_unknown_seq_number);
162		if (dpy->xcb->pending_requests_tail->next != NULL)
163			throw_thread_fail_assert("Unknown request in queue "
164			                         "while appending request",
165			                         xcb_xlib_unknown_req_pending);
166		dpy->xcb->pending_requests_tail->next = node;
167	}
168	else
169		dpy->xcb->pending_requests = node;
170	dpy->xcb->pending_requests_tail = node;
171	return node;
172}
173
174static void dequeue_pending_request(Display *dpy, PendingRequest *req)
175{
176	if (req != dpy->xcb->pending_requests)
177		throw_thread_fail_assert("Unknown request in queue while "
178		                         "dequeuing",
179		                         xcb_xlib_unknown_req_in_deq);
180
181	dpy->xcb->pending_requests = req->next;
182	if(!dpy->xcb->pending_requests)
183	{
184		if (req != dpy->xcb->pending_requests_tail)
185			throw_thread_fail_assert("Unknown request in queue "
186			                         "while dequeuing",
187			                         xcb_xlib_unknown_req_in_deq);
188		dpy->xcb->pending_requests_tail = NULL;
189	}
190	else if (XLIB_SEQUENCE_COMPARE(req->sequence, >=,
191	                               dpy->xcb->pending_requests->sequence))
192		throw_thread_fail_assert("Unknown sequence number while "
193		                         "dequeuing request",
194		                         xcb_xlib_threads_sequence_lost);
195
196	free(req);
197}
198
199static int handle_error(Display *dpy, xError *err, Bool in_XReply)
200{
201	_XExtension *ext;
202	int ret_code;
203	/* Oddly, Xlib only allows extensions to suppress errors when
204	 * those errors were seen by _XReply. */
205	if(in_XReply)
206		/*
207		 * we better see if there is an extension who may
208		 * want to suppress the error.
209		 */
210		for(ext = dpy->ext_procs; ext; ext = ext->next)
211			if(ext->error && (*ext->error)(dpy, err, &ext->codes, &ret_code))
212				return ret_code;
213	_XError(dpy, err);
214	return 0;
215}
216
217/* Widen a 32-bit sequence number into a native-word-size (unsigned long)
218 * sequence number.  Treating the comparison as a 1 and shifting it avoids a
219 * conditional branch, and shifting by 16 twice avoids a compiler warning when
220 * sizeof(unsigned long) == 4. */
221static void widen(unsigned long *wide, unsigned int narrow)
222{
223	unsigned long new = (*wide & ~0xFFFFFFFFUL) | narrow;
224	*wide = new + ((unsigned long) (new < *wide) << 16 << 16);
225}
226
227/* Thread-safety rules:
228 *
229 * At most one thread can be reading from XCB's event queue at a time.
230 * If you are not the current event-reading thread and you need to find
231 * out if an event is available, you must wait.
232 *
233 * The same rule applies for reading replies.
234 *
235 * A single thread cannot be both the the event-reading and the
236 * reply-reading thread at the same time.
237 *
238 * We always look at both the current event and the first pending reply
239 * to decide which to process next.
240 *
241 * We always process all responses in sequence-number order, which may
242 * mean waiting for another thread (either the event_waiter or the
243 * reply_waiter) to handle an earlier response before we can process or
244 * return a later one. If so, we wait on the corresponding condition
245 * variable for that thread to process the response and wake us up.
246 */
247
248static xcb_generic_reply_t *poll_for_event(Display *dpy)
249{
250	/* Make sure the Display's sequence numbers are valid */
251	require_socket(dpy);
252
253	/* Precondition: This thread can safely get events from XCB. */
254	assert(dpy->xcb->event_owner == XlibOwnsEventQueue && !dpy->xcb->event_waiter);
255
256	if(!dpy->xcb->next_event)
257		dpy->xcb->next_event = xcb_poll_for_event(dpy->xcb->connection);
258
259	if(dpy->xcb->next_event)
260	{
261		PendingRequest *req = dpy->xcb->pending_requests;
262		xcb_generic_event_t *event = dpy->xcb->next_event;
263		unsigned long event_sequence = dpy->last_request_read;
264		widen(&event_sequence, event->full_sequence);
265		if(!req || XLIB_SEQUENCE_COMPARE(event_sequence, <, req->sequence)
266		        || (event->response_type != X_Error && event_sequence == req->sequence))
267		{
268			if (XLIB_SEQUENCE_COMPARE(event_sequence, >,
269			                          dpy->request))
270			{
271				throw_thread_fail_assert("Unknown sequence "
272				                         "number while "
273							 "processing queue",
274				                xcb_xlib_threads_sequence_lost);
275			}
276			dpy->last_request_read = event_sequence;
277			dpy->xcb->next_event = NULL;
278			return (xcb_generic_reply_t *) event;
279		}
280	}
281	return NULL;
282}
283
284static xcb_generic_reply_t *poll_for_response(Display *dpy)
285{
286	void *response;
287	xcb_generic_error_t *error;
288	PendingRequest *req;
289	while(!(response = poll_for_event(dpy)) &&
290	      (req = dpy->xcb->pending_requests) &&
291	      !req->reply_waiter &&
292	      xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &response, &error))
293	{
294		if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request))
295		{
296			throw_thread_fail_assert("Unknown sequence number "
297			                         "while awaiting reply",
298			                        xcb_xlib_threads_sequence_lost);
299		}
300		dpy->last_request_read = req->sequence;
301		if(response)
302			break;
303		dequeue_pending_request(dpy, req);
304		if(error)
305			return (xcb_generic_reply_t *) error;
306	}
307	return response;
308}
309
310static void handle_response(Display *dpy, xcb_generic_reply_t *response, Bool in_XReply)
311{
312	_XAsyncHandler *async, *next;
313	switch(response->response_type)
314	{
315	case X_Reply:
316		for(async = dpy->async_handlers; async; async = next)
317		{
318			next = async->next;
319			if(async->handler(dpy, (xReply *) response, (char *) response, sizeof(xReply) + (response->length << 2), async->data))
320				break;
321		}
322		break;
323
324	case X_Error:
325		handle_error(dpy, (xError *) response, in_XReply);
326		break;
327
328	default: /* event */
329		/* GenericEvents may be > 32 bytes. In this case, the
330		 * event struct is trailed by the additional bytes. the
331		 * xcb_generic_event_t struct uses 4 bytes for internal
332		 * numbering, so we need to shift the trailing data to
333		 * be after the first 32 bytes. */
334		if(response->response_type == GenericEvent && ((xcb_ge_event_t *) response)->length)
335		{
336			xcb_ge_event_t *event = (xcb_ge_event_t *) response;
337			memmove(&event->full_sequence, &event[1], event->length * 4);
338		}
339		_XEnq(dpy, (xEvent *) response);
340		break;
341	}
342	free(response);
343}
344
345int _XEventsQueued(Display *dpy, int mode)
346{
347	xcb_generic_reply_t *response;
348	if(dpy->flags & XlibDisplayIOError)
349		return 0;
350	if(dpy->xcb->event_owner != XlibOwnsEventQueue)
351		return 0;
352
353	if(mode == QueuedAfterFlush)
354		_XSend(dpy, NULL, 0);
355	else
356		check_internal_connections(dpy);
357
358	/* If another thread is blocked waiting for events, then we must
359	 * let that thread pick up the next event. Since it blocked, we
360	 * can reasonably claim there are no new events right now. */
361	if(!dpy->xcb->event_waiter)
362	{
363		while((response = poll_for_response(dpy)))
364			handle_response(dpy, response, False);
365		if(xcb_connection_has_error(dpy->xcb->connection))
366			_XIOError(dpy);
367	}
368	return dpy->qlen;
369}
370
371/* _XReadEvents - Flush the output queue,
372 * then read as many events as possible (but at least 1) and enqueue them
373 */
374void _XReadEvents(Display *dpy)
375{
376	xcb_generic_reply_t *response;
377	unsigned long serial;
378
379	if(dpy->flags & XlibDisplayIOError)
380		return;
381	_XSend(dpy, NULL, 0);
382	if(dpy->xcb->event_owner != XlibOwnsEventQueue)
383		return;
384	check_internal_connections(dpy);
385
386	serial = dpy->next_event_serial_num;
387	while(serial == dpy->next_event_serial_num || dpy->qlen == 0)
388	{
389		if(dpy->xcb->event_waiter)
390		{
391			ConditionWait(dpy, dpy->xcb->event_notify);
392			/* Maybe the other thread got us an event. */
393			continue;
394		}
395
396		if(!dpy->xcb->next_event)
397		{
398			xcb_generic_event_t *event;
399			dpy->xcb->event_waiter = 1;
400			UnlockDisplay(dpy);
401			event = xcb_wait_for_event(dpy->xcb->connection);
402			/* It appears that classic Xlib respected user
403			 * locks when waking up after waiting for
404			 * events. However, if this thread did not have
405			 * any user locks, and another thread takes a
406			 * user lock and tries to read events, then we'd
407			 * deadlock. So we'll choose to let the thread
408			 * that got in first consume events, despite the
409			 * later thread's user locks. */
410			InternalLockDisplay(dpy, /* ignore user locks */ 1);
411			dpy->xcb->event_waiter = 0;
412			ConditionBroadcast(dpy, dpy->xcb->event_notify);
413			if(!event)
414				_XIOError(dpy);
415			dpy->xcb->next_event = event;
416		}
417
418		/* We've established most of the conditions for
419		 * poll_for_response to return non-NULL. The exceptions
420		 * are connection shutdown, and finding that another
421		 * thread is waiting for the next reply we'd like to
422		 * process. */
423
424		response = poll_for_response(dpy);
425		if(response)
426			handle_response(dpy, response, False);
427		else if(dpy->xcb->pending_requests->reply_waiter)
428		{ /* need braces around ConditionWait */
429			ConditionWait(dpy, dpy->xcb->reply_notify);
430		}
431		else
432			_XIOError(dpy);
433	}
434
435	/* The preceding loop established that there is no
436	 * event_waiter--unless we just called ConditionWait because of
437	 * a reply_waiter, in which case another thread may have become
438	 * the event_waiter while we slept unlocked. */
439	if(!dpy->xcb->event_waiter)
440		while((response = poll_for_response(dpy)))
441			handle_response(dpy, response, False);
442	if(xcb_connection_has_error(dpy->xcb->connection))
443		_XIOError(dpy);
444}
445
446/*
447 * _XSend - Flush the buffer and send the client data. 32 bit word aligned
448 * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
449 *
450 * Note that the connection must not be read from once the data currently
451 * in the buffer has been written.
452 */
453void _XSend(Display *dpy, const char *data, long size)
454{
455	static const xReq dummy_request;
456	static char const pad[3];
457	struct iovec vec[3];
458	uint64_t requests;
459	_XExtension *ext;
460	xcb_connection_t *c = dpy->xcb->connection;
461	if(dpy->flags & XlibDisplayIOError)
462		return;
463
464	if(dpy->bufptr == dpy->buffer && !size)
465		return;
466
467	/* iff we asked XCB to set aside errors, we must pick those up
468	 * eventually. iff there are async handlers, we may have just
469	 * issued requests that will generate replies. in either case,
470	 * we need to remember to check later. */
471	if(dpy->xcb->event_owner != XlibOwnsEventQueue || dpy->async_handlers)
472	{
473		uint64_t sequence;
474		for(sequence = dpy->xcb->last_flushed + 1; sequence <= dpy->request; ++sequence)
475			append_pending_request(dpy, sequence);
476	}
477	requests = dpy->request - dpy->xcb->last_flushed;
478	dpy->xcb->last_flushed = dpy->request;
479
480	vec[0].iov_base = dpy->buffer;
481	vec[0].iov_len = dpy->bufptr - dpy->buffer;
482	vec[1].iov_base = (char *)data;
483	vec[1].iov_len = size;
484	vec[2].iov_base = (char *)pad;
485	vec[2].iov_len = -size & 3;
486
487	for(ext = dpy->flushes; ext; ext = ext->next_flush)
488	{
489		int i;
490		for(i = 0; i < 3; ++i)
491			if(vec[i].iov_len)
492				ext->before_flush(dpy, &ext->codes, vec[i].iov_base, vec[i].iov_len);
493	}
494
495	if(xcb_writev(c, vec, 3, requests) < 0)
496		_XIOError(dpy);
497	dpy->bufptr = dpy->buffer;
498	dpy->last_req = (char *) &dummy_request;
499
500	check_internal_connections(dpy);
501
502	_XSetSeqSyncFunction(dpy);
503}
504
505/*
506 * _XFlush - Flush the X request buffer.  If the buffer is empty, no
507 * action is taken.
508 */
509void _XFlush(Display *dpy)
510{
511	require_socket(dpy);
512	_XSend(dpy, NULL, 0);
513
514	_XEventsQueued(dpy, QueuedAfterReading);
515}
516
517static const XID inval_id = ~0UL;
518
519void _XIDHandler(Display *dpy)
520{
521	if (dpy->xcb->next_xid == inval_id)
522		_XAllocIDs(dpy, &dpy->xcb->next_xid, 1);
523}
524
525/* _XAllocID - resource ID allocation routine. */
526XID _XAllocID(Display *dpy)
527{
528	XID ret = dpy->xcb->next_xid;
529	assert (ret != inval_id);
530	dpy->xcb->next_xid = inval_id;
531	_XSetPrivSyncFunction(dpy);
532	return ret;
533}
534
535/* _XAllocIDs - multiple resource ID allocation routine. */
536void _XAllocIDs(Display *dpy, XID *ids, int count)
537{
538	int i;
539#ifdef XTHREADS
540	if (dpy->lock)
541		(*dpy->lock->user_lock_display)(dpy);
542	UnlockDisplay(dpy);
543#endif
544	for (i = 0; i < count; i++)
545		ids[i] = xcb_generate_id(dpy->xcb->connection);
546#ifdef XTHREADS
547	InternalLockDisplay(dpy, /* don't skip user locks */ 0);
548	if (dpy->lock)
549		(*dpy->lock->user_unlock_display)(dpy);
550#endif
551}
552
553static void _XFreeReplyData(Display *dpy, Bool force)
554{
555	if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length)
556		return;
557	free(dpy->xcb->reply_data);
558	dpy->xcb->reply_data = NULL;
559}
560
561/*
562 * _XReply - Wait for a reply packet and copy its contents into the
563 * specified rep.
564 * extra: number of 32-bit words expected after the reply
565 * discard: should I discard data following "extra" words?
566 */
567Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
568{
569	xcb_generic_error_t *error;
570	xcb_connection_t *c = dpy->xcb->connection;
571	char *reply;
572	PendingRequest *current;
573
574	if (dpy->xcb->reply_data)
575		throw_extlib_fail_assert("Extra reply data still left in queue",
576		                         xcb_xlib_extra_reply_data_left);
577
578	if(dpy->flags & XlibDisplayIOError)
579		return 0;
580
581	_XSend(dpy, NULL, 0);
582	if(dpy->xcb->pending_requests_tail && dpy->xcb->pending_requests_tail->sequence == dpy->request)
583		current = dpy->xcb->pending_requests_tail;
584	else
585		current = append_pending_request(dpy, dpy->request);
586	/* Don't let any other thread get this reply. */
587	current->reply_waiter = 1;
588
589	while(1)
590	{
591		PendingRequest *req = dpy->xcb->pending_requests;
592		xcb_generic_reply_t *response;
593
594		if(req != current && req->reply_waiter)
595		{
596			ConditionWait(dpy, dpy->xcb->reply_notify);
597			/* Another thread got this reply. */
598			continue;
599		}
600		req->reply_waiter = 1;
601		UnlockDisplay(dpy);
602		response = xcb_wait_for_reply(c, req->sequence, &error);
603		/* Any user locks on another thread must have been taken
604		 * while we slept in xcb_wait_for_reply. Classic Xlib
605		 * ignored those user locks in this case, so we do too. */
606		InternalLockDisplay(dpy, /* ignore user locks */ 1);
607
608		/* We have the response we're looking for. Now, before
609		 * letting anyone else process this sequence number, we
610		 * need to process any events that should have come
611		 * earlier. */
612
613		if(dpy->xcb->event_owner == XlibOwnsEventQueue)
614		{
615			xcb_generic_reply_t *event;
616			/* If some thread is already waiting for events,
617			 * it will get the first one. That thread must
618			 * process that event before we can continue. */
619			/* FIXME: That event might be after this reply,
620			 * and might never even come--or there might be
621			 * multiple threads trying to get events. */
622			while(dpy->xcb->event_waiter)
623			{ /* need braces around ConditionWait */
624				ConditionWait(dpy, dpy->xcb->event_notify);
625			}
626			while((event = poll_for_event(dpy)))
627				handle_response(dpy, event, True);
628		}
629
630		req->reply_waiter = 0;
631		ConditionBroadcast(dpy, dpy->xcb->reply_notify);
632		if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request)) {
633			throw_thread_fail_assert("Unknown sequence number "
634			                         "while processing reply",
635			                        xcb_xlib_threads_sequence_lost);
636		}
637		dpy->last_request_read = req->sequence;
638		if(!response)
639			dequeue_pending_request(dpy, req);
640
641		if(req == current)
642		{
643			reply = (char *) response;
644			break;
645		}
646
647		if(error)
648			handle_response(dpy, (xcb_generic_reply_t *) error, True);
649		else if(response)
650			handle_response(dpy, response, True);
651	}
652	check_internal_connections(dpy);
653
654	if(dpy->xcb->next_event && dpy->xcb->next_event->response_type == X_Error)
655	{
656		xcb_generic_event_t *event = dpy->xcb->next_event;
657		unsigned long event_sequence = dpy->last_request_read;
658		widen(&event_sequence, event->full_sequence);
659		if(event_sequence == dpy->last_request_read)
660		{
661			error = (xcb_generic_error_t *) event;
662			dpy->xcb->next_event = NULL;
663		}
664	}
665
666	if(error)
667	{
668		int ret_code;
669
670		/* Xlib is evil and assumes that even errors will be
671		 * copied into rep. */
672		memcpy(rep, error, 32);
673
674		/* do not die on "no such font", "can't allocate",
675		   "can't grab" failures */
676		switch(error->error_code)
677		{
678			case BadName:
679				switch(error->major_code)
680				{
681					case X_LookupColor:
682					case X_AllocNamedColor:
683						free(error);
684						return 0;
685				}
686				break;
687			case BadFont:
688				if(error->major_code == X_QueryFont) {
689					free(error);
690					return 0;
691				}
692				break;
693			case BadAlloc:
694			case BadAccess:
695				free(error);
696				return 0;
697		}
698
699		ret_code = handle_error(dpy, (xError *) error, True);
700		free(error);
701		return ret_code;
702	}
703
704	/* it's not an error, but we don't have a reply, so it's an I/O
705	 * error. */
706	if(!reply)
707	{
708		_XIOError(dpy);
709		return 0;
710	}
711
712	/* there's no error and we have a reply. */
713	dpy->xcb->reply_data = reply;
714	dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4);
715	dpy->xcb->reply_length = sizeof(xReply);
716	if(dpy->xcb->reply_data[0] == 1)
717		dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4);
718
719	/* error: Xlib asks too much. give them what we can anyway. */
720	if(dpy->xcb->reply_length < dpy->xcb->reply_consumed)
721		dpy->xcb->reply_consumed = dpy->xcb->reply_length;
722
723	memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed);
724	_XFreeReplyData(dpy, discard);
725	return 1;
726}
727
728int _XRead(Display *dpy, char *data, long size)
729{
730	assert(size >= 0);
731	if(size == 0)
732		return 0;
733	if(dpy->xcb->reply_data == NULL ||
734	   dpy->xcb->reply_consumed + size > dpy->xcb->reply_length)
735		throw_extlib_fail_assert("Too much data requested from _XRead",
736		                         xcb_xlib_too_much_data_requested);
737	memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size);
738	dpy->xcb->reply_consumed += size;
739	_XFreeReplyData(dpy, False);
740	return 0;
741}
742
743/*
744 * _XReadPad - Read bytes from the socket taking into account incomplete
745 * reads.  If the number of bytes is not 0 mod 4, read additional pad
746 * bytes.
747 */
748void _XReadPad(Display *dpy, char *data, long size)
749{
750	_XRead(dpy, data, size);
751	dpy->xcb->reply_consumed += -size & 3;
752	_XFreeReplyData(dpy, False);
753}
754
755/* Read and discard "n" 8-bit bytes of data */
756void _XEatData(Display *dpy, unsigned long n)
757{
758	dpy->xcb->reply_consumed += n;
759	_XFreeReplyData(dpy, False);
760}
761
762/*
763 * Read and discard "n" 32-bit words of data
764 * Matches the units of the length field in X protocol replies, and provides
765 * a single implementation of overflow checking to avoid having to replicate
766 * those checks in every caller.
767 */
768void _XEatDataWords(Display *dpy, unsigned long n)
769{
770	if (n < ((INT_MAX - dpy->xcb->reply_consumed) >> 2))
771		dpy->xcb->reply_consumed += (n << 2);
772	else
773		/* Overflow would happen, so just eat the rest of the reply */
774		dpy->xcb->reply_consumed = dpy->xcb->reply_length;
775	_XFreeReplyData(dpy, False);
776}
777