Track 64-bit sequence numbers internally.
[free-sw/xcb/libxcb] / src / xcb_out.c
index f12a071..1094ceb 100644 (file)
@@ -33,9 +33,9 @@
 #include "xcb.h"
 #include "xcbext.h"
 #include "xcbint.h"
-#include "extensions/bigreq.h"
+#include "bigreq.h"
 
-static int write_block(XCBConnection *c, struct iovec *vector, int count)
+static int write_block(xcb_connection_t *c, struct iovec *vector, int count)
 {
     while(count && c->out.queue_len + vector[0].iov_len <= sizeof(c->out.queue))
     {
@@ -57,40 +57,69 @@ static int write_block(XCBConnection *c, struct iovec *vector, int count)
 
 /* Public interface */
 
-CARD32 XCBGetMaximumRequestLength(XCBConnection *c)
+void xcb_prefetch_maximum_request_length(xcb_connection_t *c)
 {
+    if(c->has_error)
+        return;
     pthread_mutex_lock(&c->out.reqlenlock);
-    if(!c->out.maximum_request_length)
+    if(c->out.maximum_request_length_tag == LAZY_NONE)
     {
-        const XCBQueryExtensionRep *ext;
-        c->out.maximum_request_length = c->setup->maximum_request_length;
-        ext = XCBGetExtensionData(c, &XCBBigRequestsId);
+        const xcb_query_extension_reply_t *ext;
+        ext = xcb_get_extension_data(c, &xcb_big_requests_id);
         if(ext && ext->present)
         {
-            XCBBigRequestsEnableRep *r = XCBBigRequestsEnableReply(c, XCBBigRequestsEnable(c), 0);
-            c->out.maximum_request_length = r->maximum_request_length;
+            c->out.maximum_request_length_tag = LAZY_COOKIE;
+            c->out.maximum_request_length.cookie = xcb_big_requests_enable(c);
+        }
+        else
+        {
+            c->out.maximum_request_length_tag = LAZY_FORCED;
+            c->out.maximum_request_length.value = c->setup->maximum_request_length;
+        }
+    }
+    pthread_mutex_unlock(&c->out.reqlenlock);
+}
+
+uint32_t xcb_get_maximum_request_length(xcb_connection_t *c)
+{
+    if(c->has_error)
+        return 0;
+    xcb_prefetch_maximum_request_length(c);
+    pthread_mutex_lock(&c->out.reqlenlock);
+    if(c->out.maximum_request_length_tag == LAZY_COOKIE)
+    {
+        xcb_big_requests_enable_reply_t *r = xcb_big_requests_enable_reply(c, c->out.maximum_request_length.cookie, 0);
+        c->out.maximum_request_length_tag = LAZY_FORCED;
+        if(r)
+        {
+            c->out.maximum_request_length.value = r->maximum_request_length;
             free(r);
         }
+        else
+            c->out.maximum_request_length.value = c->setup->maximum_request_length;
     }
     pthread_mutex_unlock(&c->out.reqlenlock);
-    return c->out.maximum_request_length;
+    return c->out.maximum_request_length.value;
 }
 
-unsigned int XCBSendRequest(XCBConnection *c, int flags, struct iovec *vector, const XCBProtocolRequest *req)
+unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req)
 {
     static const union {
         struct {
-            CARD8 major;
-            CARD8 pad;
-            CARD16 len;
+            uint8_t major;
+            uint8_t pad;
+            uint16_t len;
         } fields;
-        CARD32 packet;
-    } sync = { { /* GetInputFocus */ 43, 0, 1 } };
-    unsigned int request;
-    CARD32 prefix[3] = { 0 };
+        uint32_t packet;
+    } sync_req = { { /* GetInputFocus */ 43, 0, 1 } };
+    uint64_t request;
+    uint32_t prefix[3] = { 0 };
     int veclen = req->count;
     enum workarounds workaround = WORKAROUND_NONE;
 
+    if(c->has_error)
+        return 0;
+
     assert(c != 0);
     assert(vector != 0);
     assert(req->count > 0);
@@ -98,21 +127,24 @@ unsigned int XCBSendRequest(XCBConnection *c, int flags, struct iovec *vector, c
     if(!(flags & XCB_REQUEST_RAW))
     {
         static const char pad[3];
-        int i;
-        CARD16 shortlen = 0;
+        unsigned int i;
+        uint16_t shortlen = 0;
         size_t longlen = 0;
         assert(vector[0].iov_len >= 4);
         /* set the major opcode, and the minor opcode for extensions */
         if(req->ext)
         {
-            const XCBQueryExtensionRep *extension = XCBGetExtensionData(c, req->ext);
+            const xcb_query_extension_reply_t *extension = xcb_get_extension_data(c, req->ext);
             if(!(extension && extension->present))
+            {
+                _xcb_conn_shutdown(c);
                 return 0;
-            ((CARD8 *) vector[0].iov_base)[0] = extension->major_opcode;
-            ((CARD8 *) vector[0].iov_base)[1] = req->opcode;
+            }
+            ((uint8_t *) vector[0].iov_base)[0] = extension->major_opcode;
+            ((uint8_t *) vector[0].iov_base)[1] = req->opcode;
         }
         else
-            ((CARD8 *) vector[0].iov_base)[0] = req->opcode;
+            ((uint8_t *) vector[0].iov_base)[0] = req->opcode;
 
         /* put together the length field, possibly using BIGREQUESTS */
         for(i = 0; i < req->count; ++i)
@@ -133,11 +165,14 @@ unsigned int XCBSendRequest(XCBConnection *c, int flags, struct iovec *vector, c
             shortlen = longlen;
             longlen = 0;
         }
-        else if(longlen > XCBGetMaximumRequestLength(c))
+        else if(longlen > xcb_get_maximum_request_length(c))
+        {
+            _xcb_conn_shutdown(c);
             return 0; /* server can't take this; maybe need BIGREQUESTS? */
+        }
 
         /* set the length field. */
-        ((CARD16 *) vector[0].iov_base)[1] = shortlen;
+        ((uint16_t *) vector[0].iov_base)[1] = shortlen;
         if(!shortlen)
             prefix[2] = ++longlen;
     }
@@ -147,7 +182,7 @@ unsigned int XCBSendRequest(XCBConnection *c, int flags, struct iovec *vector, c
     /* XXX: GetFBConfigs won't use BIG-REQUESTS in any sane
      * configuration, but that should be handled here anyway. */
     if(req->ext && !req->isvoid && !strcmp(req->ext->name, "GLX") &&
-            ((req->opcode == 17 && ((CARD32 *) vector[0].iov_base)[1] == 0x10004) ||
+            ((req->opcode == 17 && ((uint32_t *) vector[0].iov_base)[1] == 0x10004) ||
              req->opcode == 21))
         workaround = WORKAROUND_GLX_GET_FB_CONFIGS_BUG;
 
@@ -157,16 +192,22 @@ unsigned int XCBSendRequest(XCBConnection *c, int flags, struct iovec *vector, c
     while(c->out.writing)
         pthread_cond_wait(&c->out.cond, &c->iolock);
 
-    if(req->isvoid && c->out.request == c->in.request_expected + (1 << 16) - 2)
+    request = ++c->out.request;
+    /* send GetInputFocus (sync_req) when 64k-2 requests have been sent without
+     * a reply.
+     * Also send sync_req (could use NoOp) at 32-bit wrap to avoid having
+     * applications see sequence 0 as that is used to indicate
+     * an error in sending the request */
+    while((req->isvoid &&
+       c->out.request == c->in.request_expected + (1 << 16) - 1) ||
+       request == 0)
     {
-        prefix[0] = sync.packet;
-        request = ++c->out.request;
+        prefix[0] = sync_req.packet;
         _xcb_in_expect_reply(c, request, WORKAROUND_NONE, XCB_REQUEST_DISCARD_REPLY);
         c->in.request_expected = c->out.request;
+       request = ++c->out.request;
     }
 
-    request = ++c->out.request;
-    assert(request != 0);
     if(workaround != WORKAROUND_NONE || flags != 0)
         _xcb_in_expect_reply(c, request, workaround, flags);
     if(!req->isvoid)
@@ -177,23 +218,28 @@ unsigned int XCBSendRequest(XCBConnection *c, int flags, struct iovec *vector, c
         --vector, ++veclen;
         if(prefix[2])
         {
-            prefix[1] = ((CARD32 *) vector[1].iov_base)[0];
-            vector[1].iov_base = (CARD32 *) vector[1].iov_base + 1;
-            vector[1].iov_len -= sizeof(CARD32);
+            prefix[1] = ((uint32_t *) vector[1].iov_base)[0];
+            vector[1].iov_base = (uint32_t *) vector[1].iov_base + 1;
+            vector[1].iov_len -= sizeof(uint32_t);
         }
-        vector[0].iov_len = sizeof(CARD32) * (prefix[0] ? 1 : 0 | prefix[2] ? 2 : 0);
+        vector[0].iov_len = sizeof(uint32_t) * (prefix[0] ? 1 : 0 | prefix[2] ? 2 : 0);
         vector[0].iov_base = prefix + !prefix[0];
     }
 
     if(!write_block(c, vector, veclen))
+    {
+        _xcb_conn_shutdown(c);
         request = 0;
+    }
     pthread_mutex_unlock(&c->iolock);
     return request;
 }
 
-int XCBFlush(XCBConnection *c)
+int xcb_flush(xcb_connection_t *c)
 {
     int ret;
+    if(c->has_error)
+        return 0;
     pthread_mutex_lock(&c->iolock);
     ret = _xcb_out_flush_to(c, c->out.request);
     pthread_mutex_unlock(&c->iolock);
@@ -215,7 +261,7 @@ int _xcb_out_init(_xcb_out *out)
 
     if(pthread_mutex_init(&out->reqlenlock, 0))
         return 0;
-    out->maximum_request_length = 0;
+    out->maximum_request_length_tag = LAZY_NONE;
 
     return 1;
 }
@@ -226,7 +272,7 @@ void _xcb_out_destroy(_xcb_out *out)
     pthread_mutex_destroy(&out->reqlenlock);
 }
 
-int _xcb_out_send(XCBConnection *c, struct iovec **vector, int *count)
+int _xcb_out_send(xcb_connection_t *c, struct iovec **vector, int *count)
 {
     int ret = 1;
     while(ret && *count)
@@ -236,10 +282,10 @@ int _xcb_out_send(XCBConnection *c, struct iovec **vector, int *count)
     return ret;
 }
 
-int _xcb_out_flush_to(XCBConnection *c, unsigned int request)
+int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request)
 {
-    assert(request <= c->out.request);
-    if(c->out.request_written >= request)
+    assert(XCB_SEQUENCE_COMPARE(request, <=, c->out.request));
+    if(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request))
         return 1;
     if(c->out.queue_len)
     {
@@ -252,6 +298,6 @@ int _xcb_out_flush_to(XCBConnection *c, unsigned int request)
     }
     while(c->out.writing)
         pthread_cond_wait(&c->out.cond, &c->iolock);
-    assert(c->out.request_written >= request);
+    assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request));
     return 1;
 }