~ubuntu-branches/ubuntu/lucid/libx11/lucid

« back to all changes in this revision

Viewing changes to src/xcb_lock.c

  • Committer: Bazaar Package Importer
  • Author(s): Timo Aaltonen
  • Date: 2009-01-17 16:34:54 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20090117163454-gaey3cd32xyavueo
Tags: 2:1.1.99.2-1build1
Fakesync with Debian, all previous Ubuntu changes are included
in the new upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett
2
 
 * This file is licensed under the MIT license. See the file COPYING. */
3
 
 
4
 
#ifdef HAVE_CONFIG_H
5
 
#include <config.h>
6
 
#endif
7
 
 
8
 
#include "Xlibint.h"
9
 
#include "locking.h"
10
 
#include "Xxcbint.h"
11
 
#include <xcb/xcbext.h>
12
 
#include <xcb/xcbxlib.h>
13
 
 
14
 
#include <pthread.h>
15
 
 
16
 
static void _XCBLockDisplay(Display *dpy)
17
 
{
18
 
    if(dpy->xcb->lock_fns.lock_display)
19
 
        dpy->xcb->lock_fns.lock_display(dpy);
20
 
    if(!dpy->lock || dpy->lock->locking_level == 0)
21
 
        xcb_xlib_lock(dpy->xcb->connection);
22
 
    if(!(dpy->flags & XlibDisplayIOError))
23
 
        _XGetXCBBuffer(dpy);
24
 
}
25
 
 
26
 
/* XXX: If you change this function, update _XReply's copy of its guts! */
27
 
static void _XCBUnlockDisplay(Display *dpy)
28
 
{
29
 
    if(!(dpy->flags & XlibDisplayIOError))
30
 
    {
31
 
        _XPutXCBBuffer(dpy);
32
 
        assert(dpy->xcb->partial_request == 0);
33
 
        assert(xcb_get_request_sent(dpy->xcb->connection) == dpy->request);
34
 
 
35
 
        /* Traditional Xlib does this in _XSend; see the Xlib/XCB version
36
 
         * of that function for why we do it here instead. */
37
 
        _XSetSeqSyncFunction(dpy);
38
 
    }
39
 
 
40
 
    if(!dpy->lock || dpy->lock->locking_level == 0)
41
 
        xcb_xlib_unlock(dpy->xcb->connection);
42
 
    if(dpy->xcb->lock_fns.unlock_display)
43
 
        dpy->xcb->lock_fns.unlock_display(dpy);
44
 
}
45
 
 
46
 
int _XCBInitDisplayLock(Display *dpy)
47
 
{
48
 
    if(!dpy->lock_fns && !(dpy->lock_fns = Xcalloc(1, sizeof(*dpy->lock_fns))))
49
 
        return 0;
50
 
    dpy->xcb->lock_fns.lock_display = dpy->lock_fns->lock_display;
51
 
    dpy->lock_fns->lock_display = _XCBLockDisplay;
52
 
    dpy->xcb->lock_fns.unlock_display = dpy->lock_fns->unlock_display;
53
 
    dpy->lock_fns->unlock_display = _XCBUnlockDisplay;
54
 
    return 1;
55
 
}
56
 
 
57
 
void _XCBShutdownDisplayLock(Display *dpy)
58
 
{
59
 
    if(dpy->lock_fns) {
60
 
        Xfree((char *)dpy->lock_fns);
61
 
        dpy->lock_fns = NULL;
62
 
    }
63
 
}
64
 
 
65
 
void _XGetXCBBuffer(Display *dpy)
66
 
{
67
 
    static const xReq dummy_request;
68
 
    unsigned int xcb_req = xcb_get_request_sent(dpy->xcb->connection);
69
 
    if(xcb_connection_has_error(dpy->xcb->connection))
70
 
        _XIOError(dpy);
71
 
 
72
 
    /* if Xlib has a partial request pending then XCB doesn't know about
73
 
     * the current request yet */
74
 
    if(dpy->xcb->partial_request)
75
 
        ++xcb_req;
76
 
 
77
 
    assert(XCB_SEQUENCE_COMPARE(xcb_req, >=, dpy->request));
78
 
    dpy->request = xcb_req;
79
 
 
80
 
    dpy->last_req = (char *) &dummy_request;
81
 
}
82
 
 
83
 
static size_t request_length(struct iovec *vec)
84
 
{
85
 
    /* we have at least part of a request. dig out the length field.
86
 
     * note that length fields are always in vec[0]: Xlib doesn't split
87
 
     * fixed-length request parts. */
88
 
    size_t len;
89
 
    assert(vec[0].iov_len >= 4);
90
 
    len = ((uint16_t *) vec[0].iov_base)[1];
91
 
    if(len == 0)
92
 
    {
93
 
        /* it's a bigrequest. dig out the *real* length field. */
94
 
        assert(vec[0].iov_len >= 8);
95
 
        len = ((uint32_t *) vec[0].iov_base)[1];
96
 
    }
97
 
    return len << 2;
98
 
}
99
 
 
100
 
static inline int issue_complete_request(Display *dpy, int veclen, struct iovec *vec)
101
 
{
102
 
    xcb_protocol_request_t xcb_req = { 0 };
103
 
    unsigned int sequence;
104
 
    int flags = XCB_REQUEST_RAW;
105
 
    int i;
106
 
    size_t len;
107
 
 
108
 
    /* skip empty iovecs. if no iovecs remain, we're done. */
109
 
    assert(veclen >= 0);
110
 
    while(veclen > 0 && vec[0].iov_len == 0)
111
 
        --veclen, ++vec;
112
 
    if(!veclen)
113
 
        return 0;
114
 
 
115
 
    len = request_length(vec);
116
 
 
117
 
    /* do we have enough data for a complete request? how many iovec
118
 
     * elements does it span? */
119
 
    for(i = 0; i < veclen; ++i)
120
 
    {
121
 
        size_t oldlen = len;
122
 
        len -= vec[i].iov_len;
123
 
        /* if len is now 0 or has wrapped, we have enough data. */
124
 
        if((len - 1) > oldlen)
125
 
            break;
126
 
    }
127
 
    if(i == veclen)
128
 
        return 0;
129
 
 
130
 
    /* we have enough data to issue one complete request. the remaining
131
 
     * code can't fail. */
132
 
 
133
 
    /* len says how far we overshot our data needs. (it's "negative" if
134
 
     * we actually overshot, or 0 if we're right on.) */
135
 
    vec[i].iov_len += len;
136
 
    xcb_req.count = i + 1;
137
 
    xcb_req.opcode = ((uint8_t *) vec[0].iov_base)[0];
138
 
 
139
 
    /* if we don't own the event queue, we have to ask XCB to set our
140
 
     * errors aside for us. */
141
 
    if(dpy->xcb->event_owner != XlibOwnsEventQueue)
142
 
        flags |= XCB_REQUEST_CHECKED;
143
 
 
144
 
    /* XCB will always skip request 0; account for that in the Xlib count */
145
 
    if (xcb_get_request_sent(dpy->xcb->connection) == 0xffffffff)
146
 
        dpy->request++;
147
 
    /* send the accumulated request. */
148
 
    sequence = xcb_send_request(dpy->xcb->connection, flags, vec, &xcb_req);
149
 
    if(!sequence)
150
 
        _XIOError(dpy);
151
 
 
152
 
    /* update the iovecs to refer only to data not yet sent. */
153
 
    vec[i].iov_len = -len;
154
 
 
155
 
    /* iff we asked XCB to set aside errors, we must pick those up
156
 
     * eventually. iff there are async handlers, we may have just
157
 
     * issued requests that will generate replies. in either case,
158
 
     * we need to remember to check later. */
159
 
    if(flags & XCB_REQUEST_CHECKED || dpy->async_handlers)
160
 
    {
161
 
        PendingRequest *req = malloc(sizeof(PendingRequest));
162
 
        assert(req);
163
 
        req->next = 0;
164
 
        req->waiters = -1;
165
 
        req->sequence = sequence;
166
 
        *dpy->xcb->pending_requests_tail = req;
167
 
        dpy->xcb->pending_requests_tail = &req->next;
168
 
    }
169
 
    return 1;
170
 
}
171
 
 
172
 
void _XPutXCBBuffer(Display *dpy)
173
 
{
174
 
    static char const pad[3];
175
 
    const int padsize = -dpy->xcb->request_extra_size & 3;
176
 
    xcb_connection_t *c = dpy->xcb->connection;
177
 
    _XExtension *ext;
178
 
    struct iovec iov[6];
179
 
 
180
 
    assert_sequence_less(dpy->last_request_read, dpy->request);
181
 
    assert_sequence_less(xcb_get_request_sent(c), dpy->request);
182
 
 
183
 
    for(ext = dpy->flushes; ext; ext = ext->next_flush)
184
 
    {
185
 
        ext->before_flush(dpy, &ext->codes, dpy->buffer, dpy->bufptr - dpy->buffer);
186
 
        if(dpy->xcb->request_extra)
187
 
        {
188
 
            ext->before_flush(dpy, &ext->codes, dpy->xcb->request_extra, dpy->xcb->request_extra_size);
189
 
            if(padsize)
190
 
                ext->before_flush(dpy, &ext->codes, pad, padsize);
191
 
        }
192
 
    }
193
 
 
194
 
    iov[2].iov_base = dpy->xcb->partial_request;
195
 
    iov[2].iov_len = dpy->xcb->partial_request_offset;
196
 
    iov[3].iov_base = dpy->buffer;
197
 
    iov[3].iov_len = dpy->bufptr - dpy->buffer;
198
 
    iov[4].iov_base = (caddr_t) dpy->xcb->request_extra;
199
 
    iov[4].iov_len = dpy->xcb->request_extra_size;
200
 
    iov[5].iov_base = (caddr_t) pad;
201
 
    iov[5].iov_len = padsize;
202
 
 
203
 
    while(issue_complete_request(dpy, 4, iov + 2))
204
 
        /* empty */;
205
 
 
206
 
    /* first discard any completed partial_request. */
207
 
    if(iov[2].iov_len == 0 && dpy->xcb->partial_request)
208
 
    {
209
 
        free(dpy->xcb->partial_request);
210
 
        dpy->xcb->partial_request = 0;
211
 
        dpy->xcb->partial_request_offset = 0;
212
 
    }
213
 
 
214
 
    /* is there anything to copy into partial_request? */
215
 
    if(iov[3].iov_len != 0 || iov[4].iov_len != 0 || iov[5].iov_len != 0)
216
 
    {
217
 
        int i;
218
 
        if(!dpy->xcb->partial_request)
219
 
        {
220
 
            size_t len = request_length(iov + 3);
221
 
            assert(!dpy->xcb->partial_request_offset);
222
 
            dpy->xcb->partial_request = malloc(len);
223
 
            assert(dpy->xcb->partial_request);
224
 
        }
225
 
        for(i = 3; i < sizeof(iov) / sizeof(*iov); ++i)
226
 
        {
227
 
            memcpy(dpy->xcb->partial_request + dpy->xcb->partial_request_offset, iov[i].iov_base, iov[i].iov_len);
228
 
            dpy->xcb->partial_request_offset += iov[i].iov_len;
229
 
        }
230
 
    }
231
 
 
232
 
    dpy->xcb->request_extra = 0;
233
 
    dpy->xcb->request_extra_size = 0;
234
 
    dpy->bufptr = dpy->buffer;
235
 
}