[PATCH v2 07/10] DRI2: Track clients' outstanding swap requests.

Pauli ext-pauli.nieminen at nokia.com
Tue Feb 8 13:42:53 PST 2011


From: Christopher James Halse Rogers <christopher.halse.rogers at canonical.com>

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 <christopher.halse.rogers at canonical.com>
Signed-off-by: Pauli Nieminen <ext-pauli.nieminen at nokia.com>
---
 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



More information about the xorg-devel mailing list