[PATCH 5/7] Add event queue splitting

Keith Packard keithp at keithp.com
Tue Nov 5 16:41:25 PST 2013


This allows apps to peel off certain XGE events into separate queues
for custom handling. Designed to support the Present extension

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 src/xcb.h    |  45 ++++++++++------
 src/xcb_in.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/xcbint.h |   2 +
 3 files changed, 194 insertions(+), 20 deletions(-)

diff --git a/src/xcb.h b/src/xcb.h
index f7dc6af..f99e677 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -138,23 +138,6 @@ typedef struct {
 } xcb_generic_event_t;
 
 /**
- * @brief GE event
- *
- * An 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 */
-    uint32_t full_sequence;  /**< full sequence */
-} xcb_ge_event_t;
-
-/**
  * @brief Generic error.
  *
  * A generic error structure.
@@ -305,6 +288,34 @@ 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);
 
+typedef struct xcb_special_event xcb_special_event_t;
+
+/**
+ * @brief Returns the next event from a special queue
+ */
+xcb_generic_event_t *xcb_check_for_special_event(xcb_connection_t *c,
+                                                 xcb_special_event_t *se);
+ 
+/**
+ * @brief Returns the next event from a special queue, blocking until one arrives
+ */
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+                                                xcb_special_event_t *se);
+ 
+/**
+ * @brief Listen for a special event
+ */
+xcb_special_event_t *xcb_register_for_special_event(xcb_connection_t *c,
+                                                    uint8_t extension,
+                                                    uint32_t eid,
+                                                    uint32_t *stamp);
+
+/**
+ * @brief Stop listening for a special event
+ */
+void xcb_unregister_for_special_event(xcb_connection_t *c,
+                                      xcb_special_event_t *se);
+
 /**
  * @brief Return the error for a request, or NULL if none can ever arrive.
  * @param c: The connection to the X server.
diff --git a/src/xcb_in.c b/src/xcb_in.c
index f9a10e7..17cd158 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -61,6 +61,23 @@ struct event_list {
     struct event_list *next;
 };
 
+struct xcb_special_event {
+
+    struct xcb_special_event *next;
+
+    /* Match XGE events for the specific extension and event ID (the
+     * first 32 bit word after evtype)
+     */
+    uint8_t     extension;
+    uint32_t    eid;
+    uint32_t    *stamp;
+
+    struct event_list   *events;
+    struct event_list   **events_tail;
+
+    pthread_cond_t special_event_cond;
+};
+
 struct reply_list {
     void *reply;
     struct reply_list *next;
@@ -105,6 +122,46 @@ static int read_fds(xcb_connection_t *c, int *fds, int nfd)
 }
 #endif
 
+typedef struct xcb_ge_special_event_t {
+    uint8_t  response_type; /**<  */
+    uint8_t  extension; /**<  */
+    uint16_t sequence; /**<  */
+    uint32_t length; /**<  */
+    uint16_t evtype; /**<  */
+    uint8_t  pad0[2]; /**< */
+    uint32_t eid; /**< */
+    uint8_t  pad1[16]; /**<  */
+} xcb_ge_special_event_t;
+
+static int event_special(xcb_connection_t *c,
+                         struct event_list *event)
+{
+    struct xcb_special_event *special_event;
+    struct xcb_ge_special_event_t *ges = (void *) event->event;
+
+    /* Special events are always XGE events */
+    if ((ges->response_type & 0x7f) != XCB_XGE_EVENT)
+        return 0;
+
+    for (special_event = c->in.special_events;
+         special_event;
+         special_event = special_event->next)
+    {
+        if (ges->extension == special_event->extension &&
+            ges->eid == special_event->eid)
+        {
+            *special_event->events_tail = event;
+            special_event->events_tail = &event->next;
+            if (special_event->stamp)
+                ++(*special_event->stamp);
+            pthread_cond_signal(&special_event->special_event_cond);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 static int read_packet(xcb_connection_t *c)
 {
     xcb_generic_reply_t genrep;
@@ -269,9 +326,12 @@ static int read_packet(xcb_connection_t *c)
     }
     event->event = buf;
     event->next = 0;
-    *c->in.events_tail = event;
-    c->in.events_tail = &event->next;
-    pthread_cond_signal(&c->in.event_cond);
+
+    if (!event_special(c, event)) {
+        *c->in.events_tail = event;
+        c->in.events_tail = &event->next;
+        pthread_cond_signal(&c->in.event_cond);
+    }
     return 1; /* I have something for you... */
 }
 
@@ -614,6 +674,107 @@ xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t co
     return ret;
 }
 
+static xcb_generic_event_t *get_special_event(xcb_connection_t *c,
+                                              xcb_special_event_t *se)
+{
+    xcb_generic_event_t *event = NULL;
+    struct event_list *events;
+
+    if ((events = se->events) != NULL) {
+        event = events->event;
+        if (!(se->events = events->next))
+            se->events_tail = &se->events;
+        free (events);
+    }
+    return event;
+}
+
+xcb_generic_event_t *xcb_check_for_special_event(xcb_connection_t *c,
+                                                 xcb_special_event_t *se)
+{
+    xcb_generic_event_t *event;
+
+    if(c->has_error)
+        return 0;
+    pthread_mutex_lock(&c->iolock);
+    event = get_special_event(c, se);
+    pthread_mutex_unlock(&c->iolock);
+    return event;
+}
+
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+                                                xcb_special_event_t *se)
+{
+    xcb_generic_event_t *event;
+
+    if(c->has_error)
+        return 0;
+    pthread_mutex_lock(&c->iolock);
+
+    /* get_special_event returns 0 on empty list. */
+    while(!(event = get_special_event(c, se)))
+        if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0))
+            break;
+
+    pthread_mutex_unlock(&c->iolock);
+    return event;
+}
+
+xcb_special_event_t *
+xcb_register_for_special_event(xcb_connection_t *c,
+                               uint8_t extension,
+                               uint32_t eid,
+                               uint32_t *stamp)
+{
+    xcb_special_event_t *se;
+    pthread_mutex_lock(&c->iolock);
+    for (se = c->in.special_events; se; se = se->next) {
+        if (se->extension == extension &&
+            se->eid == eid)
+            break;
+    }
+    if (!se) {
+        se = calloc(1, sizeof(xcb_special_event_t));
+        se->extension = extension;
+        se->eid = eid;
+
+        se->events = NULL;
+        se->events_tail = &se->events;
+
+        pthread_cond_init(&se->special_event_cond, 0);
+
+        se->next = c->in.special_events;
+        c->in.special_events = se;
+    }
+    se->stamp = stamp;
+    pthread_mutex_unlock(&c->iolock);
+    return se;
+}
+
+void
+xcb_unregister_for_special_event(xcb_connection_t *c,
+                                 xcb_special_event_t *se)
+{
+    xcb_special_event_t *s, **prev;
+    struct event_list   *events, *next;
+    pthread_mutex_lock(&c->iolock);
+
+    for (prev = &c->in.special_events; (s = *prev) != NULL; prev = &(s->next)) {
+        if (s == se) {
+            *prev = se->next;
+            for (events = se->events; events; events = next) {
+                next = events->next;
+                free (events->event);
+                free (events);
+            }
+            pthread_cond_destroy(&se->special_event_cond);
+            free (se);
+            break;
+        }
+    }
+    pthread_mutex_unlock(&c->iolock);
+}
+
 /* Private interface */
 
 int _xcb_in_init(_xcb_in *in)
diff --git a/src/xcbint.h b/src/xcbint.h
index 75d159f..62427ef 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -148,6 +148,8 @@ typedef struct _xcb_in {
     struct pending_reply *pending_replies;
     struct pending_reply **pending_replies_tail;
     _xcb_fd in_fd;
+
+    struct xcb_special_event *special_events;
 } _xcb_in;
 
 int _xcb_in_init(_xcb_in *in);
-- 
1.8.4.2



More information about the xorg-devel mailing list