Mesa (staging/20.1): loader/dri3: Check for window destruction in dri3_wait_for_event_locked

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jun 29 19:14:58 UTC 2020


Module: Mesa
Branch: staging/20.1
Commit: 195dd044617707d680b412a08549f68cc3551c53
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=195dd044617707d680b412a08549f68cc3551c53

Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Fri Jun  5 19:07:55 2020 +0200

loader/dri3: Check for window destruction in dri3_wait_for_event_locked

If the underlying X11 window gets destroyed, the event we're waiting
for may never be delivered, in which case xcb_wait_for_special_event
would hang indefinitely.

Solution:

1. Use xcb_poll_for_special_event to check if an event has arrived yet.
2. If not, Wait up to ~1s for XCB's file descriptor to become readable;
   if it does, go back to step 1.
3. If the file descriptor didn't become readable, make a round-trip to
   the X server to check that the window still exists. Go back to step
   1 if it does, otherwise bail.

Also add an early bail-out when it's known that the window was
destroyed.

Cc: mesa-stable
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/116
Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5368>
(cherry picked from commit d7d7687829875e401690219d4a72458fb2bbe4de)

---

 .pick_status.json               |  2 +-
 src/loader/loader_dri3_helper.c | 38 +++++++++++++++++++++++++++++++++++++-
 src/loader/loader_dri3_helper.h |  1 +
 3 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/.pick_status.json b/.pick_status.json
index 22b5611bd17..10081f37edc 100644
--- a/.pick_status.json
+++ b/.pick_status.json
@@ -4,7 +4,7 @@
         "description": "loader/dri3: Check for window destruction in dri3_wait_for_event_locked",
         "nominated": true,
         "nomination_type": 0,
-        "resolution": 0,
+        "resolution": 1,
         "master_sha": null,
         "because_sha": null
     },
diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
index 12860d6594f..81c67403517 100644
--- a/src/loader/loader_dri3_helper.c
+++ b/src/loader/loader_dri3_helper.c
@@ -22,6 +22,7 @@
  */
 
 #include <fcntl.h>
+#include <poll.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
@@ -532,20 +533,55 @@ dri3_wait_for_event_locked(struct loader_dri3_drawable *draw,
    xcb_generic_event_t *ev;
    xcb_present_generic_event_t *ge;
 
+   if (draw->window_destroyed)
+      return false;
+
    xcb_flush(draw->conn);
 
    /* Only have one thread waiting for events at a time */
    if (draw->has_event_waiter) {
       cnd_wait(&draw->event_cnd, &draw->mtx);
+      if (draw->window_destroyed)
+         return false;
       if (full_sequence)
          *full_sequence = draw->last_special_event_sequence;
       /* Another thread has updated the protected info, so retest. */
       return true;
    } else {
+      struct pollfd pfds;
+
       draw->has_event_waiter = true;
       /* Allow other threads access to the drawable while we're waiting. */
       mtx_unlock(&draw->mtx);
-      ev = xcb_wait_for_special_event(draw->conn, draw->special_event);
+
+      pfds.fd = xcb_get_file_descriptor(draw->conn);
+      pfds.events = POLLIN;
+
+      ev = xcb_poll_for_special_event(draw->conn, draw->special_event);
+      while (!ev) {
+         /* Wait up to ~1s for the XCB FD to become readable */
+         if (poll(&pfds, 1, 1000) < 1) {
+            xcb_get_window_attributes_cookie_t cookie;
+            xcb_get_window_attributes_reply_t *attrib;
+            xcb_generic_error_t *error;
+
+            /* Check if the window still exists */
+            cookie = xcb_get_window_attributes(draw->conn, draw->drawable);
+            attrib = xcb_get_window_attributes_reply(draw->conn, cookie, &error);
+            free(attrib);
+
+            if (error) {
+               if (error->error_code == BadWindow)
+                  draw->window_destroyed = true;
+
+               free(error);
+               break;
+            }
+         }
+
+         ev = xcb_poll_for_special_event(draw->conn, draw->special_event);
+      }
+
       mtx_lock(&draw->mtx);
       draw->has_event_waiter = false;
       cnd_broadcast(&draw->event_cnd);
diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h
index c314e4c5a9d..0961534a792 100644
--- a/src/loader/loader_dri3_helper.h
+++ b/src/loader/loader_dri3_helper.h
@@ -122,6 +122,7 @@ struct loader_dri3_drawable {
    uint8_t have_back;
    uint8_t have_fake_front;
    uint8_t is_pixmap;
+   bool window_destroyed;
 
    /* Information about the GPU owning the buffer */
    __DRIscreen *dri_screen;



More information about the mesa-commit mailing list