~ubuntu-branches/ubuntu/lucid/xcb-util/lucid

« back to all changes in this revision

Viewing changes to reply/reply.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien Danjou
  • Date: 2009-02-15 12:58:13 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090215125813-fvdfqrch1341t8bd
Tags: 0.3.3-2
Add versioned link to GPL.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include "xcb_reply.h"
 
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
 */
2
28
 
3
29
#include <stdlib.h>
4
30
#include <xcb/xcbext.h>
5
31
 
6
 
struct node {
7
 
        struct node *next;
8
 
        unsigned int request;
9
 
        generic_reply_handler handler;
10
 
        void *data;
11
 
        char handled;
12
 
};
13
 
 
14
 
struct reply_handlers {
15
 
        pthread_mutex_t lock;
16
 
        pthread_cond_t cond;
17
 
        struct node *head;
18
 
        xcb_connection_t *c;
19
 
        pthread_t thread;
20
 
};
21
 
 
22
 
reply_handlers_t *alloc_reply_handlers(xcb_connection_t *c)
23
 
{
24
 
        reply_handlers_t *ret = calloc(1, sizeof(reply_handlers_t));
25
 
        if(ret)
26
 
        {
27
 
                static const pthread_mutex_t proto_lock = PTHREAD_MUTEX_INITIALIZER;
28
 
                static const pthread_cond_t proto_cond = PTHREAD_COND_INITIALIZER;
29
 
                ret->lock = proto_lock;
30
 
                ret->cond = proto_cond;
31
 
                ret->c = c;
32
 
        }
33
 
        return ret;
34
 
}
35
 
 
36
 
void free_reply_handlers(reply_handlers_t *h)
37
 
{
38
 
        free(h);
39
 
}
40
 
 
41
 
xcb_connection_t *get_xcb_connection(reply_handlers_t *h)
42
 
{
43
 
        return h->c;
44
 
}
45
 
 
46
 
static void insert_handler(reply_handlers_t *h, struct node *cur)
47
 
{
48
 
        struct node **prev = &h->head;
49
 
        while(*prev && (*prev)->request < cur->request)
50
 
                prev = &(*prev)->next;
51
 
        cur->next = *prev;
52
 
        *prev = cur;
53
 
}
54
 
 
55
 
static void remove_handler(reply_handlers_t *h, struct node *cur)
56
 
{
57
 
        struct node **prev = &h->head;
58
 
        while(*prev && (*prev)->request < cur->request)
59
 
                prev = &(*prev)->next;
60
 
        if(!(*prev) || (*prev)->request != cur->request)
61
 
                return;
62
 
        *prev = cur->next;
63
 
        free(cur);
64
 
}
65
 
 
66
 
static int process_replies(reply_handlers_t *h, int block)
67
 
{
68
 
        int handled = 0;
69
 
        pthread_mutex_lock(&h->lock);
70
 
        pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &h->lock);
71
 
        while(1)
72
 
        {
73
 
                struct node *cur = h->head;
74
 
                xcb_generic_error_t *error;
75
 
                void *reply;
76
 
                pthread_mutex_unlock(&h->lock);
77
 
                pthread_cleanup_push((void (*)(void *)) pthread_mutex_lock, &h->lock);
78
 
                if(block)
79
 
                        reply = xcb_wait_for_reply(h->c, cur->request, &error);
80
 
                else if(!xcb_poll_for_reply(h->c, cur->request, &reply, &error))
81
 
                        return handled;
82
 
                if(reply || error)
83
 
                {
84
 
                        cur->handler(cur->data, h->c, reply, error);
85
 
                        cur->handled = 1;
86
 
                        free(reply);
87
 
                        free(error);
88
 
                }
89
 
                handled |= cur->handled;
90
 
                pthread_cleanup_pop(1);
91
 
                if(!reply)
92
 
                        remove_handler(h, cur);
93
 
                if(!h->head)
94
 
                {
95
 
                        if(block)
96
 
                                pthread_cond_wait(&h->cond, &h->lock);
97
 
                        else
98
 
                                break;
99
 
                }
100
 
        }
101
 
        pthread_cleanup_pop(1);
102
 
        return handled;
103
 
}
104
 
 
105
 
int poll_replies(reply_handlers_t *h)
106
 
{
107
 
        xcb_flush(h->c);
108
 
        return process_replies(h, 0);
109
 
}
110
 
 
111
 
static void *reply_thread(void *h)
112
 
{
113
 
        process_replies(h, 1);
114
 
        return 0;
115
 
}
116
 
 
117
 
void start_reply_thread(reply_handlers_t *h)
118
 
{
119
 
        pthread_create(&h->thread, 0, reply_thread, h);
120
 
}
121
 
 
122
 
void stop_reply_thread(reply_handlers_t *h)
123
 
{
124
 
        pthread_cancel(h->thread);
125
 
        pthread_join(h->thread, 0);
126
 
}
127
 
 
128
 
void add_reply_handler(reply_handlers_t *h, unsigned int request, generic_reply_handler handler, void *data)
129
 
{
130
 
        struct node *cur = malloc(sizeof(struct node));
131
 
        cur->request = request;
132
 
        cur->handler = handler;
133
 
        cur->data = data;
134
 
        cur->handled = 0;
135
 
 
136
 
        pthread_mutex_lock(&h->lock);
137
 
        insert_handler(h, cur);
138
 
        pthread_cond_broadcast(&h->cond);
139
 
        pthread_mutex_unlock(&h->lock);
 
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);
140
146
}