summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-06-25 22:19:23 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2014-06-26 08:28:53 +0100
commit2e8c09f3fe468abba9c307ba3d7b2d22908e1172 (patch)
tree249fa794799d0fb89ad3aac287034c2932475133
parent12a349974b63a47ad55384abe0d7a839af48f31a (diff)
sna/dri2: Hook into ClientGone callback to clear dangling references
As the Window may exist for multiple Clients, we cannot rely on the destruction of the Window decoupling all outstanding events and preventing chasing a stale Client pointer. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=80157 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/sna.h2
-rw-r--r--src/sna/sna_dri2.c140
2 files changed, 101 insertions, 41 deletions
diff --git a/src/sna/sna.h b/src/sna/sna.h
index 8640f2f4..7b89f8c3 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -114,6 +114,7 @@ struct sna_cursor;
struct sna_crtc;
struct sna_client {
+ struct list events;
int is_compositor; /* only 4 bits used */
};
@@ -334,6 +335,7 @@ struct sna {
#if HAVE_DRI2
void *flip_pending;
+ unsigned client_count;
#endif
} dri2;
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 9f8b8ee2..f24086ae 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -123,6 +123,7 @@ struct sna_dri2_event {
struct sna_dri2_event *chain;
struct list cache;
+ struct list link;
int mode;
};
@@ -1218,8 +1219,93 @@ sna_dri2_remove_event(WindowPtr win, struct sna_dri2_event *info)
chain->chain = info->chain;
}
+static void
+sna_dri2_event_free(struct sna *sna,
+ DrawablePtr draw,
+ struct sna_dri2_event *info)
+{
+ DBG(("%s(draw?=%d)\n", __FUNCTION__, draw != NULL));
+
+ if (draw && draw->type == DRAWABLE_WINDOW)
+ sna_dri2_remove_event((WindowPtr)draw, info);
+ _sna_dri2_destroy_buffer(sna, info->front);
+ _sna_dri2_destroy_buffer(sna, info->back);
+
+ while (!list_is_empty(&info->cache)) {
+ struct dri_bo *c;
+
+ c = list_first_entry(&info->cache, struct dri_bo, link);
+ list_del(&c->link);
+
+ DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
+ if (c->bo)
+ kgem_bo_destroy(&sna->kgem, c->bo);
+
+ free(c);
+ }
+
+ if (info->bo) {
+ DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
+ kgem_bo_destroy(&sna->kgem, info->bo);
+ }
+
+ _list_del(&info->link);
+ free(info);
+}
+
+static void
+sna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data)
+{
+ NewClientInfoRec *clientinfo = data;
+ ClientPtr client = clientinfo->client;
+ struct sna_client *priv = sna_client(client);
+ struct sna *sna = closure;
+
+ if (priv->events.next == NULL)
+ return;
+
+ if (client->clientState != ClientStateGone)
+ return;
+
+ DBG(("%s()\n", __FUNCTION__));
+
+ while (!list_is_empty(&priv->events)) {
+ struct sna_dri2_event *event;
+
+ event = list_first_entry(&priv->events, struct sna_dri2_event, link);
+ assert(event->client == client);
+
+ if (event->queued) {
+ event->client = NULL;
+ event->draw = NULL;
+ list_del(&event->link);
+ } else
+ sna_dri2_event_free(sna, event->draw, event);
+ }
+
+ if (--sna->dri2.client_count == 0)
+ DeleteCallback(&ClientStateCallback, sna_dri2_client_gone, sna);
+}
+
+static bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, ClientPtr client)
+{
+ struct sna_client *priv = sna_client(client);
+
+ if (priv->events.next == NULL) {
+ if (sna->dri2.client_count++ == 0 &&
+ !AddCallback(&ClientStateCallback, sna_dri2_client_gone, sna))
+ return false;
+
+ list_init(&priv->events);
+ }
+
+ list_add(&info->link, &priv->events);
+ info->client = client;
+ return true;
+}
+
static struct sna_dri2_event *
-sna_dri2_add_event(DrawablePtr draw, ClientPtr client)
+sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
{
struct dri2_window *priv;
struct sna_dri2_event *info, *chain;
@@ -1238,10 +1324,14 @@ sna_dri2_add_event(DrawablePtr draw, ClientPtr client)
list_init(&info->cache);
info->draw = draw;
- info->client = client;
info->crtc = priv->crtc;
info->pipe = sna_crtc_to_pipe(priv->crtc);
+ if (!add_event_to_client(info, sna, client)) {
+ free(info);
+ return NULL;
+ }
+
assert(priv->chain != info);
if (priv->chain == NULL) {
@@ -1258,39 +1348,6 @@ sna_dri2_add_event(DrawablePtr draw, ClientPtr client)
return info;
}
-static void
-sna_dri2_event_free(struct sna *sna,
- DrawablePtr draw,
- struct sna_dri2_event *info)
-{
- DBG(("%s\n", __FUNCTION__));
-
- if (draw && draw->type == DRAWABLE_WINDOW)
- sna_dri2_remove_event((WindowPtr)draw, info);
- _sna_dri2_destroy_buffer(sna, info->front);
- _sna_dri2_destroy_buffer(sna, info->back);
-
- while (!list_is_empty(&info->cache)) {
- struct dri_bo *c;
-
- c = list_first_entry(&info->cache, struct dri_bo, link);
- list_del(&c->link);
-
- DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
- if (c->bo)
- kgem_bo_destroy(&sna->kgem, c->bo);
-
- free(c);
- }
-
- if (info->bo) {
- DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
- kgem_bo_destroy(&sna->kgem, info->bo);
- }
-
- free(info);
-}
-
void sna_dri2_destroy_window(WindowPtr win)
{
struct sna *sna;
@@ -2022,6 +2079,7 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
break;
case WAITMSC:
+ assert(info->client);
DRI2WaitMSCComplete(info->client, draw, msc,
event->tv_sec, event->tv_usec);
break;
@@ -2377,7 +2435,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
}
}
- info = sna_dri2_add_event(draw, client);
+ info = sna_dri2_add_event(sna, draw, client);
if (info == NULL)
return false;
@@ -2423,7 +2481,7 @@ out:
return true;
}
- info = sna_dri2_add_event(draw, client);
+ info = sna_dri2_add_event(sna, draw, client);
if (info == NULL)
return false;
@@ -2507,7 +2565,7 @@ sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
if (sync) {
struct sna_dri2_event *info;
- info = sna_dri2_add_event(draw, client);
+ info = sna_dri2_add_event(sna, draw, client);
if (!info)
goto complete;
@@ -2568,7 +2626,7 @@ sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc
if (sync) {
struct sna_dri2_event *info;
- info = sna_dri2_add_event(draw, client);
+ info = sna_dri2_add_event(sna, draw, client);
if (!info)
goto complete;
@@ -2725,7 +2783,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
VG_CLEAR(vbl);
- info = sna_dri2_add_event(draw, client);
+ info = sna_dri2_add_event(sna, draw, client);
if (!info)
goto blit;
@@ -2893,7 +2951,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
if (divisor == 0 && current_msc >= target_msc)
goto out_complete;
- info = sna_dri2_add_event(draw, client);
+ info = sna_dri2_add_event(sna, draw, client);
if (!info)
goto out_complete;