[Xcb] [PATCH 4/8] Add xcb_send_fd API

Uli Schlachter psychon at znc.in
Thu Nov 7 11:21:37 CET 2013

On 07.11.2013 10:03, Uli Schlachter wrote:
> On 07.11.2013 04:45, Keith Packard wrote:
>> +void
>> +xcb_send_fd(xcb_connection_t *c, int fd)
>> +{
>   if (c->has_error)
>     return;
> This is needed before the pthread_mutex_lock(), because if
> xcb_connect_to_display() fails, it returns a pointer to an integer. The
> has_error 'field' is the only thing that might be accessed for such a connection
> object.
>> +    pthread_mutex_lock(&c->iolock);
>> +    while (c->out.out_fd.nfd == XCB_MAX_PASS_FD) {
>> +	_xcb_out_flush_to(c, c->out.request);
>> +	if (c->has_error)
>> +	    break;
>> +    }
>> +    if (!c->has_error)
>> +	c->out.out_fd.fd[c->out.out_fd.nfd++] = fd;
>> +    pthread_mutex_unlock(&c->iolock);
>> +#endif
>> +}
> So, xcb_send_fd() hands FDs to libxcb which will all be included in the next
> flush. The idea is that the user of the library calls (through the automatically
> generated protocol functions) xcb_send_fd() and then xcb_send_request(). Correct?
> However, what happens if the connection is flushed between the xcb_send_fd() and
> the xcb_send_request() calls, because another thread "interferes"? This can also
> happen with a single thread: xcb_send_request() could have to insert sync
> requests (GetInputFocus) because of sequence number 0 or sequence number wraps.
> This could cause the output buffer to go full before the "real" request is inserted.
> I guess that the server expects the FDs to be sent with the request that they
> are meant to (otherwise I could feed the server lots of FDs which it would have
> to keep around forever). So this function doesn't really work, does it?

Having thought about this some more in the shower, I would suggest to turn
xcb_send_fd() into a private _send_fd() and instead add
xcb_send_request_with_fds() (or something like that).

This way, send_request() can call _send_fd() internally after it has sent all
the needed syncs and with the mutex held. In other words: In a way that makes
sure that nothing is flushed prematurely.

However, I also noticed that I don't know much about "unix fd magic", so could
anyone please answer some questions:

- What happens if we try to send FDs over non-unix sockets?
- Does the new sendmsg() call work correctly on non-unix sockets when no FDs are
- Should we have some API to test if sending FDs works at all or if xcb just
ignores the FDs?
- What happens with partial reads? Let's say we send 4KiB of requests to the
server in one sendmsg() call and the last request has FDs attached. For whatever
reason, the server only reads 2KiB of data from the socket. Will the FDs be
handled correctly in this case? What if the FDs are for the first request
instead of the last one?
(Of course, this last question also applies to FDs that the server sends to libxcb)

Oh and I just noticed:
If HAVE_SENDMSG is not defined, shouldn't xcb_send_fd() close() the FD that it gets?

A normal person is just someone you don't know well enough yet.
 - Nettie Wiebe

More information about the Xcb mailing list