In struct XCBReplyData, change void *data to pthread_cond_t *data. That was dumb.
[free-sw/xcb/libxcb] / src / xcb_in.c
index 1f6dcbe..92bc0bf 100644 (file)
 #include "xcbext.h"
 #include "xcbint.h"
 
+struct event_list {
+    XCBGenericEvent *event;
+    struct event_list *next;
+};
+
+struct reply_list {
+    void *reply;
+    struct reply_list *next;
+};
+
 typedef struct pending_reply {
     unsigned int request;
     enum workarounds workaround;
@@ -45,7 +55,7 @@ typedef struct pending_reply {
 
 typedef struct XCBReplyData {
     unsigned int request;
-    void *data;
+    pthread_cond_t *data;
 } XCBReplyData;
 
 static int match_reply(const void *request, const void *data)
@@ -68,8 +78,9 @@ static int read_packet(XCBConnection *c)
 {
     XCBGenericRep genrep;
     int length = 32;
-    unsigned char *buf;
+    void *buf;
     pending_reply *pend = 0;
+    struct event_list *event;
 
     /* Wait for there to be enough data for us to read a whole packet */
     if(c->in.queue_len < length)
@@ -93,10 +104,11 @@ static int read_packet(XCBConnection *c)
                     c->in.pending_replies_tail = &c->in.pending_replies;
                 free(oldpend);
             }
-            if(!_xcb_queue_is_empty(c->in.current_reply))
+            if(c->in.current_reply)
             {
                 _xcb_map_put(c->in.replies, lastread, c->in.current_reply);
-                c->in.current_reply = _xcb_queue_new();
+                c->in.current_reply = 0;
+                c->in.current_reply_tail = &c->in.current_reply;
             }
         }
         if(c->in.request_read < lastread)
@@ -134,18 +146,58 @@ static int read_packet(XCBConnection *c)
     if(genrep.response_type == 1 || (genrep.response_type == 0 && pend && (pend->flags & XCB_REQUEST_CHECKED)))
     {
         XCBReplyData *reader = _xcb_list_find(c->in.readers, match_reply, &c->in.request_read);
-        _xcb_queue_enqueue(c->in.current_reply, buf);
+        struct reply_list *cur = malloc(sizeof(struct reply_list));
+        if(!cur)
+            return 0;
+        cur->reply = buf;
+        cur->next = 0;
+        *c->in.current_reply_tail = cur;
+        c->in.current_reply_tail = &cur->next;
         if(reader)
             pthread_cond_signal(reader->data);
         return 1;
     }
 
     /* event, or unchecked error */
-    _xcb_queue_enqueue(c->in.events, buf);
+    event = malloc(sizeof(struct event_list));
+    if(!event)
+    {
+        free(buf);
+        return 0;
+    }
+    event->event = buf;
+    event->next = 0;
+    *c->in.events_tail = event;
+    c->in.events_tail = &event->next;
     pthread_cond_signal(&c->in.event_cond);
     return 1; /* I have something for you... */
 }
 
+static XCBGenericEvent *get_event(XCBConnection *c)
+{
+    struct event_list *cur = c->in.events;
+    XCBGenericEvent *ret;
+    if(!c->in.events)
+        return 0;
+    ret = cur->event;
+    c->in.events = cur->next;
+    if(!cur->next)
+        c->in.events_tail = &c->in.events;
+    free(cur);
+    return ret;
+}
+
+static void free_reply_list(struct reply_list *head)
+{
+    while(head)
+    {
+        struct reply_list *cur = head;
+        head = cur->next;
+        free(cur->reply);
+        free(cur);
+    }
+}
+
 static int read_block(const int fd, void *buf, const size_t len)
 {
     int done = 0;
@@ -173,6 +225,7 @@ void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **
 {
     pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
     XCBReplyData reader;
+    struct reply_list *head;
     void *ret = 0;
     if(e)
         *e = 0;
@@ -193,31 +246,40 @@ void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **
 
     /* If this request has not been read yet, wait for it. */
     while(((signed int) (c->in.request_read - request) < 0 ||
-            (c->in.request_read == request &&
-            _xcb_queue_is_empty(c->in.current_reply))))
+            (c->in.request_read == request && !c->in.current_reply)))
         if(!_xcb_conn_wait(c, /*should_write*/ 0, &cond))
             goto done;
 
     if(c->in.request_read != request)
     {
-        _xcb_queue *q = _xcb_map_get(c->in.replies, request);
-        if(q)
+        head = _xcb_map_remove(c->in.replies, request);
+        if(head && head->next)
+            _xcb_map_put(c->in.replies, request, head->next);
+    }
+    else
+    {
+        head = c->in.current_reply;
+        if(head)
         {
-            ret = _xcb_queue_dequeue(q);
-            if(_xcb_queue_is_empty(q))
-                _xcb_queue_delete(_xcb_map_remove(c->in.replies, request), free);
+            c->in.current_reply = head->next;
+            if(!head->next)
+                c->in.current_reply_tail = &c->in.current_reply;
         }
     }
-    else
-        ret = _xcb_queue_dequeue(c->in.current_reply);
 
-    if(ret && ((XCBGenericRep *) ret)->response_type == 0) /* X error */
+    if(head)
     {
-        if(e)
-            *e = ret;
-        else
-            free(ret);
-        ret = 0;
+        ret = head->reply;
+        free(head);
+
+        if(((XCBGenericRep *) ret)->response_type == 0) /* X error */
+        {
+            if(e)
+                *e = ret;
+            else
+                free(ret);
+            ret = 0;
+        }
     }
 
 done:
@@ -238,8 +300,8 @@ XCBGenericEvent *XCBWaitForEvent(XCBConnection *c)
 {
     XCBGenericEvent *ret;
     pthread_mutex_lock(&c->iolock);
-    /* _xcb_list_remove_head returns 0 on empty list. */
-    while(!(ret = _xcb_queue_dequeue(c->in.events)))
+    /* get_event returns 0 on empty list. */
+    while(!(ret = get_event(c)))
         if(!_xcb_conn_wait(c, /*should_write*/ 0, &c->in.event_cond))
             break;
 
@@ -256,7 +318,7 @@ XCBGenericEvent *XCBPollForEvent(XCBConnection *c, int *error)
         *error = 0;
     /* FIXME: follow X meets Z architecture changes. */
     if(_xcb_in_read(c))
-        ret = _xcb_queue_dequeue(c->in.events);
+        ret = get_event(c);
     else if(error)
         *error = -1;
     else
@@ -290,14 +352,14 @@ int _xcb_in_init(_xcb_in *in)
     in->queue_len = 0;
 
     in->request_read = 0;
-    in->current_reply = _xcb_queue_new();
 
     in->replies = _xcb_map_new();
-    in->events = _xcb_queue_new();
     in->readers = _xcb_list_new();
-    if(!in->current_reply || !in->replies || !in->events || !in->readers)
+    if(!in->replies || !in->readers)
         return 0;
 
+    in->current_reply_tail = &in->current_reply;
+    in->events_tail = &in->events;
     in->pending_replies_tail = &in->pending_replies;
 
     return 1;
@@ -306,10 +368,16 @@ int _xcb_in_init(_xcb_in *in)
 void _xcb_in_destroy(_xcb_in *in)
 {
     pthread_cond_destroy(&in->event_cond);
-    _xcb_queue_delete(in->current_reply, free);
-    _xcb_map_delete(in->replies, free);
-    _xcb_queue_delete(in->events, free);
+    free_reply_list(in->current_reply);
+    _xcb_map_delete(in->replies, (void (*)(void *)) free_reply_list);
     _xcb_list_delete(in->readers, 0);
+    while(in->events)
+    {
+        struct event_list *e = in->events;
+        in->events = e->next;
+        free(e->event);
+        free(e);
+    }
     while(in->pending_replies)
     {
         pending_reply *pend = in->pending_replies;