aboutsummaryrefslogtreecommitdiff
path: root/libxcb/src
diff options
context:
space:
mode:
Diffstat (limited to 'libxcb/src')
-rw-r--r--libxcb/src/c_client.py18
-rw-r--r--libxcb/src/xcb_in.c13
-rw-r--r--libxcb/src/xcb_out.c40
-rw-r--r--libxcb/src/xcbext.h1
-rw-r--r--libxcb/src/xcbint.h7
5 files changed, 49 insertions, 30 deletions
diff --git a/libxcb/src/c_client.py b/libxcb/src/c_client.py
index a8e21012c..a43eae21b 100644
--- a/libxcb/src/c_client.py
+++ b/libxcb/src/c_client.py
@@ -688,10 +688,20 @@ def _c_serialize_helper_switch(context, self, complex_name,
switch_expr = _c_accessor_get_expr(self.expr, None)
for b in self.bitcases:
- bitcase_expr = _c_accessor_get_expr(b.type.expr, None)
- code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
-# code_lines.append(' printf("switch %s: entering bitcase section %s (mask=%%%%d)...\\n", %s);' %
-# (self.name[-1], b.type.name[-1], bitcase_expr))
+ len_expr = len(b.type.expr)
+ for n, expr in enumerate(b.type.expr):
+ bitcase_expr = _c_accessor_get_expr(expr, None)
+ # only one <enumref> in the <bitcase>
+ if len_expr == 1:
+ code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
+ # multiple <enumref> in the <bitcase>
+ elif n == 0: # first
+ code_lines.append(' if((%s & %s) ||' % (switch_expr, bitcase_expr))
+ elif len_expr == (n + 1): # last
+ code_lines.append(' (%s & %s)) {' % (switch_expr, bitcase_expr))
+ else: # between first and last
+ code_lines.append(' (%s & %s) ||' % (switch_expr, bitcase_expr))
+
b_prefix = prefix
if b.type.has_name:
b_prefix = prefix + [(b.c_field_name, '.', b.type)]
diff --git a/libxcb/src/xcb_in.c b/libxcb/src/xcb_in.c
index da2b7077a..a10dbe83c 100644
--- a/libxcb/src/xcb_in.c
+++ b/libxcb/src/xcb_in.c
@@ -94,8 +94,9 @@ static void remove_finished_readers(reader_list **prev_reader, uint64_t complete
static int read_packet(xcb_connection_t *c)
{
xcb_generic_reply_t genrep;
- int length = 32;
- int eventlength = 0; /* length after first 32 bytes for GenericEvents */
+ uint64_t length = 32;
+ uint64_t eventlength = 0; /* length after first 32 bytes for GenericEvents */
+ uint64_t bufsize;
void *buf;
pending_reply *pend = 0;
struct event_list *event;
@@ -170,8 +171,12 @@ static int read_packet(xcb_connection_t *c)
if ((genrep.response_type & 0x7f) == XCB_XGE_EVENT)
eventlength = genrep.length * 4;
- buf = malloc(length + eventlength +
- (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t)));
+ bufsize = length + eventlength +
+ (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t));
+ if (bufsize < INT32_MAX)
+ buf = malloc((size_t) bufsize);
+ else
+ buf = NULL;
if(!buf)
{
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
diff --git a/libxcb/src/xcb_out.c b/libxcb/src/xcb_out.c
index 996fedb23..4cb837c1a 100644
--- a/libxcb/src/xcb_out.c
+++ b/libxcb/src/xcb_out.c
@@ -87,21 +87,24 @@ static void send_sync(xcb_connection_t *c)
static void get_socket_back(xcb_connection_t *c)
{
- while(c->out.return_socket && c->out.socket_moving)
- pthread_cond_wait(&c->out.socket_cond, &c->iolock);
- if(!c->out.return_socket)
- return;
-
- c->out.socket_moving = 1;
- pthread_mutex_unlock(&c->iolock);
- c->out.return_socket(c->out.socket_closure);
- pthread_mutex_lock(&c->iolock);
- c->out.socket_moving = 0;
-
- pthread_cond_broadcast(&c->out.socket_cond);
- c->out.return_socket = 0;
- c->out.socket_closure = 0;
- _xcb_in_replies_done(c);
+ while (c->out.return_socket) {
+ /* we are about to release the lock,
+ so make a copy of the current status */
+ xcb_return_socket_func_t return_socket = c->out.return_socket;
+ void *socket_closure = c->out.socket_closure;
+ int socket_seq = c->out.socket_seq;
+
+ pthread_mutex_unlock(&c->iolock);
+ return_socket(socket_closure);
+ pthread_mutex_lock(&c->iolock);
+
+ /* make sure nobody else has acquired the socket */
+ if (socket_seq == c->out.socket_seq) {
+ c->out.return_socket = 0;
+ c->out.socket_closure = 0;
+ _xcb_in_replies_done(c);
+ }
+ }
}
/* Public interface */
@@ -273,12 +276,13 @@ int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), v
* write requests, so keep flushing until we're done
*/
do
- ret = _xcb_out_flush_to(c, c->out.request);
+ ret = _xcb_out_flush_to(c, c->out.request);
while (ret && c->out.request != c->out.request_written);
if(ret)
{
c->out.return_socket = return_socket;
c->out.socket_closure = closure;
+ ++c->out.socket_seq;
if(flags)
_xcb_in_expect_reply(c, c->out.request, WORKAROUND_EXTERNAL_SOCKET_OWNER, flags);
assert(c->out.request == c->out.request_written);
@@ -315,11 +319,9 @@ int xcb_flush(xcb_connection_t *c)
int _xcb_out_init(_xcb_out *out)
{
- if(pthread_cond_init(&out->socket_cond, 0))
- return 0;
out->return_socket = 0;
out->socket_closure = 0;
- out->socket_moving = 0;
+ out->socket_seq = 0;
if(pthread_cond_init(&out->cond, 0))
return 0;
diff --git a/libxcb/src/xcbext.h b/libxcb/src/xcbext.h
index 98b3c93c1..4e1f2f73d 100644
--- a/libxcb/src/xcbext.h
+++ b/libxcb/src/xcbext.h
@@ -66,6 +66,7 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
* callback which XCB can call when it wants the write side of the
* socket back to make a request. This callback synchronizes with the
* external socket owner and flushes any output queues if appropriate.
+ * The callback might be called from different threads at the same time.
* If you are sending requests which won't cause a reply, please note the
* comment for xcb_writev which explains some sequence number wrap issues.
* */
diff --git a/libxcb/src/xcbint.h b/libxcb/src/xcbint.h
index f9e5a52f7..7f9ab2838 100644
--- a/libxcb/src/xcbint.h
+++ b/libxcb/src/xcbint.h
@@ -79,14 +79,15 @@ void *_xcb_map_remove(_xcb_map *q, unsigned int key);
/* xcb_out.c */
+typedef void (*xcb_return_socket_func_t)(void *closure);
+
typedef struct _xcb_out {
pthread_cond_t cond;
int writing;
- pthread_cond_t socket_cond;
- void (*return_socket)(void *closure);
+ xcb_return_socket_func_t return_socket;
void *socket_closure;
- int socket_moving;
+ unsigned int socket_seq;
char queue[XCB_QUEUE_BUFFER_SIZE];
int queue_len;