diff options
author | Julien Danjou <julien@danjou.info> | 2008-09-16 16:33:46 +0200 |
---|---|---|
committer | Julien Danjou <julien@danjou.info> | 2008-09-16 16:52:02 +0200 |
commit | 22189c7092c008c39019a41e3b78eb58fff5334a (patch) | |
tree | 9c8f0c1146e19b58aad4e23ec85832c9a1b73280 /reply | |
parent | 17132de01495c95833c2e8bafd66210a64d157d2 (diff) |
reply: rework and add some documentation
Signed-off-by: Julien Danjou <julien@danjou.info>
Diffstat (limited to 'reply')
-rw-r--r-- | reply/Makefile.am | 1 | ||||
-rw-r--r-- | reply/reply.c | 222 | ||||
-rw-r--r-- | reply/test_reply.c | 10 | ||||
-rw-r--r-- | reply/xcb_reply.h | 99 |
4 files changed, 208 insertions, 124 deletions
diff --git a/reply/Makefile.am b/reply/Makefile.am index 847d0f7..aa49773 100644 --- a/reply/Makefile.am +++ b/reply/Makefile.am @@ -12,6 +12,7 @@ XCB_REPLY_LIBS = libxcb-reply.la libxcb_reply_la_SOURCES = reply.c libxcb_reply_la_CPPFLAGS = $(XCB_CFLAGS) libxcb_reply_la_LIBADD = $(XCB_LIBS) -lpthread +libxcb_reply_la_LDFLAGS = -version-info 1:0:0 pkgconfig_DATA = xcb-reply.pc diff --git a/reply/reply.c b/reply/reply.c index 2072ae1..0322ae0 100644 --- a/reply/reply.c +++ b/reply/reply.c @@ -1,140 +1,146 @@ -#include "xcb_reply.h" +/* + * Copyright (C) 2008 Julien Danjou <julien@danjou.info> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or + * their institutions shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without + * prior written authorization from the authors. + */ #include <stdlib.h> #include <xcb/xcbext.h> -struct node { - struct node *next; - unsigned int request; - generic_reply_handler handler; - void *data; - char handled; -}; - -struct reply_handlers { - pthread_mutex_t lock; - pthread_cond_t cond; - struct node *head; - xcb_connection_t *c; - pthread_t thread; -}; - -reply_handlers_t *alloc_reply_handlers(xcb_connection_t *c) -{ - reply_handlers_t *ret = calloc(1, sizeof(reply_handlers_t)); - if(ret) - { - static const pthread_mutex_t proto_lock = PTHREAD_MUTEX_INITIALIZER; - static const pthread_cond_t proto_cond = PTHREAD_COND_INITIALIZER; - ret->lock = proto_lock; - ret->cond = proto_cond; - ret->c = c; - } - return ret; -} - -void free_reply_handlers(reply_handlers_t *h) -{ - free(h); -} +#include "xcb_reply.h" -xcb_connection_t *get_xcb_connection(reply_handlers_t *h) +void +xcb_reply_handlers_init(xcb_connection_t *c, xcb_reply_handlers_t *r) { - return h->c; + static const pthread_mutex_t proto_lock = PTHREAD_MUTEX_INITIALIZER; + static const pthread_cond_t proto_cond = PTHREAD_COND_INITIALIZER; + r->lock = proto_lock; + r->cond = proto_cond; + r->c = c; + r->head = NULL; } -static void insert_handler(reply_handlers_t *h, struct node *cur) +xcb_connection_t * +xcb_reply_get_xcb_connection(xcb_reply_handlers_t *h) { - struct node **prev = &h->head; - while(*prev && (*prev)->request < cur->request) - prev = &(*prev)->next; - cur->next = *prev; - *prev = cur; + return h->c; } -static void remove_handler(reply_handlers_t *h, struct node *cur) +static void +insert_handler(xcb_reply_handlers_t *h, struct xcb_reply_node *cur) { - struct node **prev = &h->head; - while(*prev && (*prev)->request < cur->request) - prev = &(*prev)->next; - if(!(*prev) || (*prev)->request != cur->request) - return; - *prev = cur->next; - free(cur); + struct xcb_reply_node **prev = &h->head; + while(*prev && (*prev)->request < cur->request) + prev = &(*prev)->next; + cur->next = *prev; + *prev = cur; } -static int process_replies(reply_handlers_t *h, int block) +static void +remove_handler(xcb_reply_handlers_t *h, struct xcb_reply_node *cur) { - int handled = 0; - pthread_mutex_lock(&h->lock); - pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &h->lock); - while(1) - { - struct node *cur = h->head; - xcb_generic_error_t *error; - void *reply; - pthread_mutex_unlock(&h->lock); - pthread_cleanup_push((void (*)(void *)) pthread_mutex_lock, &h->lock); - if(block) - reply = xcb_wait_for_reply(h->c, cur->request, &error); - else if(!xcb_poll_for_reply(h->c, cur->request, &reply, &error)) - return handled; - if(reply || error) - { - cur->handler(cur->data, h->c, reply, error); - cur->handled = 1; - free(reply); - free(error); - } - handled |= cur->handled; - pthread_cleanup_pop(1); - if(!reply) - remove_handler(h, cur); - if(!h->head) - { - if(block) - pthread_cond_wait(&h->cond, &h->lock); - else - break; - } - } - pthread_cleanup_pop(1); - return handled; + struct xcb_reply_node **prev = &h->head; + while(*prev && (*prev)->request < cur->request) + prev = &(*prev)->next; + if(!(*prev) || (*prev)->request != cur->request) + return; + *prev = cur->next; + free(cur); } -int poll_replies(reply_handlers_t *h) +static int +process_replies(xcb_reply_handlers_t *h, int block) { - xcb_flush(h->c); - return process_replies(h, 0); + int handled = 0; + pthread_mutex_lock(&h->lock); + pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &h->lock); + while(1) + { + struct xcb_reply_node *cur = h->head; + xcb_generic_error_t *error; + void *reply; + pthread_mutex_unlock(&h->lock); + pthread_cleanup_push((void (*)(void *)) pthread_mutex_lock, &h->lock); + if(block) + reply = xcb_wait_for_reply(h->c, cur->request, &error); + else if(!xcb_poll_for_reply(h->c, cur->request, &reply, &error)) + return handled; + if(reply || error) + { + cur->handler(cur->data, h->c, reply, error); + cur->handled = 1; + free(reply); + free(error); + } + handled |= cur->handled; + pthread_cleanup_pop(1); + if(!reply) + remove_handler(h, cur); + if(!h->head) + { + if(block) + pthread_cond_wait(&h->cond, &h->lock); + else + break; + } + } + pthread_cleanup_pop(1); + return handled; } -static void *reply_thread(void *h) +static void * +reply_thread(void *h) { - process_replies(h, 1); - return 0; + process_replies(h, 1); + return 0; } -void start_reply_thread(reply_handlers_t *h) +void +xcb_reply_start_thread(xcb_reply_handlers_t *h) { - pthread_create(&h->thread, 0, reply_thread, h); + pthread_create(&h->thread, 0, reply_thread, h); } -void stop_reply_thread(reply_handlers_t *h) +void +xcb_reply_stop_thread(xcb_reply_handlers_t *h) { - pthread_cancel(h->thread); - pthread_join(h->thread, 0); + pthread_cancel(h->thread); + pthread_join(h->thread, 0); } -void add_reply_handler(reply_handlers_t *h, unsigned int request, generic_reply_handler handler, void *data) +void +xcb_reply_add_handler(xcb_reply_handlers_t *h, unsigned int request, xcb_generic_reply_handler_t handler, void *data) { - struct node *cur = malloc(sizeof(struct node)); - cur->request = request; - cur->handler = handler; - cur->data = data; - cur->handled = 0; + struct xcb_reply_node *cur = malloc(sizeof(struct xcb_reply_node)); + cur->request = request; + cur->handler = handler; + cur->data = data; + cur->handled = 0; - pthread_mutex_lock(&h->lock); - insert_handler(h, cur); - pthread_cond_broadcast(&h->cond); - pthread_mutex_unlock(&h->lock); + pthread_mutex_lock(&h->lock); + insert_handler(h, cur); + pthread_cond_broadcast(&h->cond); + pthread_mutex_unlock(&h->lock); } diff --git a/reply/test_reply.c b/reply/test_reply.c index 8aee7d8..6f6a021 100644 --- a/reply/test_reply.c +++ b/reply/test_reply.c @@ -1,4 +1,3 @@ -#include <xcb/xcb.h> #include "xcb_reply.h" #include <string.h> @@ -36,18 +35,19 @@ int main(int argc, char **argv) int count = 10; char *pattern = "*"; xcb_connection_t *c = xcb_connect(NULL, NULL); - reply_handlers_t *h = alloc_reply_handlers(c); + xcb_reply_handlers_t h; + xcb_reply_handlers_init(c, &h); if(argc > 1) count = atoi(argv[1]); if(argc > 2) pattern = argv[2]; - add_reply_handler(h, xcb_list_fonts_with_info(c, count, strlen(pattern), pattern).sequence, fontinfo_handler, 0); + xcb_reply_add_handler(&h, xcb_list_fonts_with_info(c, count, strlen(pattern), pattern).sequence, fontinfo_handler, 0); pthread_mutex_lock(&lock); - start_reply_thread(h); + xcb_reply_start_thread(&h); pthread_cond_wait(&cond, &lock); - stop_reply_thread(h); + xcb_reply_stop_thread(&h); pthread_mutex_unlock(&lock); xcb_disconnect(c); diff --git a/reply/xcb_reply.h b/reply/xcb_reply.h index 8a9e71e..360f74a 100644 --- a/reply/xcb_reply.h +++ b/reply/xcb_reply.h @@ -1,32 +1,109 @@ +/* + * Copyright (C) 2008 Julien Danjou <julien@danjou.info> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or + * their institutions shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without + * prior written authorization from the authors. + */ + #ifndef __XCB_REPLY_H__ #define __XCB_REPLY_H__ #include <xcb/xcb.h> #include <pthread.h> - #ifdef __cplusplus extern "C" { #endif +typedef void (*xcb_generic_reply_handler_t)(void *data, xcb_connection_t *c, xcb_generic_reply_t *reply, xcb_generic_error_t *error); + +struct xcb_reply_node +{ + struct xcb_reply_node *next; + unsigned int request; + xcb_generic_reply_handler_t handler; + void *data; + char handled; +}; + +struct xcb_reply_handlers +{ + pthread_mutex_t lock; + pthread_cond_t cond; + struct xcb_reply_node *head; + xcb_connection_t *c; + pthread_t thread; +}; -typedef struct reply_handlers reply_handlers_t; -reply_handlers_t *alloc_reply_handlers(xcb_connection_t *c); -void free_reply_handlers(reply_handlers_t *h); -xcb_connection_t *get_xcb_connection(reply_handlers_t *h); +typedef struct xcb_reply_handlers xcb_reply_handlers_t; -int poll_replies(reply_handlers_t *h); -void start_reply_thread(reply_handlers_t *h); -void stop_reply_thread(reply_handlers_t *h); +/** + * @brief Initialize a reply handlers structure. + * @param c The connection to the X server. + * @param h The reply handlers. + */ +void xcb_reply_handlers_init(xcb_connection_t *c, xcb_reply_handlers_t *h); -typedef void (*generic_reply_handler)(void *data, xcb_connection_t *c, xcb_generic_reply_t *reply, xcb_generic_error_t *error); +/** + * @brief Get the connection to the X server used in reply handlers. + * @param h The reply handlers data structure. + * @return The connection to the X server. + */ +xcb_connection_t *xcb_reply_get_xcb_connection(xcb_reply_handlers_t *h); -void add_reply_handler(reply_handlers_t *h, unsigned int request, generic_reply_handler handler, void *data); +/** + * @brief Poll for reply using reply handlers. + * @param h The reply handlers data structure. + * @return The value return by the handler callback function, or 0 if no + * handler was found. + */ +int xcb_reply_poll_for_reply(xcb_reply_handlers_t *h); +/** + * @brief Start reply handling thread. + * This thread will run forever until it is stop with xcb_reply_stop_thread. + * @param h The reply handlers. + */ +void xcb_reply_start_thread(xcb_reply_handlers_t *h); + +/** + * @brief Stop reply handling thread. + * @param h The reply handlers. + */ +void xcb_reply_stop_thread(xcb_reply_handlers_t *h); + +/** + * @brief Add a reply handler. + * @param h The reply handlers data structure to fill. + * @param request The request identifier. + * @param handler The handler to call for this request. + * @param data Optional data passed to the callback function handling request. + */ +void xcb_reply_add_handler(xcb_reply_handlers_t *h, unsigned int request, xcb_generic_reply_handler_t handler, void *data); #ifdef __cplusplus } #endif - #endif /* __XCB_REPLY_H__ */ |