[Xcb] [PATCH RFC 2/2] Add a pipe for waking up from _xcb_conn_wait()

Uli Schlachter psychon at znc.in
Thu Apr 10 07:25:37 PDT 2014


This commit adds a pipe to every xcb_connection_t. The read end of this pipe
gets included in the poll() or select() call in _xcb_conn_wait() so that we can
now wake up threads that are waiting for data from the X server. When the pipe
becomes readable, _xcb_conn_wait() signals an error to its caller.

The write end of the pipe gets written to in _xcb_conn_shutdown(). So when the
connection enters an error state, all threads will get out of libxcb code soon
and won't be able to get back in.

This gets rid of threads that are stuck in xcb_wait_for_event().

TODO: I bet that this doesn't compile for _WIN32.

Also-not-signed-off-by (I'm not even sure if this is worth fixing)
---
 src/xcb_conn.c | 45 ++++++++++++++++++++++++++++++++++++---------
 src/xcbint.h   |  1 +
 2 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/src/xcb_conn.c b/src/xcb_conn.c
index fa50985..283f6ed 100644
--- a/src/xcb_conn.c
+++ b/src/xcb_conn.c
@@ -311,6 +311,7 @@ int xcb_connection_has_error(xcb_connection_t *c)
 xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info)
 {
     xcb_connection_t* c;
+    int pipes[2] = { -1 , -1 };
 
 #ifndef _WIN32
 #ifndef USE_POLL
@@ -322,13 +323,22 @@ xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info)
 #endif
 #endif /* !_WIN32*/
 
+    if (pipe(pipes) != 0) {
+        close(fd);
+        return _xcb_conn_ret_error(XCB_CONN_ERROR);
+    }
+
     c = calloc(1, sizeof(xcb_connection_t));
     if(!c) {
         close(fd);
+        close(pipes[0]);
+        close(pipes[1]);
         return _xcb_conn_ret_error(XCB_CONN_CLOSED_MEM_INSUFFICIENT) ;
     }
 
     c->fd = fd;
+    c->pipe_read = pipes[0];
+    c->pipe_write = pipes[1];
 
     if(!(
         set_fd_flags(fd) &&
@@ -358,6 +368,8 @@ void xcb_disconnect(xcb_connection_t *c)
     /* disallow further sends and receives */
     shutdown(c->fd, SHUT_RDWR);
     close(c->fd);
+    close(c->pipe_write);
+    close(c->pipe_read);
 
     pthread_mutex_destroy(&c->iolock);
     _xcb_in_destroy(&c->in);
@@ -377,7 +389,12 @@ void xcb_disconnect(xcb_connection_t *c)
 
 void _xcb_conn_shutdown(xcb_connection_t *c, int err)
 {
+    char buf[1] = { 0 };
+
     c->has_error = err;
+
+    /* Make threads wake up from poll() */
+    write(c->pipe_write, buf, sizeof(buf));
 }
 
 /* Return connection error state.
@@ -416,7 +433,7 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
 {
     int ret;
 #if USE_POLL
-    struct pollfd fd;
+    struct pollfd fds[2];
 #else
     fd_set rfds, wfds;
 #endif
@@ -429,19 +446,22 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
     }
 
 #if USE_POLL
-    memset(&fd, 0, sizeof(fd));
-    fd.fd = c->fd;
-    fd.events = POLLIN;
+    memset(&fds[0], 0, sizeof(fds));
+    fds[0].fd = c->fd;
+    fds[0].events = POLLIN;
+    fds[1].fd = c->pipe_read;
+    fds[1].events = POLLIN;
 #else
     FD_ZERO(&rfds);
     FD_SET(c->fd, &rfds);
+    FD_SET(c->pipe_read, &rfds);
 #endif
     ++c->in.reading;
 
 #if USE_POLL
     if(count)
     {
-        fd.events |= POLLOUT;
+        fds[0].events |= POLLOUT;
         ++c->out.writing;
     }
 #else
@@ -456,10 +476,10 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
     pthread_mutex_unlock(&c->iolock);
     do {
 #if USE_POLL
-        ret = poll(&fd, 1, -1);
+        ret = poll(&fds[0], 2, -1);
         /* If poll() returns an event we didn't expect, such as POLLNVAL, treat
          * it as if it failed. */
-        if(ret >= 0 && (fd.revents & ~fd.events))
+        if(ret >= 0 && (fds[0].revents & ~fds[0].events))
         {
             ret = -1;
             break;
@@ -488,18 +508,25 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
          */
         int may_read = c->in.reading == 1 || !count;
 #if USE_POLL
-        if(may_read && (fd.revents & POLLIN) != 0)
+        if(may_read && (fds[0].revents & POLLIN) != 0)
 #else
         if(may_read && FD_ISSET(c->fd, &rfds))
 #endif
             ret = ret && _xcb_in_read(c);
 
 #if USE_POLL
-        if((fd.revents & POLLOUT) != 0)
+        if((fds[0].revents & POLLOUT) != 0)
 #else
         if(FD_ISSET(c->fd, &wfds))
 #endif
             ret = ret && write_vec(c, vector, count);
+
+#if USE_POLL
+        if((fds[1].revents & POLLIN) != 0)
+#else
+        if(FD_ISSET(c->pipe_read, &ffds))
+#endif
+           ret = 0;
     }
 
     if(count)
diff --git a/src/xcbint.h b/src/xcbint.h
index f89deba..aeadba2 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -198,6 +198,7 @@ struct xcb_connection_t {
     /* constant data */
     xcb_setup_t *setup;
     int fd;
+    int pipe_read, pipe_write;
 
     /* I/O data */
     pthread_mutex_t iolock;
-- 
1.9.1



More information about the Xcb mailing list