[Xcb] [PATCH 6/8] Add event queue splitting

Uli Schlachter psychon at znc.in
Thu Nov 7 02:14:29 PST 2013


On 07.11.2013 04:45, Keith Packard wrote:
> 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;

For bikeshedding, I would call this xcb_special_event_filter_t, because this is
not actually an event. Having said that, feel free to ignore me.

> +/**
> + * @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;


Add this, please:

    if(c->has_error)
        return NULL;

> +    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;
> +}

Uhm, this function just updates stamp if it calls for already existing events? I
don't like that, because this way the caller doesn't know if it has to call
_unregister again or not.

Is there any reason why this cannot return NULL on "collisisions"?

Oh and: Please check for calloc() failures.

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

    if(c->has_error)
        return;

> +    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);
> 


-- 
"In the beginning the Universe was created. This has made a lot of
 people very angry and has been widely regarded as a bad move."


More information about the xorg-devel mailing list