[PATCH 6/8] Add event queue splitting

Keith Packard keithp at keithp.com
Wed Nov 6 19:45:43 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    |  28 ++++++++++
 src/xcb_in.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/xcbint.h |   1 +
 3 files changed, 193 insertions(+), 3 deletions(-)

diff --git a/src/xcb.h b/src/xcb.h
index c251330..cde820d 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -287,6 +287,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_poll_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_xge(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 0a78ae6..9239c93 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_poll_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_xge(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 bbc5398..364dc59 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -150,6 +150,7 @@ typedef struct _xcb_in {
 #if HAVE_SENDMSG
     _xcb_fd in_fd;
 #endif
+    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