1/* 2 * Copyright © 2008 Julien Danjou <julien@danjou.info> 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Except as contained in this notice, the names of the authors or 24 * their institutions shall not be used in advertising or otherwise to 25 * promote the sale, use or other dealings in this Software without 26 * prior written authorization from the authors. 27 */ 28 29#include <stdlib.h> 30#include <xcb/xcbext.h> 31 32#include "xcb_reply.h" 33 34void 35xcb_reply_handlers_init(xcb_connection_t *c, xcb_reply_handlers_t *r) 36{ 37 static const pthread_mutex_t proto_lock = PTHREAD_MUTEX_INITIALIZER; 38 static const pthread_cond_t proto_cond = PTHREAD_COND_INITIALIZER; 39 r->lock = proto_lock; 40 r->cond = proto_cond; 41 r->c = c; 42 r->head = NULL; 43} 44 45xcb_connection_t * 46xcb_reply_get_xcb_connection(xcb_reply_handlers_t *h) 47{ 48 return h->c; 49} 50 51static void 52insert_handler(xcb_reply_handlers_t *h, struct xcb_reply_node *cur) 53{ 54 struct xcb_reply_node **prev = &h->head; 55 while(*prev && (*prev)->request < cur->request) 56 prev = &(*prev)->next; 57 cur->next = *prev; 58 *prev = cur; 59} 60 61static void 62remove_handler(xcb_reply_handlers_t *h, struct xcb_reply_node *cur) 63{ 64 struct xcb_reply_node **prev = &h->head; 65 while(*prev && (*prev)->request < cur->request) 66 prev = &(*prev)->next; 67 if(!(*prev) || (*prev)->request != cur->request) 68 return; 69 *prev = cur->next; 70 free(cur); 71} 72 73static int 74process_replies(xcb_reply_handlers_t *h, int block) 75{ 76 int handled = 0; 77 pthread_mutex_lock(&h->lock); 78 pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &h->lock); 79 while(1) 80 { 81 struct xcb_reply_node *cur = h->head; 82 xcb_generic_error_t *error; 83 void *reply; 84 pthread_mutex_unlock(&h->lock); 85 pthread_cleanup_push((void (*)(void *)) pthread_mutex_lock, &h->lock); 86 if(block) 87 reply = xcb_wait_for_reply(h->c, cur->request, &error); 88 else if(!xcb_poll_for_reply(h->c, cur->request, &reply, &error)) 89 return handled; 90 if(reply || error) 91 { 92 cur->handler(cur->data, h->c, reply, error); 93 cur->handled = 1; 94 free(reply); 95 free(error); 96 } 97 handled |= cur->handled; 98 pthread_cleanup_pop(1); 99 if(!reply) 100 remove_handler(h, cur); 101 if(!h->head) 102 { 103 if(block) 104 pthread_cond_wait(&h->cond, &h->lock); 105 else 106 break; 107 } 108 } 109 pthread_cleanup_pop(1); 110 return handled; 111} 112 113static void * 114reply_thread(void *h) 115{ 116 process_replies(h, 1); 117 return 0; 118} 119 120void 121xcb_reply_start_thread(xcb_reply_handlers_t *h) 122{ 123 pthread_create(&h->thread, 0, reply_thread, h); 124} 125 126void 127xcb_reply_stop_thread(xcb_reply_handlers_t *h) 128{ 129 pthread_cancel(h->thread); 130 pthread_join(h->thread, 0); 131} 132 133void 134xcb_reply_add_handler(xcb_reply_handlers_t *h, unsigned int request, xcb_generic_reply_handler_t handler, void *data) 135{ 136 struct xcb_reply_node *cur = malloc(sizeof(struct xcb_reply_node)); 137 cur->request = request; 138 cur->handler = handler; 139 cur->data = data; 140 cur->handled = 0; 141 142 pthread_mutex_lock(&h->lock); 143 insert_handler(h, cur); 144 pthread_cond_broadcast(&h->cond); 145 pthread_mutex_unlock(&h->lock); 146} 147