Git init
[framework/uifw/xorg/xcb/xcb-util.git] / reply / reply.c
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
34 void
35 xcb_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
45 xcb_connection_t *
46 xcb_reply_get_xcb_connection(xcb_reply_handlers_t *h)
47 {
48     return h->c;
49 }
50
51 static void
52 insert_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
61 static void
62 remove_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
73 static int
74 process_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
113 static void *
114 reply_thread(void *h)
115 {
116     process_replies(h, 1);
117     return 0;
118 }
119
120 void
121 xcb_reply_start_thread(xcb_reply_handlers_t *h)
122 {
123     pthread_create(&h->thread, 0, reply_thread, h);
124 }
125
126 void
127 xcb_reply_stop_thread(xcb_reply_handlers_t *h)
128 {
129     pthread_cancel(h->thread);
130     pthread_join(h->thread, 0);
131 }
132
133 void
134 xcb_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 }