[Xcb] [PATCH libxcb 2/5] send_fds(): Make sure no other thread interrupts us

Uli Schlachter psychon at znc.in
Mon May 18 12:45:34 PDT 2015


Two threads trying to send fds at the same time could interfere. To guarantee a
correct ordering, we have to use correct locking. The code in send_fds() missed
one case: If there was another thread already writing requests, we slept on the
"done with writing" condition variable (c->out.cond). This would allow other
threads to re-acquire the iolock before us and could cause fds to be sent out of
order.

To fix this, at the beginning of send_fds() we now make sure that no other
thread is already writing requests. This is what prepare_socket_request() does.
Additionally, it gets the socket back in case xcb_take_socket() was called,
which is a good thing, too, since fds are only sent with corresponding requests.
---
 src/xcb_out.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/xcb_out.c b/src/xcb_out.c
index 722463e..ec132fc 100644
--- a/src/xcb_out.c
+++ b/src/xcb_out.c
@@ -186,6 +186,15 @@ static void close_fds(int *fds, unsigned int num_fds)
 static void send_fds(xcb_connection_t *c, int *fds, unsigned int num_fds)
 {
 #if HAVE_SENDMSG
+    /* Calling _xcb_out_flush_to() can drop the iolock and wait on a condition
+     * variable if another thread is currently writing (c->out.writing > 0).
+     * This call waits for writers to be done and thus _xcb_out_flush_to() will
+     * do the work itself (in which case we are a writer and
+     * prepare_socket_request() will wait for us to be done if another threads
+     * tries to send fds, too). Thanks to this, we can atomically write out FDs.
+     */
+    prepare_socket_request(c);
+
     while (num_fds > 0) {
         /* FIXME: This will busy-loop when XCB_MAX_PASS_FD fds are sent at once */
         while (c->out.out_fd.nfd == XCB_MAX_PASS_FD && !c->has_error) {
-- 
2.1.4



More information about the Xcb mailing list