Shut down the connection in all "fatal" error cases.
[free-sw/xcb/libxcb] / src / xcb_in.c
index 6433f0e..2ac1e52 100644 (file)
@@ -108,8 +108,8 @@ static int read_packet(XCBConnection *c)
             }
             c->in.request_completed = c->in.request_read - 1;
         }
-        if(genrep.response_type != XCBReply) /* error or event */
-            c->in.request_completed = c->in.request_read; /* XXX: does event/error imply no more replies? */
+        if(genrep.response_type == XCBError)
+            c->in.request_completed = c->in.request_read;
 
         while(c->in.pending_replies && 
              XCB_SEQUENCE_COMPARE (c->in.pending_replies->request, <=, c->in.request_completed))
@@ -142,7 +142,10 @@ static int read_packet(XCBConnection *c)
 
     buf = malloc(length + (genrep.response_type == XCBReply ? 0 : sizeof(CARD32)));
     if(!buf)
+    {
+        _xcb_conn_shutdown(c);
         return 0;
+    }
     if(_xcb_in_read_block(c, buf, length) <= 0)
     {
         free(buf);
@@ -164,7 +167,10 @@ static int read_packet(XCBConnection *c)
         reader_list *reader;
         struct reply_list *cur = malloc(sizeof(struct reply_list));
         if(!cur)
+        {
+            _xcb_conn_shutdown(c);
             return 0;
+        }
         cur->reply = buf;
         cur->next = 0;
         *c->in.current_reply_tail = cur;
@@ -187,6 +193,7 @@ static int read_packet(XCBConnection *c)
     event = malloc(sizeof(struct event_list));
     if(!event)
     {
+        _xcb_conn_shutdown(c);
         free(buf);
         return 0;
     }
@@ -308,6 +315,8 @@ void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **
     void *ret = 0;
     if(e)
         *e = 0;
+    if(c->has_error)
+        return 0;
 
     pthread_mutex_lock(&c->iolock);
 
@@ -356,6 +365,13 @@ void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **
 int XCBPollForReply(XCBConnection *c, unsigned int request, void **reply, XCBGenericError **error)
 {
     int ret;
+    if(c->has_error)
+    {
+        *reply = 0;
+        if(error)
+            *error = 0;
+        return 1; /* would not block */
+    }
     assert(reply != 0);
     pthread_mutex_lock(&c->iolock);
     ret = poll_for_reply(c, request, reply, error);
@@ -363,14 +379,11 @@ int XCBPollForReply(XCBConnection *c, unsigned int request, void **reply, XCBGen
     return ret;
 }
 
-XCBGenericEvent *XCBWaitEvent(XCBConnection *c)
-{
-    return XCBWaitForEvent(c);
-}
-
 XCBGenericEvent *XCBWaitForEvent(XCBConnection *c)
 {
     XCBGenericEvent *ret;
+    if(c->has_error)
+        return 0;
     pthread_mutex_lock(&c->iolock);
     /* get_event returns 0 on empty list. */
     while(!(ret = get_event(c)))
@@ -384,32 +397,50 @@ XCBGenericEvent *XCBWaitForEvent(XCBConnection *c)
 
 XCBGenericEvent *XCBPollForEvent(XCBConnection *c, int *error)
 {
-    XCBGenericEvent *ret = 0;
-    pthread_mutex_lock(&c->iolock);
+    if(!c->has_error)
+    {
+        XCBGenericEvent *ret = 0;
+        int success;
+        pthread_mutex_lock(&c->iolock);
+        /* FIXME: follow X meets Z architecture changes. */
+        success = _xcb_in_read(c);
+        if(success)
+            ret = get_event(c);
+        pthread_mutex_unlock(&c->iolock);
+        if(success)
+        {
+            if(error)
+                *error = 0;
+            return ret;
+        }
+    }
     if(error)
-        *error = 0;
-    /* FIXME: follow X meets Z architecture changes. */
-    if(_xcb_in_read(c))
-        ret = get_event(c);
-    else if(error)
         *error = -1;
     else
     {
         fprintf(stderr, "XCBPollForEvent: I/O error occured, but no handler provided.\n");
         abort();
     }
-    pthread_mutex_unlock(&c->iolock);
-    return ret;
+    return 0;
 }
 
-unsigned int XCBGetRequestRead(XCBConnection *c)
+XCBGenericError *XCBRequestCheck(XCBConnection *c, XCBVoidCookie cookie)
 {
-    unsigned int ret;
-    pthread_mutex_lock(&c->iolock);
-    /* FIXME: follow X meets Z architecture changes. */
-    _xcb_in_read(c);
-    ret = c->in.request_read;
-    pthread_mutex_unlock(&c->iolock);
+    /* FIXME: this could hold the lock to avoid syncing unnecessarily, but
+     * that would require factoring the locking out of XCBGetInputFocus,
+     * XCBGetInputFocusReply, and XCBWaitForReply. */
+    XCBGenericError *ret;
+    void *reply;
+    if(c->has_error)
+        return 0;
+    if(XCB_SEQUENCE_COMPARE(cookie.sequence,>,c->in.request_expected)
+       && XCB_SEQUENCE_COMPARE(cookie.sequence,>,c->in.request_completed))
+    {
+        free(XCBGetInputFocusReply(c, XCBGetInputFocus(c), &ret));
+        assert(!ret);
+    }
+    reply = XCBWaitForReply(c, cookie.sequence, &ret);
+    assert(!reply);
     return ret;
 }
 
@@ -462,7 +493,10 @@ int _xcb_in_expect_reply(XCBConnection *c, unsigned int request, enum workaround
     pending_reply *pend = malloc(sizeof(pending_reply));
     assert(workaround != WORKAROUND_NONE || flags != 0);
     if(!pend)
+    {
+        _xcb_conn_shutdown(c);
         return 0;
+    }
     pend->request = request;
     pend->workaround = workaround;
     pend->flags = flags;
@@ -479,7 +513,10 @@ int _xcb_in_read(XCBConnection *c)
         c->in.queue_len += n;
     while(read_packet(c))
         /* empty */;
-    return (n > 0) || (n < 0 && errno == EAGAIN);
+    if((n > 0) || (n < 0 && errno == EAGAIN))
+        return 1;
+    _xcb_conn_shutdown(c);
+    return 0;
 }
 
 int _xcb_in_read_block(XCBConnection *c, void *buf, int len)
@@ -496,7 +533,10 @@ int _xcb_in_read_block(XCBConnection *c, void *buf, int len)
     {
         int ret = read_block(c->fd, (char *) buf + done, len - done);
         if(ret <= 0)
+        {
+            _xcb_conn_shutdown(c);
             return ret;
+        }
     }
 
     return len;