[PATCH xcb] don't flag extra reply in xcb_take_socket

Julien Cristau jcristau at debian.org
Tue Aug 14 12:46:58 UTC 2018


+xcb@

On 08/09/2018 12:20 AM, Erik Kurzinger wrote:
> If any flags are specified in a call to xcb_take_socket,
> they should only be applied to replies for requests sent
> after that function returns (and until the socket is
> re-acquired by XCB).
> 
> Previously, they would also be incorrectly applied to the
> reply for the last request sent before the socket was taken.
> For instance, in this example program the reply for the
> GetInputFocus request gets discarded, even though it was
> sent before the socket was taken. This results in the
> call to retrieve the reply hanging indefinitely.
> 
> static void return_socket(void *closure) {}
> 
> int main(void)
> {
>     Display *dpy = XOpenDisplay(NULL);
>     xcb_connection_t *c = XGetXCBConnection(dpy);
> 
>     xcb_get_input_focus_cookie_t cookie = xcb_get_input_focus_unchecked(c);
>     xcb_flush(c);
> 
>     uint64_t seq;
>     xcb_take_socket(c, return_socket, dpy, XCB_REQUEST_DISCARD_REPLY, &seq);
> 
>     xcb_generic_error_t *err;
>     xcb_get_input_focus_reply(c, cookie, &err);
> }
> 
> In practice, this has been causing intermittent KWin crashes when
> used in combination with the proprietary NVIDIA driver such as
> https://bugs.kde.org/show_bug.cgi?id=386370 since when Xlib fails to
> retrieve one of these incorrectly discarded replies it triggers
> an IO error.
> 
> Signed-off-by: Erik Kurzinger <ekurzinger at nvidia.com>
> ---
>  src/xcb_in.c  | 21 +++++++++++++++++++--
>  src/xcb_out.c | 10 ++++++++--
>  2 files changed, 27 insertions(+), 4 deletions(-)
> 
> diff --git a/src/xcb_in.c b/src/xcb_in.c
> index 73209e0..4333ad3 100644
> --- a/src/xcb_in.c
> +++ b/src/xcb_in.c
> @@ -958,8 +958,25 @@ void _xcb_in_replies_done(xcb_connection_t *c)
>          pend = container_of(c->in.pending_replies_tail, struct pending_reply, next);
>          if(pend->workaround == WORKAROUND_EXTERNAL_SOCKET_OWNER)
>          {
> -            pend->last_request = c->out.request;
> -            pend->workaround = WORKAROUND_NONE;
> +            if (XCB_SEQUENCE_COMPARE(pend->first_request, <=, c->out.request)) {
> +                pend->last_request = c->out.request;
> +                pend->workaround = WORKAROUND_NONE;
> +            } else {
> +                /* The socket was taken, but no requests were actually sent
> +                 * so just discard the pending_reply that was created.
> +                 */
> +                struct pending_reply *prev_pend = c->in.pending_replies;
> +                if (prev_pend == pend) {
> +                    c->in.pending_replies = NULL;
> +                    c->in.pending_replies_tail = &c->in.pending_replies;
> +                } else {
> +                    while (prev_pend->next != pend)
> +                        prev_pend = prev_pend->next;
> +                    prev_pend->next = NULL;
> +                    c->in.pending_replies_tail = &prev_pend->next;
> +                }
> +                free(pend);
> +            }
>          }
>      }
>  }
> diff --git a/src/xcb_out.c b/src/xcb_out.c
> index 3601a5f..c9593e5 100644
> --- a/src/xcb_out.c
> +++ b/src/xcb_out.c
> @@ -387,8 +387,14 @@ int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), v
>      {
>          c->out.return_socket = return_socket;
>          c->out.socket_closure = closure;
> -        if(flags)
> -            _xcb_in_expect_reply(c, c->out.request, WORKAROUND_EXTERNAL_SOCKET_OWNER, flags);
> +        if(flags) {
> +            /* c->out.request + 1 will be the first request sent by the external
> +             * socket owner. If the socket is returned before this request is sent
> +             * it will be detected in _xcb_in_replies_done and this pending_reply
> +             * will be discarded.
> +             */
> +            _xcb_in_expect_reply(c, c->out.request + 1, WORKAROUND_EXTERNAL_SOCKET_OWNER, flags);
> +        }
>          assert(c->out.request == c->out.request_written);
>          *sent = c->out.request;
>      }
> 



More information about the xorg-devel mailing list