send_fds(): Make sure no other thread interrupts us
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.
This commit is contained in:
parent
25f9e7e45a
commit
cc04cfb41b
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue