[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