[Xcb] [RFC v-1] API with 64bit seq. and more love for requests
Bart Massey
bart at cs.pdx.edu
Mon Feb 25 23:37:05 PST 2013
As far as "event-driven programming" goes, the
never-seriously-implemented plan was always to have a separate layer
above XCB, perhaps in a separate thread, that was an event queue and
dispatch mechanism. I've got nothing against event queues (OK, maybe,
but let's pretend); I just don't think they should be buried in a
library that's supposed to be a low-level protocol binding. This is
where Xlib started off the rails 20 years ago IMHO: first you dump an
event queue in there, then a bunch of key processing, then a color
management system, and the next thing you know... :-) --Bart
On Mon, Feb 25, 2013 at 11:53 AM, Daniel Martin <consume.noise at gmail.com> wrote:
> ---
> Here's my proposal to
> - fix the full_sequence problem with GE events,
> - make the full 64bit sequence available and
> - allow libxcb to be used in a more event driven style.
>
> Hopefully, my descriptions are as descriptive as I want them to be. The
> doxygen style is not 100% correct. I'll fix that, as well as typos. I
> haven't coded anything yet, it's just the API/ABI I would like to
> realize.
>
> 1. To not mess events (mostly GE events) with the full_sequence,
> there're new pure alternatives:
> xcb_rcv_event_t, xcb_rcv_ge_event_t (and xcb_rcv_error_t)
>
> Yes, that doesn't fix the old xcb_ge_event_t. Which is not possible
> without breaking the API (i.e. Xlib uses it). Here I thought about
> returning a zerod out GE event if someone requests such an event
> with the current API.
>
> 2. The sequence in this API is a
> typedef uint64_t xcb_rcv_sequence_t;
> and used instead of a cookie. The current cookies can not be changed
> to adopt the 64bit sequence without breaking the ABI.
>
> With xcb_rcv_event() an event can be picked up. It has an optional
> out parameter for the sequence. The parameter can be NULL if someone
> doesn't care about the sequence for events. And it has a mode
> parameter indicating if you want it to be a wait, poll or
> (poll_for_)queued.
>
> With xcb_rcv_send() the request will be send. It's basicly the same
> as xcb_send_request(). Just returning an xcb_rcv_sequence_t instead
> of an unsigned int and uses a typdefed enum for flags. It's
> noteworthy, because the generated requests have to use it.
> Additionally, I will generate one request function returning the
> xcb_rcv_sequence_t and allowing to set the flags. That way I don't
> need to create _checked() and _unchecked() versions and (first realy
> new thing) it allows to set "discard" directly when creating the
> request.
> With xcb_rcv_reply() the reply gets picked up. It has the same mode
> parameter as xcb_rcv_event() allowing to use to wait, poll and
> (poll_for_)queued replies. The latter was not possible before.
>
> 3. I'm missing the functionallity to use libxcb in a more event driven
> fashion. Sure I can poll for every outstanding reply with the
> specific xcb_[request_name]_reply() function but that has it's
> limits. One thing to come across this is allowing xcb_rcv_reply() to
> be calles with "queued". But, there're two more functions I would
> like to introduce xcb_rcv_next() and xcb_rcv_last().
> _last() one first: It just returns the sequence of the last received
> reply. With this you know which replies can be picked up (all with a
> sequence <= xcb_rcv_last()) without blocking or causing IO.
> With xcb_rcv_next() one can check for available data. It uses the
> mode parameter (like xcb_rcv_event() and xcv_rcv_reply()), returns a
> value depending on the next available data (XCB_RCV_EVENT or
> XCB_RCV_REPLY) and has an optional out parameter sequence.
> It can be used as a central blocking function in a loop and according
> to the return value you can dispatch while using the sequence. I.e.
> if it returns XCB_RCV_REPLY and you use the optional sequence
> parameter, you know for which specific request the reply is available
> in the queue.
> Or if you use something else to monitor the fd (like tscb::io_service
> or boost::asio) you can call xcb_rcv_next() with mode = XCB_RCV_POLL
> and dispatch the return value and sequence as your will.
>
> Everything together is bit more then would've been necessary to fix
> either the full_sequence problem or the 64bit API thing. But, it was
> muddy outside and I was in the mood to sum up my ideas and wishes. ;)
>
> Thanks for any comments, I know reading long mails is a pain. But, I
> didn't know howto cut this down without missing the thoughts I had.
> Well, I could've send the diff only.
>
>
> Cheers,
> Daniel Martin
>
> src/xcb.h | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> src/xcbext.h | 88 +++++++++++++++++++++++++++++++++---
> 2 files changed, 224 insertions(+), 9 deletions(-)
>
> diff --git a/src/xcb.h b/src/xcb.h
> index f7dc6af..c2228cb 100644
> --- a/src/xcb.h
> +++ b/src/xcb.h
> @@ -127,7 +127,7 @@ typedef struct {
> /**
> * @brief Generic event.
> *
> - * A generic event structure.
> + * A generic event structure with the internal sequence attached.
> */
> typedef struct {
> uint8_t response_type; /**< Type of the response */
> @@ -140,8 +140,9 @@ typedef struct {
> /**
> * @brief GE event
> *
> - * An event as sent by the XGE extension. The length field specifies the
> - * number of 4-byte blocks trailing the struct.
> + * An event as sent by the XGE extension with the internal sequence
> + * attached. The length field specifies the number of 4-byte blocks
> + * trailing the struct.
> */
> typedef struct {
> uint8_t response_type; /**< Type of the response */
> @@ -157,7 +158,7 @@ typedef struct {
> /**
> * @brief Generic error.
> *
> - * A generic error structure.
> + * A generic error structure with the internal sequence attached.
> */
> typedef struct {
> uint8_t response_type; /**< Type of the response */
> @@ -172,6 +173,50 @@ typedef struct {
> } xcb_generic_error_t;
>
> /**
> + * @brief Generic event.
> + *
> + * A pure generic event structure.
> + */
> +typedef struct {
> + uint8_t response_type; /**< Type of the response */
> + uint8_t pad0; /**< Padding */
> + uint16_t sequence; /**< Sequence number */
> + uint32_t pad[7]; /**< Padding */
> +} xcb_rcv_event_t;
> +
> +/**
> + * @brief GE event
> + *
> + * A pure event as sent by the XGE extension. The length field specifies
> + * the number of 4-byte blocks trailing the struct.
> + */
> +typedef struct {
> + uint8_t response_type; /**< Type of the response */
> + uint8_t pad0; /**< Padding */
> + uint16_t sequence; /**< Sequence number */
> + uint32_t length;
> + uint16_t event_type;
> + uint16_t pad1;
> + uint32_t pad[5]; /**< Padding */
> +} xcb_rcv_ge_event_t;
> +
> +/**
> + * @brief Generic error.
> + *
> + * A pure generic error structure.
> + */
> +typedef struct {
> + uint8_t response_type; /**< Type of the response */
> + uint8_t error_code; /**< Error code */
> + uint16_t sequence; /**< Sequence number */
> + uint32_t resource_id; /** < Resource ID for requests with side effects only */
> + uint16_t minor_code; /** < Minor opcode of the failed request */
> + uint8_t major_code; /** < Major opcode of the failed request */
> + uint8_t pad0;
> + uint32_t pad[5]; /**< Padding */
> +} xcb_rcv_error_t;
> +
> +/**
> * @brief Generic cookie.
> *
> * A generic cookie structure.
> @@ -180,6 +225,45 @@ typedef struct {
> unsigned int sequence; /**< Sequence number */
> } xcb_void_cookie_t;
>
> +/**
> + * @brief A sequence number.
> + *
> + * TODO: description?
> + */
> +typedef uint64_t xcb_rcv_sequence_t; /**< Sequence number */
> +
> +/**
> + * @brief Mode to retrieve the data with.
> + *
> + * The mode to retrieve the data with depending on the use case.
> + * This can be:
> + * XCB_RCV_WAIT: Examine the queue and block (wait for IO) until the
> + * desired data is available.
> + * XCB_RCV_POLL: Examine the queue and poll for IO once if the desired
> + * data is not available.
> + * XCB_RCV_QUEUED: Just examine the queue for the desired data.
> + * Doesn't cause IO even if the data is not available.
> + *
> + * (data can be either an event or a reply.)
> + */
> +typedef enum {
> + XCB_RCV_WAIT, /**< block until the data available */
> + XCB_RCV_POLL, /**< poll once for the data */
> + XCB_RCV_QUEUED /**< check the queue for the data only */
> +} xcb_rcv_mode_t;
> +
> +/**
> + * @brief Status which can be returned by xcb_rcv_...() functions.
> + *
> + * An xcb_rcv_...() function usually returns one of these values.
> + */
> +typedef enum {
> + XCB_RCV_NONE,
> + XCB_RCV_EVENT,
> + XCB_RCV_REPLY,
> + XCB_RCV_ERROR,
> +} xcb_rcv_status_t;
> +
>
> /* Include the generated xproto header. */
> #include "xproto.h"
> @@ -306,6 +390,29 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c);
> xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c);
>
> /**
> + * @brief Receive an event.
> + * @param c: The connection to the X server.
> + * @param mode: The mode to retrieve the event with.
> + * @param event: The event, if one could be retrieved.
> + * @param sequence: [out](optional) The internal sequence number.
> + * @return XCB_RCV_EVENT, when an event could be retrieved.
> + * @return XCB_RCV_NONE, when no event could be retrieved.
> + *
> + * This is a version of xcb_poll_for_event that only examines the
> + * event queue for new events. The function doesn't try to read new
> + * events from the connection if no queued events are found.
> + *
> + * This function is useful for callers that know in advance that all
> + * interesting events have already been read from the connection. For
> + * example, callers might use xcb_wait_for_reply and be interested
> + * only of events that preceded a specific reply.
> + */
> +xcb_rcv_status_t xcb_rcv_event(xcb_connection_t *c,
> + xcb_rcv_mode_t mode,
> + xcb_rcv_event_t *event,
> + xcb_rcv_sequence_t *sequence);
> +
> +/**
> * @brief Return the error for a request, or NULL if none can ever arrive.
> * @param c: The connection to the X server.
> * @param cookie: The request cookie.
> @@ -324,6 +431,23 @@ xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c);
> xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie);
>
> /**
> + * @brief Check for a pending error for a request.
> + * @param c: The connection to the X server.
> + * @param mode: The mode to retrieve the error with.
> + * @param sequence: The sequence number of the request.
> + * @param error: The error, if one arrived.
> + * @return XCB_RCV_ERROR, when an error occured or no error will ever arrive.
> + * @return XCB_RCV_NONE, when no error has been received yet.
> + *
> + * TODO - description:
> + * - not restricted to _checked() sequences like xcb_request_check()
> + */
> +xcb_rcv_status_t xcb_rcv_check(xcb_connection_t *c,
> + xcb_rcv_mode_t mode,
> + xcb_rcv_sequence_t sequence,
> + xcb_rcv_error_t **error);
> +
> +/**
> * @brief Discards the reply for a request.
> * @param c: The connection to the X server.
> * @param sequence: The request sequence number from a cookie.
> @@ -339,6 +463,19 @@ xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t co
> */
> void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
>
> +/**
> + * @brief Discards the reply for a request.
> + * @param c: The connection to the X server.
> + * @param sequence: The request sequence number from a cookie.
> + *
> + * Discards the reply for a request. Additionally, any error generated
> + * by the request is also discarded (unless it was a request with the
> + * flag XCB_RCV_UNCHECKED and the error has already arrived).
> + *
> + * This function will not block even if the reply is not yet available.
> + */
> +void xcb_rcv_discard(xcb_connection_t *c, xcb_rcv_sequence_t sequence);
> +
>
> /* xcb_ext.c */
>
> diff --git a/src/xcbext.h b/src/xcbext.h
> index 98b3c93..04385c6 100644
> --- a/src/xcbext.h
> +++ b/src/xcbext.h
> @@ -51,14 +51,43 @@ typedef struct {
> uint8_t isvoid;
> } xcb_protocol_request_t;
>
> -enum xcb_send_request_flags_t {
> - XCB_REQUEST_CHECKED = 1 << 0,
> - XCB_REQUEST_RAW = 1 << 1,
> - XCB_REQUEST_DISCARD_REPLY = 1 << 2
> -};
> +/**
> + * @brief Flags howto handle the reply or error.
> + *
> + * Flags to modify how a reply or error gets handled. This can be:
> + * XCB_REQUEST_DEFAULT: Will automatically select XCB_REQUEST_CHECKED
> + * for a request causing a reply or nothing
> + * (unchecked) for a request without a reply.
> + * XCB_REQUEST_CHECKED: The error will be attached to the reply queue.
> + * If not set, the error will be attached to the
> + * event queue.
> + * XCB_REQUEST_RAW: TODO
> + * XCB_REQUEST_DISCARD_REPLY: The reply or error will be discarded.
> + */
> +typedef enum xcb_send_request_flags_t {
> + XCB_REQUEST_DEFAULT = 0 << 0, /**< Use XCB_REQUEST_CHECKED or not depending on the request */
> + XCB_REQUEST_CHECKED = 1 << 0, /**< Checked error (in reply queue) */
> + XCB_REQUEST_RAW = 1 << 1, /**< TODO */
> + XCB_REQUEST_DISCARD_REPLY = 1 << 2 /**< Discard reply or error */
> +} xcb_rcv_flags_t;
>
> unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
>
> +/**
> + * @brief Send a request to the X server.
> + * @param c: The connection to the X server.
> + * @param flags: Howto handle the error or reply.
> + * @param vector: TODO
> + * @param request: TODO
> + * @return The sequence number of the request, which is necessary to retrieve the error or reply later.
> + *
> + * TODO: description
> + */
> +xcb_rcv_sequence_t xcb_rcv_send(xcb_connection_t *c,
> + xcb_rcv_flags_t flags,
> + struct iovec *vector,
> + const xcb_protocol_request_t *request);
> +
> /* xcb_take_socket allows external code to ask XCB for permission to
> * take over the write side of the socket and send raw data with
> * xcb_writev. xcb_take_socket provides the sequence number of the last
> @@ -89,6 +118,55 @@ int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t re
> void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
> int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error);
>
> +/**
> + * @brief Retrieve the reply for a request.
> + * @param c: The connection to the X server.
> + * @param mode: The mode howto retrieve the reply.
> + * @param sequence: The sequence number of the request.
> + * @param reply[out]: The reply, if one could be retrieved.
> + * @param error[out]: (optional) The error, if one has be retrieved.
> + * @return XCB_RCV_NONE, when no reply could be retrieved.
> + * @return XCB_RCV_REPLY, when something has been retrieved and reply or error is set.
> + *
> + * Depending on the mode this function checks for a queued reply or
> + * blocks until the reply is available.
> + *
> + * (Here a reply means: a reply or an error.)
> + */
> +xcb_rcv_status_t xcb_rcv_reply(xcb_connection_t *c,
> + xcb_rcv_mode_t mode,
> + xcb_rcv_sequence_t sequence,
> + void **reply,
> + xcb_rcv_error_t **error);
> +
> +/**
> + * @brief Check for available data.
> + * @param c: The connection to the X server.
> + * @param mode: The mode howto check for data.
> + * @param sequence[out]: (optional) The sequence number of the data.
> + * @return XCB_RCV_NONE, when no data is available.
> + * @return XCB_RCV_EVENT, when data is available in the event queue.
> + * @return XCB_RCV_REPLY, when data is available in the reply queue.
> + *
> + * Depending on the mode this function checks for queued data or blocks
> + * until data is available. If something has been found, set the
> + * sequence accordingly and return a value matching the result.
> + *
> + * (data can be a reply, event or error)
> + */
> +xcb_rcv_status_t xcb_rcv_first(xcb_connection_t *c,
> + xcb_rcv_mode_t mode,
> + xcb_rcv_sequence_t *sequence);
> +
> +/**
> + * @brief Get the sequence of the last received reply.
> + * @param c: The connection to the X server.
> + * @return The sequence of the last received reply.
> + *
> + * This function doesn't do any IO. It just returns the sequence of the
> + * last received reply.
> + */
> +xcb_rcv_sequence_t xcb_rcv_last(xcb_connection_t *c);
>
> /* xcb_util.c */
>
> --
> 1.8.1.4
>
> _______________________________________________
> Xcb mailing list
> Xcb at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/xcb
More information about the Xcb
mailing list