summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2015-01-29 23:55:19 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2015-01-29 23:55:19 +0000
commitdc51886c0c637a1da94e6379f183fc32ac345df6 (patch)
tree8a625130cd545383f86e4cb8108754229c415fb3
parent1030705cdc7725ee821cf10be9c3cb0aeb31564c (diff)
sna/dri2: Fix use of stale flip_pending after removing window
Testcase: dri2-race Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/sna_dri2.c10
-rw-r--r--test/dri2-race.c46
2 files changed, 53 insertions, 3 deletions
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 4056fbb5..81ad9c60 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -1330,6 +1330,9 @@ sna_dri2_event_free(struct sna_dri2_event *info)
DrawablePtr draw = info->draw;
DBG(("%s(draw?=%d)\n", __FUNCTION__, draw != NULL));
+ if (info->sna->dri2.flip_pending == info)
+ info->sna->dri2.flip_pending = info->chain;
+ assert(info->sna->dri2.flip_pending != info);
if (draw && draw->type == DRAWABLE_WINDOW)
sna_dri2_remove_event((WindowPtr)draw, info);
@@ -1501,6 +1504,7 @@ void sna_dri2_destroy_window(WindowPtr win)
chain = priv->chain;
while ((info = chain)) {
+ assert(info->draw == &win->drawable);
info->draw = NULL;
info->client = NULL;
list_del(&info->link);
@@ -2089,9 +2093,9 @@ static void chain_swap(struct sna_dri2_event *chain)
if (chain->queued) /* too early! */
return;
- assert(chain == dri2_chain(chain->draw));
DBG(("%s: chaining draw=%ld, type=%d\n",
__FUNCTION__, (long)chain->draw->id, chain->type));
+ assert(chain == dri2_chain(chain->draw));
chain->queued = true;
switch (chain->type) {
@@ -2392,8 +2396,8 @@ static void chain_flip(struct sna *sna)
struct sna_dri2_event *chain = sna->dri2.flip_pending;
assert(chain->type == FLIP);
- DBG(("%s: chaining type=%d, cancelled?=%d\n",
- __FUNCTION__, chain->type, chain->draw == NULL));
+ DBG(("%s: chaining type=%d, cancelled?=%d window=%ld\n",
+ __FUNCTION__, chain->type, chain->draw == NULL, chain->draw ? chain->draw->id : 0));
sna->dri2.flip_pending = NULL;
if (chain->draw == NULL) {
diff --git a/test/dri2-race.c b/test/dri2-race.c
index 8862c84c..4f6d1063 100644
--- a/test/dri2-race.c
+++ b/test/dri2-race.c
@@ -5,6 +5,10 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xfixes.h>
+#include <X11/Xlib-xcb.h>
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+#include <xcb/dri2.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
@@ -41,6 +45,25 @@ static int dri2_open(Display *dpy)
return fd;
}
+static void swap_buffers(Display *dpy, Window win,
+ unsigned int *attachments, int nattachments)
+{
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ unsigned int seq[2];
+
+ seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
+ 0, 0, 0, 0, 0, 0).sequence;
+
+
+ seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
+ nattachments, nattachments,
+ attachments).sequence;
+
+ xcb_flush(c);
+ xcb_discard_reply(c, seq[0]);
+ xcb_discard_reply(c, seq[1]);
+}
+
static void run(Display *dpy, int width, int height,
unsigned int *attachments, int nattachments,
const char *name)
@@ -77,6 +100,29 @@ static void run(Display *dpy, int width, int height,
XDestroyWindow(dpy, win);
} while (--loop);
+ loop = 100;
+ do {
+ win = XCreateWindow(dpy, DefaultRootWindow(dpy),
+ 0, 0, width, height, 0,
+ DefaultDepth(dpy, DefaultScreen(dpy)),
+ InputOutput,
+ DefaultVisual(dpy, DefaultScreen(dpy)),
+ CWOverrideRedirect, &attr);
+ XMapWindow(dpy, win);
+
+ DRI2CreateDrawable(dpy, win);
+
+ buffers = DRI2GetBuffers(dpy, win, &width, &height,
+ attachments, nattachments, &count);
+ if (count != nattachments)
+ return;
+
+ free(buffers);
+ for (count = 0; count < loop; count++)
+ swap_buffers(dpy, win, attachments, nattachments);
+ XDestroyWindow(dpy, win);
+ } while (--loop);
+
XSync(dpy, 1);
sleep(2);
XSync(dpy, 1);