[Xcb] Questions about the X protocol and the XCB implementation

Uli Schlachter psychon at znc.in
Wed Jan 29 13:43:02 PST 2014


On 29.01.2014 22:18, Jochen Keil wrote:
> On 29.01.2014 06:19, Bart Massey wrote:
>> You could try to get XCB to writev() your C++ data structure for you
>> to avoid the copy, but it would be a non-trivial amount of work. It
>> would probably involve using the binding generator to build a special
>> C++ XCB binding that took various C++ data structures into account.
>> Doable, perhaps, but probably not worth the immense effort. --Bart
> Thanks for your answer. The main problem is, that I cannot easily reuse
> the {xcb_,}send_* functions, because each calls another subsequently.

Uhm, another what?

> From what I understand it looks like this: xcb_send_request sets the
> length of the request in vector[1], send_request then copies everything
> into the connection queue.

That's the main thing that xcb_send_request() does to the request itself.
However, it also handles some thread synchronisation things and gets the
request's sequence number.

> Here's what I don't understand. Why is there are queue at all? Why is
> the request not sent directly?

Performance. Sending things in short bursts is just inefficient. This is e.g.
why the TCP Nagle algorithm exists.

> Also, from looking at send_request() I
> get the impression that the request does not get sent immediately when
> the request can be enqueued completely (from "if(!count) return;" where
> count is the number of iovecs). Does this mean that the request is in
> the queue and gets only sent after a sync or when another request fills
> up the queue?

Yes. However, xcb_flush() and xcb_wait_for_reply() (if the request that is being
waited for wasn't sent yet) also can cause the queue to be sent.

> Basically, here's what I think I could do. First, create a request
> without the payload (because it's in a container). Then copy it into the
> queue. After that, copy the payload directly into the queue and
> (possibly) trigger the actual send.

That doesn't sound thread safe, but I'll just assume that this is not an issue
for you.

> That would at least save me the transformation of the container to an
> array and I think it could be easier to implement (However, I still
> would have to duplicate some code which is something I'm not too happy
> about).

I am not sure what you mean exactly. The (only) public function that you might
want to use would be xcb_send_request() (unless you want to go through the
uglyness of xcb_take_socket() and xcb_writev() which you might actually want to
do...). For xcb_send_request(), you'd have to set up an array of iovecs anyway.
If each of those is quite small and only contains some bytes, the result would
again be inefficient and just copying things into a block would be faster.

I guess that only xcb_put_image() actually makes sense for something like this.
At least I can't think right now of a (common) request that could need to send
lots of data.


>> On Tue, Jan 28, 2014 at 3:04 PM, Jochen Keil <jochen.keil at gmail.com> wrote:
>>> Hello,
>>> currently I'm trying to understand the X protocol and the XCB
>>> implementation better. My first question about the X protocol would be
>>> if there is something like a picture or so which describes the
>>> (byte-wise) layout of a request/event/etc. packet.
>>> Maybe similar to what exists for the TCP/IP packets. Or is this
>>> a misconception of mine?
>>> Secondly I've looked a bit at the XCB implementation, starting from
>>> a generated request (xcb_change_property) to the stubs. If I understood
>>> it correctly, the request function calls xcb_send_request ->
>>> send_request -> _xcb_out_send -> _xcb_conn_wait -> write_vec.
>>> write_vec finally send()s the data over the socket.
>>> Now, if I have a (high-level) container like a C++ map, I would have to
>>> transform (copy) the values to an array first, which then gets copied
>>> again by memcpy in send_request().
>>> I figured, that it would be good if the values from the container could
>>> be written directly to the socket. E.g.:
>>> for (k, v in map) { send(c-fd, &v, sizeof(v)); }
>>> Now I'd like to know if this makes sense at all and if I could implement
>>> this easily by (re-)using the existing implementation.
>>> My biggest problem is to understand what xcb_send_request does. Could
>>> I just send a request "head" (e.g. for change_property: mode, window,
>>> property,
>>> type, format) followed by the data in separate send() calls?
>>> I hope I expressed my ideas clearly enough. Please ask, if I should go
>>> more into detail about something. I also appreciate any critique!
>>> Thank you,
>>> Jochen
>>> _______________________________________________
>>> Xcb mailing list
>>> Xcb at lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/xcb
> _______________________________________________
> Xcb mailing list
> Xcb at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/xcb

"For saving the Earth.. and eating cheesecake!"

More information about the Xcb mailing list