XCB provides functions xcb_{wait,poll}_for_{reply,event}, but not xcb_{wait,poll}_for_reply_or_event, which would be useful in the following scenario:
- Send a batch of requests.
- Wait for replies. While waiting, handle incoming events.
- When the replies finally come in, handle the replies.
To implement steps 2 and 3, we could poll the the underlying socket, as follows:
- Check for queued replies with
xcb_poll_for_reply. - Check for queued events with
xcb_poll_for_event. pollthe underlying socket.- When
pollindicates a read is possible, callxcb_poll_for_replyand/orxcb_poll_for_eventand process the new data.
However, this seems to have a race condition. If a reply (but not an event) arrives between steps 1 and 2, it will get queued in XCB's internal data structures in step 2. Then we will end up blocking in poll even though there is data available to process. (Of course, a similar issue occurs if steps 1 and 2 are swapped.)
So, is there any efficient way to wait/poll for replies or events without this deficiency?
CodePudding user response:
The problem can be solved by polling the underlying socket as described in the question, but with xcb_poll_for_event in step 2 replaced by xcb_poll_for_queued_event. (This might still be broken in multithreaded scenarios.)
Alternatively, we can avoid needing to poll the socket by sending an unchecked dummy request that is guaranteed to fail, as follows:
- Send a batch of requests.
- Send an unchecked dummy request that will fail (e.g., MapWindow with an invalid window argument).
- Repeatedly call
xcb_wait_for_eventand handle incoming events while waiting for replies. - Eventually,
xcb_wait_for_eventwill return an error. If the sequence number in the error matches the sequence number of the dummy request, then ignore the error and continue to the next step; all replies must have arrived. Otherwise, the error is for a genuine request and should be handled appropriately. - Read in all replies with
xcb_poll_for_replyor the appropriate generated reply functions.
The first approach is more efficient, but the second approach might lead to simpler code.
