[Xcb] [PATCH 1/4] Disable cancellation around every (potential) cancellation point...

Rémi Denis-Courmont remi at remlab.net
Thu Jan 7 09:25:12 PST 2010


...and functions in external libraries (just in case).
This should make XCB safe w.r.t. to synchronous cancellation.
However, with no cancellation points, this is not terribly useful.
---
 src/xcb_auth.c |   26 +++++++++++++++++++++-----
 src/xcb_conn.c |   37 ++++++++++++++++++++++++++++---------
 src/xcb_in.c   |   14 ++++++++++++--
 src/xcb_out.c  |   18 ++++++++++++++++++
 src/xcb_util.c |   24 ++++++++++++++++++++++++
 5 files changed, 103 insertions(+), 16 deletions(-)

diff --git a/src/xcb_auth.c b/src/xcb_auth.c
index 104f2f0..f98dee1 100644
--- a/src/xcb_auth.c
+++ b/src/xcb_auth.c
@@ -92,12 +92,14 @@ static int authname_match(enum auth_protos kind, char *name, size_t namelen)
 static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen,
                           int display)
 {
+    Xauth *xauth;
     char *addr = 0;
     int addrlen = 0;
     unsigned short family;
     char hostnamebuf[256];   /* big enough for max hostname */
     char dispbuf[40];   /* big enough to hold more than 2^64 base 10 */
     int dispbuflen;
+    int canc;
 
     family = FamilyLocal; /* 256 */
     switch(sockname->sa_family)
@@ -134,17 +136,22 @@ static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen,
     /* snprintf may have truncate our text */
     dispbuflen = MIN(dispbuflen, sizeof(dispbuf) - 1);
 
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
     if (family == FamilyLocal) {
-        if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1)
+        if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1) {
+            pthread_setcancelstate(canc, NULL);
             return 0;   /* do not know own hostname */
+        }
         addr = hostnamebuf;
         addrlen = strlen(addr);
     }
 
-    return XauGetBestAuthByAddr (family,
-                                 (unsigned short) addrlen, addr,
-                                 (unsigned short) dispbuflen, dispbuf,
-                                 N_AUTH_PROTOS, authnames, authnameslen);
+    xauth = XauGetBestAuthByAddr (family,
+                                  (unsigned short) addrlen, addr,
+                                  (unsigned short) dispbuflen, dispbuf,
+                                  N_AUTH_PROTOS, authnames, authnameslen);
+    pthread_setcancelstate(canc, NULL);
+    return xauth;
 }
 
 #ifdef HASXDMAUTH
@@ -167,6 +174,8 @@ static void do_append(char *buf, int *idxp, void *val, size_t valsize) {
      
 static int compute_auth(xcb_auth_info_t *info, Xauth *authptr, struct sockaddr *sockname)
 {
+    int canc;
+
     if (authname_match(AUTH_MC1, authptr->name, authptr->name_length)) {
         info->datalen = memdup(&info->data, authptr->data, authptr->data_length);
         if(!info->datalen)
@@ -234,7 +243,9 @@ static int compute_auth(xcb_auth_info_t *info, Xauth *authptr, struct sockaddr *
 	while (j < 192 / 8)
 	    info->data[j++] = 0;
 	info->datalen = j;
+	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
 	XdmcpWrap ((unsigned char *) info->data, (unsigned char *) authptr->data + 8, (unsigned char *) info->data, info->datalen);
+	pthread_setcancelstate(canc, NULL);
 	return 1;
     }
 #undef APPEND
@@ -253,6 +264,7 @@ int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display)
     int gotsockname = 0;
     Xauth *authptr = 0;
     int ret = 1;
+    int canc;
 
     /* Some systems like hpux or Hurd do not expose peer names
      * for UNIX Domain Sockets, but this is irrelevant,
@@ -288,12 +300,16 @@ int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display)
         goto no_auth;   /* cannot build auth record */
     }
 
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
     XauDisposeAuth(authptr);
+    pthread_setcancelstate(canc, NULL);
     return ret;
 
  no_auth:
     info->name = 0;
     info->namelen = 0;
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
     XauDisposeAuth(authptr);
+    pthread_setcancelstate(canc, NULL);
     return 0;
 }
diff --git a/src/xcb_conn.c b/src/xcb_conn.c
index ed2153d..23b2eb1 100644
--- a/src/xcb_conn.c
+++ b/src/xcb_conn.c
@@ -52,15 +52,18 @@ static const int error_connection = 1;
 
 static int set_fd_flags(const int fd)
 {
-    int flags = fcntl(fd, F_GETFL, 0);
-    if(flags == -1)
-        return 0;
-    flags |= O_NONBLOCK;
-    if(fcntl(fd, F_SETFL, flags) == -1)
-        return 0;
-    if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
-        return 0;
-    return 1;
+    int flags;
+    int cancel;
+    int ret = 0;
+
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
+    flags = fcntl(fd, F_GETFL, 0);
+    if(flags != -1 &&
+       fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1 &&
+       fcntl(fd, F_SETFD, FD_CLOEXEC) != -1)
+        ret = 1;
+    pthread_setcancelstate(cancel, NULL);
+    return ret;
 }
 
 static int write_setup(xcb_connection_t *c, xcb_auth_info_t *auth_info)
@@ -136,14 +139,20 @@ static int read_setup(xcb_connection_t *c)
     case 0: /* failed */
         {
             xcb_setup_failed_t *setup = (xcb_setup_failed_t *) c->setup;
+            int cancel;
+            pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
             write(STDERR_FILENO, xcb_setup_failed_reason(setup), xcb_setup_failed_reason_length(setup));
+            pthread_setcancelstate(cancel, NULL);
             return 0;
         }
 
     case 2: /* authenticate */
         {
             xcb_setup_authenticate_t *setup = (xcb_setup_authenticate_t *) c->setup;
+            int cancel;
+            pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
             write(STDERR_FILENO, xcb_setup_authenticate_reason(setup), xcb_setup_authenticate_reason_length(setup));
+            pthread_setcancelstate(cancel, NULL);
             return 0;
         }
     }
@@ -155,8 +164,11 @@ static int read_setup(xcb_connection_t *c)
 static int write_vec(xcb_connection_t *c, struct iovec **vector, int *count)
 {
     int n;
+    int cancel;
     assert(!c->out.queue_len);
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
     n = writev(c->fd, *vector, *count);
+    pthread_setcancelstate(cancel, NULL);
     if(n < 0 && errno == EAGAIN)
         return 1;
     if(n <= 0)
@@ -238,11 +250,15 @@ xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info)
 
 void xcb_disconnect(xcb_connection_t *c)
 {
+    int cancel;
+
     if(c->has_error)
         return;
 
     free(c->setup);
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
     close(c->fd);
+    pthread_setcancelstate(cancel, NULL);
 
     pthread_mutex_destroy(&c->iolock);
     _xcb_in_destroy(&c->in);
@@ -264,6 +280,7 @@ void _xcb_conn_shutdown(xcb_connection_t *c)
 int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count)
 {
     int ret;
+    int cancel;
 #if USE_POLL
     struct pollfd fd;
 #else
@@ -303,6 +320,7 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
 #endif
 
     pthread_mutex_unlock(&c->iolock);
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
     do {
 #if USE_POLL
     ret = poll(&fd, 1, -1);
@@ -310,6 +328,7 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
 	ret = select(c->fd + 1, &rfds, &wfds, 0, 0);
 #endif
     } while (ret == -1 && errno == EINTR);
+    pthread_setcancelstate(cancel, NULL);
     if (ret < 0)
     {
         _xcb_conn_shutdown(c);
diff --git a/src/xcb_in.c b/src/xcb_in.c
index 26ab358..afb7cad 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -267,7 +267,11 @@ static int read_block(const int fd, void *buf, const ssize_t len)
     int done = 0;
     while(done < len)
     {
-        int ret = read(fd, ((char *) buf) + done, len - done);
+        int ret;
+        int cancel;
+
+        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
+        ret = read(fd, ((char *) buf) + done, len - done);
         if(ret > 0)
             done += ret;
         if(ret < 0 && errno == EAGAIN)
@@ -289,6 +293,7 @@ static int read_block(const int fd, void *buf, const ssize_t len)
 	    } while (ret == -1 && errno == EINTR);
 #endif
         }
+        pthread_setcancelstate(cancel, NULL);
         if(ret <= 0)
             return ret;
     }
@@ -555,7 +560,12 @@ void _xcb_in_replies_done(xcb_connection_t *c)
 
 int _xcb_in_read(xcb_connection_t *c)
 {
-    int n = read(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len);
+    int n;
+    int cancel;
+
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
+    n = read(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len);
+    pthread_setcancelstate(cancel, NULL);
     if(n > 0)
         c->in.queue_len += n;
     while(read_packet(c))
diff --git a/src/xcb_out.c b/src/xcb_out.c
index b3050fe..c5137a7 100644
--- a/src/xcb_out.c
+++ b/src/xcb_out.c
@@ -58,7 +58,13 @@ static int write_block(xcb_connection_t *c, struct iovec *vector, int count)
 static void get_socket_back(xcb_connection_t *c)
 {
     while(c->out.return_socket && c->out.socket_moving)
+    {
+        int cancel;
+
+        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
         pthread_cond_wait(&c->out.socket_cond, &c->iolock);
+        pthread_setcancelstate(cancel, NULL);
+    }
     if(!c->out.return_socket)
         return;
 
@@ -209,7 +215,13 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
     pthread_mutex_lock(&c->iolock);
     /* wait for other writing threads to get out of my way. */
     while(c->out.writing)
+    {
+        int cancel;
+
+        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
         pthread_cond_wait(&c->out.cond, &c->iolock);
+        pthread_setcancelstate(cancel, NULL);
+    }
     get_socket_back(c);
 
     request = ++c->out.request;
@@ -356,7 +368,13 @@ int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request)
         return _xcb_out_send(c, &vec_ptr, &count);
     }
     while(c->out.writing)
+    {
+        int cancel;
+
+        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
         pthread_cond_wait(&c->out.cond, &c->iolock);
+        pthread_setcancelstate(cancel, NULL);
+    }
     assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request));
     return 1;
 }
diff --git a/src/xcb_util.c b/src/xcb_util.c
index c3cbfa6..325681a 100644
--- a/src/xcb_util.c
+++ b/src/xcb_util.c
@@ -184,6 +184,7 @@ static int _xcb_open_decnet(const char *host, const char *protocol, const unsign
     struct sockaddr_dn addr;
     struct accessdata_dn accessdata;
     struct nodeent *nodeaddr = getnodebyname(host);
+    int cancel;
 
     if(!nodeaddr)
         return -1;
@@ -209,10 +210,13 @@ static int _xcb_open_decnet(const char *host, const char *protocol, const unsign
         return -1;
     setsockopt(fd, DNPROTO_NSP, SO_CONACCESS, &accessdata, sizeof(accessdata));
 
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
     if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
         close(fd);
+        pthread_setcancelstate(cancel, NULL);
         return -1;
     }
+    pthread_setcancelstate(cancel, NULL);
     return fd;
 }
 #endif
@@ -224,6 +228,7 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
     char service[6]; /* "65535" with the trailing '\0' */
     struct addrinfo *results, *addr;
     char *bracket;
+    int cancel;
 
     if (protocol && strcmp("tcp",protocol))
         return -1;
@@ -250,9 +255,15 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
 #endif
 
     snprintf(service, sizeof(service), "%hu", port);
+
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
     if(getaddrinfo(host, service, &hints, &results))
+    {
+        pthread_setcancelstate(cancel, NULL);
         /* FIXME: use gai_strerror, and fill in error connection */
         return -1;
+    }
+    pthread_setcancelstate(cancel, NULL);
 
     for(addr = results; addr; addr = addr->ai_next)
     {
@@ -262,9 +273,14 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
             setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
 	    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
 
+            pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
             if (connect(fd, addr->ai_addr, addr->ai_addrlen) >= 0)
+            {
+                pthread_setcancelstate(cancel, NULL);
                 break;
+            }
             close(fd);
+            pthread_setcancelstate(cancel, NULL);
             fd = -1;
         }
     }
@@ -275,6 +291,7 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
 static int _xcb_open_unix(char *protocol, const char *file)
 {
     int fd;
+    int cancel;
     struct sockaddr_un addr;
 
     if (protocol && strcmp("unix",protocol))
@@ -288,10 +305,13 @@ static int _xcb_open_unix(char *protocol, const char *file)
     fd = socket(AF_UNIX, SOCK_STREAM, 0);
     if(fd == -1)
         return -1;
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
     if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
         close(fd);
+        pthread_setcancelstate(cancel, NULL);
         return -1;
     }
+    pthread_setcancelstate(cancel, NULL);
     return fd;
 }
 
@@ -299,6 +319,7 @@ static int _xcb_open_unix(char *protocol, const char *file)
 static int _xcb_open_abstract(char *protocol, const char *file, size_t filelen)
 {
     int fd;
+    int cancel;
     struct sockaddr_un addr = {0};
     socklen_t namelen;
 
@@ -314,10 +335,13 @@ static int _xcb_open_abstract(char *protocol, const char *file, size_t filelen)
     fd = socket(AF_UNIX, SOCK_STREAM, 0);
     if (fd == -1)
         return -1;
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
     if (connect(fd, (struct sockaddr *) &addr, namelen) == -1) {
         close(fd);
+        pthread_setcancelstate(cancel, NULL);
         return -1;
     }
+    pthread_setcancelstate(cancel, NULL);
     return fd;
 }
 #endif
-- 
1.6.6



More information about the Xcb mailing list