[Xcb] [RFC v-1] API with 64bit seq. and more love for requests

Daniel Martin consume.noise at gmail.com
Mon Feb 25 11:53:31 PST 2013


---
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



More information about the Xcb mailing list