xcb_in.c revision f1c62215
1/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a 4 * copy of this software and associated documentation files (the "Software"), 5 * to deal in the Software without restriction, including without limitation 6 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 * and/or sell copies of the Software, and to permit persons to whom the 8 * Software is furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 17 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 * 20 * Except as contained in this notice, the names of the authors or their 21 * institutions shall not be used in advertising or otherwise to promote the 22 * sale, use or other dealings in this Software without prior written 23 * authorization from the authors. 24 */ 25 26/* Stuff that reads stuff from the server. */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <assert.h> 33#include <string.h> 34#include <stdlib.h> 35#include <unistd.h> 36#include <stdio.h> 37#include <errno.h> 38 39#if USE_POLL 40#include <poll.h> 41#endif 42#ifndef _WIN32 43#include <sys/select.h> 44#include <sys/socket.h> 45#endif 46 47#ifdef _WIN32 48#include "xcb_windefs.h" 49#endif /* _WIN32 */ 50 51#include "xcb.h" 52#include "xcbext.h" 53#include "xcbint.h" 54 55#define XCB_ERROR 0 56#define XCB_REPLY 1 57#define XCB_XGE_EVENT 35 58 59struct event_list { 60 xcb_generic_event_t *event; 61 struct event_list *next; 62}; 63 64struct xcb_special_event { 65 66 struct xcb_special_event *next; 67 68 /* Match XGE events for the specific extension and event ID (the 69 * first 32 bit word after evtype) 70 */ 71 uint8_t extension; 72 uint32_t eid; 73 uint32_t *stamp; 74 75 struct event_list *events; 76 struct event_list **events_tail; 77 78 pthread_cond_t special_event_cond; 79}; 80 81struct reply_list { 82 void *reply; 83 struct reply_list *next; 84}; 85 86typedef struct pending_reply { 87 uint64_t first_request; 88 uint64_t last_request; 89 enum workarounds workaround; 90 int flags; 91 struct pending_reply *next; 92} pending_reply; 93 94typedef struct reader_list { 95 uint64_t request; 96 pthread_cond_t *data; 97 struct reader_list *next; 98} reader_list; 99 100typedef struct special_list { 101 xcb_special_event_t *se; 102 struct special_list *next; 103} special_list; 104 105static void remove_finished_readers(reader_list **prev_reader, uint64_t completed) 106{ 107 while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, completed)) 108 { 109 /* If you don't have what you're looking for now, you never 110 * will. Wake up and leave me alone. */ 111 pthread_cond_signal((*prev_reader)->data); 112 *prev_reader = (*prev_reader)->next; 113 } 114} 115 116#if HAVE_SENDMSG 117static int read_fds(xcb_connection_t *c, int *fds, int nfd) 118{ 119 int *ifds = &c->in.in_fd.fd[c->in.in_fd.ifd]; 120 int infd = c->in.in_fd.nfd - c->in.in_fd.ifd; 121 122 if (nfd > infd) 123 return 0; 124 memcpy(fds, ifds, nfd * sizeof (int)); 125 c->in.in_fd.ifd += nfd; 126 return 1; 127} 128#endif 129 130typedef struct xcb_ge_special_event_t { 131 uint8_t response_type; /**< */ 132 uint8_t extension; /**< */ 133 uint16_t sequence; /**< */ 134 uint32_t length; /**< */ 135 uint16_t evtype; /**< */ 136 uint8_t pad0[2]; /**< */ 137 uint32_t eid; /**< */ 138 uint8_t pad1[16]; /**< */ 139} xcb_ge_special_event_t; 140 141static int event_special(xcb_connection_t *c, 142 struct event_list *event) 143{ 144 struct xcb_special_event *special_event; 145 struct xcb_ge_special_event_t *ges = (void *) event->event; 146 147 /* Special events are always XGE events */ 148 if ((ges->response_type & 0x7f) != XCB_XGE_EVENT) 149 return 0; 150 151 for (special_event = c->in.special_events; 152 special_event; 153 special_event = special_event->next) 154 { 155 if (ges->extension == special_event->extension && 156 ges->eid == special_event->eid) 157 { 158 *special_event->events_tail = event; 159 special_event->events_tail = &event->next; 160 if (special_event->stamp) 161 ++(*special_event->stamp); 162 pthread_cond_signal(&special_event->special_event_cond); 163 return 1; 164 } 165 } 166 167 return 0; 168} 169 170static int read_packet(xcb_connection_t *c) 171{ 172 xcb_generic_reply_t genrep; 173 uint64_t length = 32; 174 uint64_t eventlength = 0; /* length after first 32 bytes for GenericEvents */ 175 int nfd = 0; /* Number of file descriptors attached to the reply */ 176 uint64_t bufsize; 177 void *buf; 178 pending_reply *pend = 0; 179 struct event_list *event; 180 181 /* Wait for there to be enough data for us to read a whole packet */ 182 if(c->in.queue_len < length) 183 return 0; 184 185 /* Get the response type, length, and sequence number. */ 186 memcpy(&genrep, c->in.queue, sizeof(genrep)); 187 188 /* Compute 32-bit sequence number of this packet. */ 189 if((genrep.response_type & 0x7f) != XCB_KEYMAP_NOTIFY) 190 { 191 uint64_t lastread = c->in.request_read; 192 c->in.request_read = (lastread & UINT64_C(0xffffffffffff0000)) | genrep.sequence; 193 if(XCB_SEQUENCE_COMPARE(c->in.request_read, <, lastread)) 194 c->in.request_read += 0x10000; 195 if(XCB_SEQUENCE_COMPARE(c->in.request_read, >, c->in.request_expected)) 196 c->in.request_expected = c->in.request_read; 197 198 if(c->in.request_read != lastread) 199 { 200 if(c->in.current_reply) 201 { 202 _xcb_map_put(c->in.replies, lastread, c->in.current_reply); 203 c->in.current_reply = 0; 204 c->in.current_reply_tail = &c->in.current_reply; 205 } 206 c->in.request_completed = c->in.request_read - 1; 207 } 208 209 while(c->in.pending_replies && 210 c->in.pending_replies->workaround != WORKAROUND_EXTERNAL_SOCKET_OWNER && 211 XCB_SEQUENCE_COMPARE (c->in.pending_replies->last_request, <=, c->in.request_completed)) 212 { 213 pending_reply *oldpend = c->in.pending_replies; 214 c->in.pending_replies = oldpend->next; 215 if(!oldpend->next) 216 c->in.pending_replies_tail = &c->in.pending_replies; 217 free(oldpend); 218 } 219 220 if(genrep.response_type == XCB_ERROR) 221 c->in.request_completed = c->in.request_read; 222 223 remove_finished_readers(&c->in.readers, c->in.request_completed); 224 } 225 226 if(genrep.response_type == XCB_ERROR || genrep.response_type == XCB_REPLY) 227 { 228 pend = c->in.pending_replies; 229 if(pend && 230 !(XCB_SEQUENCE_COMPARE(pend->first_request, <=, c->in.request_read) && 231 (pend->workaround == WORKAROUND_EXTERNAL_SOCKET_OWNER || 232 XCB_SEQUENCE_COMPARE(c->in.request_read, <=, pend->last_request)))) 233 pend = 0; 234 } 235 236 /* For reply packets, check that the entire packet is available. */ 237 if(genrep.response_type == XCB_REPLY) 238 { 239 if(pend && pend->workaround == WORKAROUND_GLX_GET_FB_CONFIGS_BUG) 240 { 241 uint32_t *p = (uint32_t *) c->in.queue; 242 genrep.length = p[2] * p[3] * 2; 243 } 244 length += genrep.length * 4; 245 246 /* XXX a bit of a hack -- we "know" that all FD replys place 247 * the number of fds in the pad0 byte */ 248 if (pend && pend->flags & XCB_REQUEST_REPLY_FDS) 249 nfd = genrep.pad0; 250 } 251 252 /* XGE events may have sizes > 32 */ 253 if ((genrep.response_type & 0x7f) == XCB_XGE_EVENT) 254 eventlength = genrep.length * 4; 255 256 bufsize = length + eventlength + nfd * sizeof(int) + 257 (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t)); 258 if (bufsize < INT32_MAX) 259 buf = malloc((size_t) bufsize); 260 else 261 buf = NULL; 262 if(!buf) 263 { 264 _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT); 265 return 0; 266 } 267 268 if(_xcb_in_read_block(c, buf, length) <= 0) 269 { 270 free(buf); 271 return 0; 272 } 273 274 /* pull in XGE event data if available, append after event struct */ 275 if (eventlength) 276 { 277 if(_xcb_in_read_block(c, &((xcb_generic_event_t*)buf)[1], eventlength) <= 0) 278 { 279 free(buf); 280 return 0; 281 } 282 } 283 284#if HAVE_SENDMSG 285 if (nfd) 286 { 287 if (!read_fds(c, (int *) &((char *) buf)[length], nfd)) 288 { 289 free(buf); 290 return 0; 291 } 292 } 293#endif 294 295 if(pend && (pend->flags & XCB_REQUEST_DISCARD_REPLY)) 296 { 297 free(buf); 298 return 1; 299 } 300 301 if(genrep.response_type != XCB_REPLY) 302 ((xcb_generic_event_t *) buf)->full_sequence = c->in.request_read; 303 304 /* reply, or checked error */ 305 if( genrep.response_type == XCB_REPLY || 306 (genrep.response_type == XCB_ERROR && pend && (pend->flags & XCB_REQUEST_CHECKED))) 307 { 308 struct reply_list *cur = malloc(sizeof(struct reply_list)); 309 if(!cur) 310 { 311 _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT); 312 free(buf); 313 return 0; 314 } 315 cur->reply = buf; 316 cur->next = 0; 317 *c->in.current_reply_tail = cur; 318 c->in.current_reply_tail = &cur->next; 319 if(c->in.readers && c->in.readers->request == c->in.request_read) 320 pthread_cond_signal(c->in.readers->data); 321 return 1; 322 } 323 324 /* event, or unchecked error */ 325 event = malloc(sizeof(struct event_list)); 326 if(!event) 327 { 328 _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT); 329 free(buf); 330 return 0; 331 } 332 event->event = buf; 333 event->next = 0; 334 335 if (!event_special(c, event)) { 336 *c->in.events_tail = event; 337 c->in.events_tail = &event->next; 338 pthread_cond_signal(&c->in.event_cond); 339 } 340 return 1; /* I have something for you... */ 341} 342 343static xcb_generic_event_t *get_event(xcb_connection_t *c) 344{ 345 struct event_list *cur = c->in.events; 346 xcb_generic_event_t *ret; 347 if(!c->in.events) 348 return 0; 349 ret = cur->event; 350 c->in.events = cur->next; 351 if(!cur->next) 352 c->in.events_tail = &c->in.events; 353 free(cur); 354 return ret; 355} 356 357static void free_reply_list(struct reply_list *head) 358{ 359 while(head) 360 { 361 struct reply_list *cur = head; 362 head = cur->next; 363 free(cur->reply); 364 free(cur); 365 } 366} 367 368static int read_block(const int fd, void *buf, const ssize_t len) 369{ 370 int done = 0; 371 while(done < len) 372 { 373 int ret = recv(fd, ((char *) buf) + done, len - done, 0); 374 if(ret > 0) 375 done += ret; 376#ifndef _WIN32 377 if(ret < 0 && errno == EAGAIN) 378#else 379 if(ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) 380#endif /* !_Win32 */ 381 { 382#if USE_POLL 383 struct pollfd pfd; 384 pfd.fd = fd; 385 pfd.events = POLLIN; 386 pfd.revents = 0; 387 do { 388 ret = poll(&pfd, 1, -1); 389 } while (ret == -1 && errno == EINTR); 390#else 391 fd_set fds; 392 FD_ZERO(&fds); 393 FD_SET(fd, &fds); 394 395 /* Initializing errno here makes sure that for Win32 this loop will execute only once */ 396 errno = 0; 397 do { 398 ret = select(fd + 1, &fds, 0, 0, 0); 399 } while (ret == -1 && errno == EINTR); 400#endif /* USE_POLL */ 401 } 402 if(ret <= 0) 403 return ret; 404 } 405 return len; 406} 407 408static int poll_for_reply(xcb_connection_t *c, uint64_t request, void **reply, xcb_generic_error_t **error) 409{ 410 struct reply_list *head; 411 412 /* If an error occurred when issuing the request, fail immediately. */ 413 if(!request) 414 head = 0; 415 /* We've read requests past the one we want, so if it has replies we have 416 * them all and they're in the replies map. */ 417 else if(XCB_SEQUENCE_COMPARE(request, <, c->in.request_read)) 418 { 419 head = _xcb_map_remove(c->in.replies, request); 420 if(head && head->next) 421 _xcb_map_put(c->in.replies, request, head->next); 422 } 423 /* We're currently processing the responses to the request we want, and we 424 * have a reply ready to return. So just return it without blocking. */ 425 else if(request == c->in.request_read && c->in.current_reply) 426 { 427 head = c->in.current_reply; 428 c->in.current_reply = head->next; 429 if(!head->next) 430 c->in.current_reply_tail = &c->in.current_reply; 431 } 432 /* We know this request can't have any more replies, and we've already 433 * established it doesn't have a reply now. Don't bother blocking. */ 434 else if(request == c->in.request_completed) 435 head = 0; 436 /* We may have more replies on the way for this request: block until we're 437 * sure. */ 438 else 439 return 0; 440 441 if(error) 442 *error = 0; 443 *reply = 0; 444 445 if(head) 446 { 447 if(((xcb_generic_reply_t *) head->reply)->response_type == XCB_ERROR) 448 { 449 if(error) 450 *error = head->reply; 451 else 452 free(head->reply); 453 } 454 else 455 *reply = head->reply; 456 457 free(head); 458 } 459 460 return 1; 461} 462 463static void insert_reader(reader_list **prev_reader, reader_list *reader, uint64_t request, pthread_cond_t *cond) 464{ 465 while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, request)) 466 prev_reader = &(*prev_reader)->next; 467 reader->request = request; 468 reader->data = cond; 469 reader->next = *prev_reader; 470 *prev_reader = reader; 471} 472 473static void remove_reader(reader_list **prev_reader, reader_list *reader) 474{ 475 while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, reader->request)) 476 if(*prev_reader == reader) 477 { 478 *prev_reader = (*prev_reader)->next; 479 break; 480 } 481} 482 483static void insert_special(special_list **prev_special, special_list *special, xcb_special_event_t *se) 484{ 485 special->se = se; 486 special->next = *prev_special; 487 *prev_special = special; 488} 489 490static void remove_special(special_list **prev_special, special_list *special) 491{ 492 while(*prev_special) 493 { 494 if(*prev_special == special) 495 { 496 *prev_special = (*prev_special)->next; 497 break; 498 } 499 prev_special = &(*prev_special)->next; 500 } 501} 502 503static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_error_t **e) 504{ 505 void *ret = 0; 506 507 /* If this request has not been written yet, write it. */ 508 if(c->out.return_socket || _xcb_out_flush_to(c, request)) 509 { 510 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 511 reader_list reader; 512 513 insert_reader(&c->in.readers, &reader, request, &cond); 514 515 while(!poll_for_reply(c, request, &ret, e)) 516 if(!_xcb_conn_wait(c, &cond, 0, 0)) 517 break; 518 519 remove_reader(&c->in.readers, &reader); 520 pthread_cond_destroy(&cond); 521 } 522 523 _xcb_in_wake_up_next_reader(c); 524 return ret; 525} 526 527static uint64_t widen(xcb_connection_t *c, unsigned int request) 528{ 529 uint64_t widened_request = (c->out.request & UINT64_C(0xffffffff00000000)) | request; 530 if(widened_request > c->out.request) 531 widened_request -= UINT64_C(1) << 32; 532 return widened_request; 533} 534 535/* Public interface */ 536 537void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e) 538{ 539 void *ret; 540 if(e) 541 *e = 0; 542 if(c->has_error) 543 return 0; 544 545 pthread_mutex_lock(&c->iolock); 546 ret = wait_for_reply(c, widen(c, request), e); 547 pthread_mutex_unlock(&c->iolock); 548 return ret; 549} 550 551void *xcb_wait_for_reply64(xcb_connection_t *c, uint64_t request, xcb_generic_error_t **e) 552{ 553 void *ret; 554 if(e) 555 *e = 0; 556 if(c->has_error) 557 return 0; 558 559 pthread_mutex_lock(&c->iolock); 560 ret = wait_for_reply(c, request, e); 561 pthread_mutex_unlock(&c->iolock); 562 return ret; 563} 564 565int *xcb_get_reply_fds(xcb_connection_t *c, void *reply, size_t reply_size) 566{ 567 return (int *) (&((char *) reply)[reply_size]); 568} 569 570static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_next, uint64_t seq) 571{ 572 pending_reply *pend; 573 pend = malloc(sizeof(*pend)); 574 if(!pend) 575 { 576 _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT); 577 return; 578 } 579 580 pend->first_request = seq; 581 pend->last_request = seq; 582 pend->workaround = 0; 583 pend->flags = XCB_REQUEST_DISCARD_REPLY; 584 pend->next = *prev_next; 585 *prev_next = pend; 586 587 if(!pend->next) 588 c->in.pending_replies_tail = &pend->next; 589} 590 591static void discard_reply(xcb_connection_t *c, uint64_t request) 592{ 593 void *reply; 594 pending_reply **prev_pend; 595 596 /* Free any replies or errors that we've already read. Stop if 597 * xcb_wait_for_reply would block or we've run out of replies. */ 598 while(poll_for_reply(c, request, &reply, 0) && reply) 599 free(reply); 600 601 /* If we've proven there are no more responses coming, we're done. */ 602 if(XCB_SEQUENCE_COMPARE(request, <=, c->in.request_completed)) 603 return; 604 605 /* Walk the list of pending requests. Mark the first match for deletion. */ 606 for(prev_pend = &c->in.pending_replies; *prev_pend; prev_pend = &(*prev_pend)->next) 607 { 608 if(XCB_SEQUENCE_COMPARE((*prev_pend)->first_request, >, request)) 609 break; 610 611 if((*prev_pend)->first_request == request) 612 { 613 /* Pending reply found. Mark for discard: */ 614 (*prev_pend)->flags |= XCB_REQUEST_DISCARD_REPLY; 615 return; 616 } 617 } 618 619 /* Pending reply not found (likely due to _unchecked request). Create one: */ 620 insert_pending_discard(c, prev_pend, request); 621} 622 623void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence) 624{ 625 if(c->has_error) 626 return; 627 628 /* If an error occurred when issuing the request, fail immediately. */ 629 if(!sequence) 630 return; 631 632 pthread_mutex_lock(&c->iolock); 633 discard_reply(c, widen(c, sequence)); 634 pthread_mutex_unlock(&c->iolock); 635} 636 637void xcb_discard_reply64(xcb_connection_t *c, uint64_t sequence) 638{ 639 if(c->has_error) 640 return; 641 642 /* If an error occurred when issuing the request, fail immediately. */ 643 if(!sequence) 644 return; 645 646 pthread_mutex_lock(&c->iolock); 647 discard_reply(c, sequence); 648 pthread_mutex_unlock(&c->iolock); 649} 650 651int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error) 652{ 653 int ret; 654 if(c->has_error) 655 { 656 *reply = 0; 657 if(error) 658 *error = 0; 659 return 1; /* would not block */ 660 } 661 assert(reply != 0); 662 pthread_mutex_lock(&c->iolock); 663 ret = poll_for_reply(c, widen(c, request), reply, error); 664 pthread_mutex_unlock(&c->iolock); 665 return ret; 666} 667 668int xcb_poll_for_reply64(xcb_connection_t *c, uint64_t request, void **reply, xcb_generic_error_t **error) 669{ 670 int ret; 671 if(c->has_error) 672 { 673 *reply = 0; 674 if(error) 675 *error = 0; 676 return 1; /* would not block */ 677 } 678 assert(reply != 0); 679 pthread_mutex_lock(&c->iolock); 680 ret = poll_for_reply(c, request, reply, error); 681 pthread_mutex_unlock(&c->iolock); 682 return ret; 683} 684 685xcb_generic_event_t *xcb_wait_for_event(xcb_connection_t *c) 686{ 687 xcb_generic_event_t *ret; 688 if(c->has_error) 689 return 0; 690 pthread_mutex_lock(&c->iolock); 691 /* get_event returns 0 on empty list. */ 692 while(!(ret = get_event(c))) 693 if(!_xcb_conn_wait(c, &c->in.event_cond, 0, 0)) 694 break; 695 696 _xcb_in_wake_up_next_reader(c); 697 pthread_mutex_unlock(&c->iolock); 698 return ret; 699} 700 701static xcb_generic_event_t *poll_for_next_event(xcb_connection_t *c, int queued) 702{ 703 xcb_generic_event_t *ret = 0; 704 if(!c->has_error) 705 { 706 pthread_mutex_lock(&c->iolock); 707 /* FIXME: follow X meets Z architecture changes. */ 708 ret = get_event(c); 709 if(!ret && !queued && c->in.reading == 0 && _xcb_in_read(c)) /* _xcb_in_read shuts down the connection on error */ 710 ret = get_event(c); 711 pthread_mutex_unlock(&c->iolock); 712 } 713 return ret; 714} 715 716xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c) 717{ 718 return poll_for_next_event(c, 0); 719} 720 721xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c) 722{ 723 return poll_for_next_event(c, 1); 724} 725 726xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie) 727{ 728 uint64_t request; 729 xcb_generic_error_t *ret = 0; 730 void *reply; 731 if(c->has_error) 732 return 0; 733 pthread_mutex_lock(&c->iolock); 734 request = widen(c, cookie.sequence); 735 if(XCB_SEQUENCE_COMPARE(request, >=, c->in.request_expected) 736 && XCB_SEQUENCE_COMPARE(request, >, c->in.request_completed)) 737 { 738 _xcb_out_send_sync(c); 739 _xcb_out_flush_to(c, c->out.request); 740 } 741 reply = wait_for_reply(c, request, &ret); 742 assert(!reply); 743 pthread_mutex_unlock(&c->iolock); 744 return ret; 745} 746 747static xcb_generic_event_t *get_special_event(xcb_connection_t *c, 748 xcb_special_event_t *se) 749{ 750 xcb_generic_event_t *event = NULL; 751 struct event_list *events; 752 753 if ((events = se->events) != NULL) { 754 event = events->event; 755 if (!(se->events = events->next)) 756 se->events_tail = &se->events; 757 free (events); 758 } 759 return event; 760} 761 762xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c, 763 xcb_special_event_t *se) 764{ 765 xcb_generic_event_t *event; 766 767 if(c->has_error) 768 return 0; 769 pthread_mutex_lock(&c->iolock); 770 event = get_special_event(c, se); 771 pthread_mutex_unlock(&c->iolock); 772 return event; 773} 774 775xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c, 776 xcb_special_event_t *se) 777{ 778 special_list special; 779 xcb_generic_event_t *event; 780 781 if(c->has_error) 782 return 0; 783 pthread_mutex_lock(&c->iolock); 784 785 insert_special(&c->in.special_waiters, &special, se); 786 787 /* get_special_event returns 0 on empty list. */ 788 while(!(event = get_special_event(c, se))) 789 if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0)) 790 break; 791 792 remove_special(&c->in.special_waiters, &special); 793 794 _xcb_in_wake_up_next_reader(c); 795 pthread_mutex_unlock(&c->iolock); 796 return event; 797} 798 799xcb_special_event_t * 800xcb_register_for_special_xge(xcb_connection_t *c, 801 xcb_extension_t *ext, 802 uint32_t eid, 803 uint32_t *stamp) 804{ 805 xcb_special_event_t *se; 806 const xcb_query_extension_reply_t *ext_reply; 807 808 if(c->has_error) 809 return NULL; 810 ext_reply = xcb_get_extension_data(c, ext); 811 if (!ext_reply) 812 return NULL; 813 pthread_mutex_lock(&c->iolock); 814 for (se = c->in.special_events; se; se = se->next) { 815 if (se->extension == ext_reply->major_opcode && 816 se->eid == eid) { 817 pthread_mutex_unlock(&c->iolock); 818 return NULL; 819 } 820 } 821 se = calloc(1, sizeof(xcb_special_event_t)); 822 if (!se) { 823 pthread_mutex_unlock(&c->iolock); 824 return NULL; 825 } 826 827 se->extension = ext_reply->major_opcode; 828 se->eid = eid; 829 830 se->events = NULL; 831 se->events_tail = &se->events; 832 se->stamp = stamp; 833 834 pthread_cond_init(&se->special_event_cond, 0); 835 836 se->next = c->in.special_events; 837 c->in.special_events = se; 838 pthread_mutex_unlock(&c->iolock); 839 return se; 840} 841 842void 843xcb_unregister_for_special_event(xcb_connection_t *c, 844 xcb_special_event_t *se) 845{ 846 xcb_special_event_t *s, **prev; 847 struct event_list *events, *next; 848 849 if (!se) 850 return; 851 852 if (c->has_error) 853 return; 854 855 pthread_mutex_lock(&c->iolock); 856 857 for (prev = &c->in.special_events; (s = *prev) != NULL; prev = &(s->next)) { 858 if (s == se) { 859 *prev = se->next; 860 for (events = se->events; events; events = next) { 861 next = events->next; 862 free (events->event); 863 free (events); 864 } 865 pthread_cond_destroy(&se->special_event_cond); 866 free (se); 867 break; 868 } 869 } 870 pthread_mutex_unlock(&c->iolock); 871} 872 873/* Private interface */ 874 875int _xcb_in_init(_xcb_in *in) 876{ 877 if(pthread_cond_init(&in->event_cond, 0)) 878 return 0; 879 in->reading = 0; 880 881 in->queue_len = 0; 882 883 in->request_read = 0; 884 in->request_completed = 0; 885 886 in->replies = _xcb_map_new(); 887 if(!in->replies) 888 return 0; 889 890 in->current_reply_tail = &in->current_reply; 891 in->events_tail = &in->events; 892 in->pending_replies_tail = &in->pending_replies; 893 894 return 1; 895} 896 897void _xcb_in_destroy(_xcb_in *in) 898{ 899 pthread_cond_destroy(&in->event_cond); 900 free_reply_list(in->current_reply); 901 _xcb_map_delete(in->replies, (void (*)(void *)) free_reply_list); 902 while(in->events) 903 { 904 struct event_list *e = in->events; 905 in->events = e->next; 906 free(e->event); 907 free(e); 908 } 909 while(in->pending_replies) 910 { 911 pending_reply *pend = in->pending_replies; 912 in->pending_replies = pend->next; 913 free(pend); 914 } 915} 916 917void _xcb_in_wake_up_next_reader(xcb_connection_t *c) 918{ 919 int pthreadret; 920 if(c->in.readers) 921 pthreadret = pthread_cond_signal(c->in.readers->data); 922 else if(c->in.special_waiters) 923 pthreadret = pthread_cond_signal(&c->in.special_waiters->se->special_event_cond); 924 else 925 pthreadret = pthread_cond_signal(&c->in.event_cond); 926 assert(pthreadret == 0); 927} 928 929int _xcb_in_expect_reply(xcb_connection_t *c, uint64_t request, enum workarounds workaround, int flags) 930{ 931 pending_reply *pend = malloc(sizeof(pending_reply)); 932 assert(workaround != WORKAROUND_NONE || flags != 0); 933 if(!pend) 934 { 935 _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT); 936 return 0; 937 } 938 pend->first_request = pend->last_request = request; 939 pend->workaround = workaround; 940 pend->flags = flags; 941 pend->next = 0; 942 *c->in.pending_replies_tail = pend; 943 c->in.pending_replies_tail = &pend->next; 944 return 1; 945} 946 947void _xcb_in_replies_done(xcb_connection_t *c) 948{ 949 struct pending_reply *pend; 950 if (c->in.pending_replies_tail != &c->in.pending_replies) 951 { 952 pend = container_of(c->in.pending_replies_tail, struct pending_reply, next); 953 if(pend->workaround == WORKAROUND_EXTERNAL_SOCKET_OWNER) 954 { 955 pend->last_request = c->out.request; 956 pend->workaround = WORKAROUND_NONE; 957 } 958 } 959} 960 961int _xcb_in_read(xcb_connection_t *c) 962{ 963 int n; 964 965#if HAVE_SENDMSG 966 struct iovec iov = { 967 .iov_base = c->in.queue + c->in.queue_len, 968 .iov_len = sizeof(c->in.queue) - c->in.queue_len, 969 }; 970 union { 971 struct cmsghdr cmsghdr; 972 char buf[CMSG_SPACE(XCB_MAX_PASS_FD * sizeof(int))]; 973 } cmsgbuf; 974 struct msghdr msg = { 975 .msg_name = NULL, 976 .msg_namelen = 0, 977 .msg_iov = &iov, 978 .msg_iovlen = 1, 979 .msg_control = cmsgbuf.buf, 980 .msg_controllen = CMSG_SPACE(sizeof(int) * (XCB_MAX_PASS_FD - c->in.in_fd.nfd)), 981 }; 982 n = recvmsg(c->fd, &msg, 0); 983 984 /* Check for truncation errors. Only MSG_CTRUNC is 985 * probably possible here, which would indicate that 986 * the sender tried to transmit more than XCB_MAX_PASS_FD 987 * file descriptors. 988 */ 989 if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 990 _xcb_conn_shutdown(c, XCB_CONN_CLOSED_FDPASSING_FAILED); 991 return 0; 992 } 993#else 994 n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0); 995#endif 996 if(n > 0) { 997#if HAVE_SENDMSG 998 struct cmsghdr *hdr; 999 1000 if (msg.msg_controllen >= sizeof (struct cmsghdr)) { 1001 for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { 1002 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { 1003 int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int); 1004 memcpy(&c->in.in_fd.fd[c->in.in_fd.nfd], CMSG_DATA(hdr), nfd * sizeof (int)); 1005 c->in.in_fd.nfd += nfd; 1006 } 1007 } 1008 } 1009#endif 1010 c->in.queue_len += n; 1011 } 1012 while(read_packet(c)) 1013 /* empty */; 1014#if HAVE_SENDMSG 1015 if (c->in.in_fd.nfd) { 1016 c->in.in_fd.nfd -= c->in.in_fd.ifd; 1017 memmove(&c->in.in_fd.fd[0], 1018 &c->in.in_fd.fd[c->in.in_fd.ifd], 1019 c->in.in_fd.nfd * sizeof (int)); 1020 c->in.in_fd.ifd = 0; 1021 1022 /* If we have any left-over file descriptors after emptying 1023 * the input buffer, then the server sent some that we weren't 1024 * expecting. Close them and mark the connection as broken; 1025 */ 1026 if (c->in.queue_len == 0 && c->in.in_fd.nfd != 0) { 1027 int i; 1028 for (i = 0; i < c->in.in_fd.nfd; i++) 1029 close(c->in.in_fd.fd[i]); 1030 _xcb_conn_shutdown(c, XCB_CONN_CLOSED_FDPASSING_FAILED); 1031 return 0; 1032 } 1033 } 1034#endif 1035#ifndef _WIN32 1036 if((n > 0) || (n < 0 && errno == EAGAIN)) 1037#else 1038 if((n > 0) || (n < 0 && WSAGetLastError() == WSAEWOULDBLOCK)) 1039#endif /* !_WIN32 */ 1040 return 1; 1041 _xcb_conn_shutdown(c, XCB_CONN_ERROR); 1042 return 0; 1043} 1044 1045int _xcb_in_read_block(xcb_connection_t *c, void *buf, int len) 1046{ 1047 int done = c->in.queue_len; 1048 if(len < done) 1049 done = len; 1050 1051 memcpy(buf, c->in.queue, done); 1052 c->in.queue_len -= done; 1053 memmove(c->in.queue, c->in.queue + done, c->in.queue_len); 1054 1055 if(len > done) 1056 { 1057 int ret = read_block(c->fd, (char *) buf + done, len - done); 1058 if(ret <= 0) 1059 { 1060 _xcb_conn_shutdown(c, XCB_CONN_ERROR); 1061 return ret; 1062 } 1063 } 1064 1065 return len; 1066} 1067