Added more error states and removed global error_connection
[free-sw/xcb/libxcb] / src / xcb_in.c
index 7d34429..969cfc0 100644 (file)
@@ -80,6 +80,17 @@ typedef struct reader_list {
     struct reader_list *next;
 } reader_list;
 
+static void remove_finished_readers(reader_list **prev_reader, uint64_t completed)
+{
+    while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, completed))
+    {
+        /* If you don't have what you're looking for now, you never
+         * will. Wake up and leave me alone. */
+        pthread_cond_signal((*prev_reader)->data);
+        *prev_reader = (*prev_reader)->next;
+    }
+}
+
 static int read_packet(xcb_connection_t *c)
 {
     xcb_generic_reply_t genrep;
@@ -130,6 +141,8 @@ static int read_packet(xcb_connection_t *c)
 
         if(genrep.response_type == XCB_ERROR)
             c->in.request_completed = c->in.request_read;
+
+        remove_finished_readers(&c->in.readers, c->in.request_completed);
     }
 
     if(genrep.response_type == XCB_ERROR || genrep.response_type == XCB_REPLY)
@@ -154,14 +167,14 @@ static int read_packet(xcb_connection_t *c)
     }
 
     /* XGE events may have sizes > 32 */
-    if (genrep.response_type == XCB_XGE_EVENT)
+    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)));
     if(!buf)
     {
-        _xcb_conn_shutdown(c);
+        _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
         return 0;
     }
 
@@ -194,11 +207,10 @@ static int read_packet(xcb_connection_t *c)
     if( genrep.response_type == XCB_REPLY ||
        (genrep.response_type == XCB_ERROR && pend && (pend->flags & XCB_REQUEST_CHECKED)))
     {
-        reader_list *reader;
         struct reply_list *cur = malloc(sizeof(struct reply_list));
         if(!cur)
         {
-            _xcb_conn_shutdown(c);
+            _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
             free(buf);
             return 0;
         }
@@ -206,17 +218,8 @@ static int read_packet(xcb_connection_t *c)
         cur->next = 0;
         *c->in.current_reply_tail = cur;
         c->in.current_reply_tail = &cur->next;
-        for(reader = c->in.readers; 
-           reader && 
-           XCB_SEQUENCE_COMPARE(reader->request, <=, c->in.request_read);
-           reader = reader->next)
-       {
-            pthread_cond_signal(reader->data);
-            if(reader->request == c->in.request_read)
-            {
-                break;
-            }
-       }
+        if(c->in.readers && c->in.readers->request == c->in.request_read)
+            pthread_cond_signal(c->in.readers->data);
         return 1;
     }
 
@@ -224,7 +227,7 @@ static int read_packet(xcb_connection_t *c)
     event = malloc(sizeof(struct event_list));
     if(!event)
     {
-        _xcb_conn_shutdown(c);
+        _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
         free(buf);
         return 0;
     }
@@ -356,6 +359,26 @@ static int poll_for_reply(xcb_connection_t *c, uint64_t request, void **reply, x
     return 1;
 }
 
+static void insert_reader(reader_list **prev_reader, reader_list *reader, uint64_t request, pthread_cond_t *cond)
+{
+    while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, request))
+        prev_reader = &(*prev_reader)->next;
+    reader->request = request;
+    reader->data = cond;
+    reader->next = *prev_reader;
+    *prev_reader = reader;
+}
+
+static void remove_reader(reader_list **prev_reader, reader_list *reader)
+{
+    while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, reader->request))
+        if(*prev_reader == reader)
+        {
+            *prev_reader = (*prev_reader)->next;
+            break;
+        }
+}
+
 static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_error_t **e)
 {
     void *ret = 0;
@@ -365,35 +388,14 @@ static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_e
     {
         pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
         reader_list reader;
-        reader_list **prev_reader;
-
-        for(prev_reader = &c->in.readers; 
-           *prev_reader && 
-           XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, request);
-           prev_reader = &(*prev_reader)->next)
-       {
-            /* empty */;
-       }
-        reader.request = request;
-        reader.data = &cond;
-        reader.next = *prev_reader;
-        *prev_reader = &reader;
+
+        insert_reader(&c->in.readers, &reader, request, &cond);
 
         while(!poll_for_reply(c, request, &ret, e))
             if(!_xcb_conn_wait(c, &cond, 0, 0))
                 break;
 
-        for(prev_reader = &c->in.readers;
-           *prev_reader && 
-           XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, request);
-           prev_reader = &(*prev_reader)->next)
-       {
-            if(*prev_reader == &reader)
-            {
-                *prev_reader = (*prev_reader)->next;
-                break;
-            }
-       }
+        remove_reader(&c->in.readers, &reader);
         pthread_cond_destroy(&cond);
     }
 
@@ -431,7 +433,7 @@ static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_nex
     pend = malloc(sizeof(*pend));
     if(!pend)
     {
-        _xcb_conn_shutdown(c);
+        _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
         return;
     }
 
@@ -525,7 +527,7 @@ xcb_generic_event_t *xcb_wait_for_event(xcb_connection_t *c)
     return ret;
 }
 
-xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c)
+static xcb_generic_event_t *poll_for_next_event(xcb_connection_t *c, int queued)
 {
     xcb_generic_event_t *ret = 0;
     if(!c->has_error)
@@ -533,13 +535,23 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c)
         pthread_mutex_lock(&c->iolock);
         /* FIXME: follow X meets Z architecture changes. */
         ret = get_event(c);
-        if(!ret && _xcb_in_read(c)) /* _xcb_in_read shuts down the connection on error */
+        if(!ret && !queued && c->in.reading == 0 && _xcb_in_read(c)) /* _xcb_in_read shuts down the connection on error */
             ret = get_event(c);
         pthread_mutex_unlock(&c->iolock);
     }
     return ret;
 }
 
+xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c)
+{
+    return poll_for_next_event(c, 0);
+}
+
+xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c)
+{
+    return poll_for_next_event(c, 1);
+}
+
 xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie)
 {
     uint64_t request;
@@ -621,7 +633,7 @@ int _xcb_in_expect_reply(xcb_connection_t *c, uint64_t request, enum workarounds
     assert(workaround != WORKAROUND_NONE || flags != 0);
     if(!pend)
     {
-        _xcb_conn_shutdown(c);
+        _xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
         return 0;
     }
     pend->first_request = pend->last_request = request;
@@ -660,7 +672,7 @@ int _xcb_in_read(xcb_connection_t *c)
     if((n > 0) || (n < 0 && WSAGetLastError() == WSAEWOULDBLOCK))
 #endif /* !_WIN32 */
         return 1;
-    _xcb_conn_shutdown(c);
+    _xcb_conn_shutdown(c, XCB_CONN_ERROR);
     return 0;
 }
 
@@ -679,7 +691,7 @@ int _xcb_in_read_block(xcb_connection_t *c, void *buf, int len)
         int ret = read_block(c->fd, (char *) buf + done, len - done);
         if(ret <= 0)
         {
-            _xcb_conn_shutdown(c);
+            _xcb_conn_shutdown(c, XCB_CONN_ERROR);
             return ret;
         }
     }