You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
libxcb is just a wrapper around a socket with some external state, so theoretically we should be able to implement CanBeAsyncDisplay on XcbDisplay (and also XlibDisplay). In practice, it ends up being more complicated.
Here are the methods of CanBeAsyncDisplay in order of difficulty of implementation:
try_wait_for_reply_raw, try_wait_for_event - Trivial. Use xcb_poll_for_reply64 or xcb_poll_for_event, and return AsyncStatus::Read if one doesn't come up.
try_send_request_raw - Hard. libxcb on its own does not support non-blocking writes. However, it is possible to get the file descriptor of the connection, preform non-blocking writes on that, and then use xcb_writev to update the connection's sequence number. Note that this restricts async support to being Unix-only, since Windows async systems use Windows sockets.
try_flush - Hard. xcb_flush preforms a blocking flush of the internal connection buffer, and there is no other way to access that buffer from the external API. That being said, while using the async API, we probably won't involve the internal buffer too much. We could have a check saying, "if the socket has been taken since we last used it, this flush will be blocking", and then also make sure to flush our own buffer. Note that this means that we'd have to make our own buffer for writes here, which I expected to have to do anyways.
format_request - Very Hard. We need the sequence number to do formatting, which we get from xcb_take_socket (note that we need to call xcb_take_socket for writing above). First, it preforms a flush of the internal buffer which, as discussed above, can be problematic. Although that can be avoided, we do have to deal with the case where a malicious user takes the socket and passes in a callback that blocks for an extended period of time. We could probably also check to see if the socket has been taken and, if so, expect to block. That being said, we also may need to query for extensions and maximum request length, which use internal consistent state and can't be done without blocking. In these cases, this moves up to Impossible.
try_check_for_error - Very Hard. Basically the same as flushing and then reading.
try_generate_xid, try_maximum_request_length - Impossible. xcb_generate_id and xcb_maximum_request_length rely on internal state that needs to be kept consistent between breadx and libxcb. Even if we could get around this by emulating it on the breadx end, foreign code could call these functions before/after the Display in instantiated and mess up our state.
The Impossibles are generally cold operations, so we could probably eat the cost of using a threadpool and import blocking or using tokio's spawn_blocking function. The Hards require a new type at minimum to wrap XcbDisplay, and probably some kind of system for taking the XCB socket.
The text was updated successfully, but these errors were encountered:
libxcb
is just a wrapper around a socket with some external state, so theoretically we should be able to implementCanBeAsyncDisplay
onXcbDisplay
(and alsoXlibDisplay
). In practice, it ends up being more complicated.Here are the methods of
CanBeAsyncDisplay
in order of difficulty of implementation:try_wait_for_reply_raw
,try_wait_for_event
- Trivial. Usexcb_poll_for_reply64
orxcb_poll_for_event
, and returnAsyncStatus::Read
if one doesn't come up.try_send_request_raw
- Hard.libxcb
on its own does not support non-blocking writes. However, it is possible to get the file descriptor of the connection, preform non-blocking writes on that, and then usexcb_writev
to update the connection's sequence number. Note that this restrictsasync
support to being Unix-only, since Windows async systems use Windows sockets.try_flush
- Hard.xcb_flush
preforms a blocking flush of the internal connection buffer, and there is no other way to access that buffer from the external API. That being said, while using the async API, we probably won't involve the internal buffer too much. We could have a check saying, "if the socket has been taken since we last used it, this flush will be blocking", and then also make sure to flush our own buffer. Note that this means that we'd have to make our own buffer for writes here, which I expected to have to do anyways.format_request
- Very Hard. We need the sequence number to do formatting, which we get fromxcb_take_socket
(note that we need to callxcb_take_socket
for writing above). First, it preforms a flush of the internal buffer which, as discussed above, can be problematic. Although that can be avoided, we do have to deal with the case where a malicious user takes the socket and passes in a callback that blocks for an extended period of time. We could probably also check to see if the socket has been taken and, if so, expect to block. That being said, we also may need to query for extensions and maximum request length, which use internal consistent state and can't be done without blocking. In these cases, this moves up to Impossible.try_check_for_error
- Very Hard. Basically the same as flushing and then reading.try_generate_xid
,try_maximum_request_length
- Impossible.xcb_generate_id
andxcb_maximum_request_length
rely on internal state that needs to be kept consistent betweenbreadx
andlibxcb
. Even if we could get around this by emulating it on thebreadx
end, foreign code could call these functions before/after theDisplay
in instantiated and mess up our state.The Impossibles are generally cold operations, so we could probably eat the cost of using a threadpool and import blocking or using tokio's spawn_blocking function. The Hards require a new type at minimum to wrap
XcbDisplay
, and probably some kind of system for taking the XCB socket.The text was updated successfully, but these errors were encountered: