From: Christopher James Halse Rogers <[email protected]>

Clients can terminate with pending SwapBuffers requests waiting
for the trigger, potentially a long way in the future.
Track these requests so we don't end up delivering
SwapBuffersComplete to an entirely unrelated client.

Signed-off-by: Christopher James Halse Rogers 
<[email protected]>
Signed-off-by: Pauli Nieminen <[email protected]>
---
 hw/xfree86/dri2/dri2.c |   56 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 5868fb4..9133bb3 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -60,6 +60,9 @@ static DevPrivateKeyRec dri2WindowPrivateKeyRec;
 static DevPrivateKeyRec dri2PixmapPrivateKeyRec;
 #define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
 
+static DevPrivateKeyRec dri2ClientPrivateKeyRec;
+#define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec)
+
 RESTYPE       dri2DrawableRes;
 
 typedef struct _DRI2Screen *DRI2ScreenPtr;
@@ -113,8 +116,15 @@ typedef struct _DRI2SwapCompleteDataRec {
     DRI2BufferPtr      dest;
     ClientPtr          client;
     void *             data;
+    struct list                link;
 } DRI2SwapCompleteDataRec, *DRI2SwapCompleteDataPtr;
 
+static struct list *
+DRI2GetClientEventList(ClientPtr client)
+{
+    return dixLookupPrivate(&client->devPrivates, dri2ClientPrivateKey);
+}
+
 static DRI2ScreenPtr
 DRI2GetScreen(ScreenPtr pScreen)
 {
@@ -806,6 +816,7 @@ DRI2WakeClient(ClientPtr client, DRI2DrawablePtr pPriv, int 
frame,
 static void
 free_swap_complete_data (DRI2DrawablePtr pPriv, DRI2SwapCompleteDataPtr 
pSwapData)
 {
+    list_del(&pSwapData->link);
     buffer_unref(pPriv, pSwapData->src);
     buffer_unref(pPriv, pSwapData->dest);
     free(pSwapData);
@@ -825,6 +836,11 @@ DRI2SwapComplete2(DRI2DrawablePtr pPriv, int frame,
     pPriv->swap_count++;
     pPriv->refcnt--;
 
+    ust = ((CARD64)tv_sec * 1000000) + tv_usec;
+
+    if (client == NULL)
+       goto out;
+
     if (pDraw) {
        BoxRec          box;
        RegionRec       region;
@@ -838,16 +854,16 @@ DRI2SwapComplete2(DRI2DrawablePtr pPriv, int frame,
                       DRI2BufferFrontLeft);
     }
 
-    ust = ((CARD64)tv_sec * 1000000) + tv_usec;
     if (swap_complete)
        swap_complete(client, pSwapData->data, type, ust, frame,
                pPriv->swap_count);
 
+    DRI2WakeClient(client, pPriv, frame, tv_sec, tv_usec);
+
+out:
     pPriv->last_swap_msc = frame;
     pPriv->last_swap_ust = ust;
 
-    DRI2WakeClient(client, pPriv, frame, tv_sec, tv_usec);
-
     free_swap_complete_data(pPriv, pSwapData);
 
     if (pPriv->refcnt <= 0)
@@ -881,6 +897,7 @@ DRI2SwapBuffers(ClientPtr client, DRI2DrawablePtr pPriv, 
CARD64 target_msc,
     DRI2ScreenPtr           ds = pPriv->dri2_screen;
     DRI2BufferPtr           pDestBuffer = NULL, pSrcBuffer = NULL;
     DRI2SwapCompleteDataPtr pSwapData;
+    struct list *          clientEvents = DRI2GetClientEventList(client);
     int                     ret, i;
     CARD64                  ust, current_msc;
 
@@ -919,6 +936,7 @@ DRI2SwapBuffers(ClientPtr client, DRI2DrawablePtr pPriv, 
CARD64 target_msc,
     pSwapData->dest = pDestBuffer;
     pSwapData->client = client;
     pSwapData->data = data;
+    list_add (&pSwapData->link, clientEvents);
 
     /* Old DDX or no swap interval, just blit */
     if (!ds->ScheduleSwap || !pPriv->swap_interval) {
@@ -1191,6 +1209,9 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
     if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
        return FALSE;
 
+    if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, 
sizeof (struct list)))
+       return FALSE;
+
     ds = calloc(1, sizeof *ds);
     if (!ds)
        return FALSE;
@@ -1289,6 +1310,34 @@ DRI2CloseScreen(ScreenPtr pScreen)
     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
 }
 
+static void
+DRI2ClientCallback(CallbackListPtr *ClientStateCallback, pointer closure, 
pointer calldata)
+{
+    NewClientInfoRec *clientinfo = calldata;
+    ClientPtr pClient = clientinfo->client;
+    struct list *clientEvents = DRI2GetClientEventList(pClient);
+    DRI2SwapCompleteDataPtr ref, next;
+
+    switch (pClient->clientState) {
+       case ClientStateInitial:
+           list_init(clientEvents);
+           break;
+       case ClientStateRunning:
+           break;
+       case ClientStateRetained:
+       case ClientStateGone:
+           if (clientEvents) {
+               list_for_each_entry_safe(ref, next, clientEvents, link) {
+                   ref->client = NULL;
+                   list_del(&ref->link);
+               }
+           }
+           break;
+       default:
+           break;
+    }
+}
+
 extern ExtensionModule dri2ExtensionModule;
 
 static pointer
@@ -1301,6 +1350,7 @@ DRI2Setup(pointer module, pointer opts, int *errmaj, int 
*errmin)
     if (!setupDone)
     {
        setupDone = TRUE;
+       AddCallback(&ClientStateCallback, DRI2ClientCallback, NULL);
        LoadExtension(&dri2ExtensionModule, FALSE);
     }
     else
-- 
1.7.0.4

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to