[PATCH 2/2] DRI2: Track clients' outstanding swap requests.

Christopher James Halse Rogers christopher.halse.rogers at canonical.com
Tue Dec 7 22:56:34 PST 2010


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>
---
 hw/xfree86/dri2/dri2.c |   54 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 6da2e17..37648bd 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)
+
 static RESTYPE       dri2DrawableRes;
 
 typedef struct _DRI2Screen *DRI2ScreenPtr;
@@ -111,8 +114,16 @@ typedef struct _DRI2SwapCompleteDataRec {
     DRI2BufferPtr	src;
     DRI2BufferPtr	dest;
     void *		data;
+    Bool		clientGone;
+    struct list		link;
 } DRI2SwapCompleteDataRec, *DRI2SwapCompleteDataPtr;
 
+static struct list *
+DRI2GetClientEventList(ClientPtr client)
+{
+    return dixLookupPrivate(&client->devPrivates, dri2ClientPrivateKey);
+}
+
 static DRI2ScreenPtr
 DRI2GetScreen(ScreenPtr pScreen)
 {
@@ -739,6 +750,7 @@ DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
 static void
 free_swap_complete_data (DrawablePtr pDraw, DRI2SwapCompleteDataPtr pSwapData)
 {
+    list_del(&pSwapData->link);
     buffer_unref(pDraw, pSwapData->src);
     buffer_unref(pDraw, pSwapData->dest);
     free(pSwapData);
@@ -776,15 +788,16 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
 		   DRI2BufferFrontLeft);
 
     ust = ((CARD64)tv_sec * 1000000) + tv_usec;
-    if (swap_complete)
+    if (swap_complete && !pSwapData->clientGone)
 	swap_complete(client, pSwapData->data, type, ust, frame,
 		      pPriv->swap_count);
 
     pPriv->last_swap_msc = frame;
     pPriv->last_swap_ust = ust;
 
-    DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
-    
+    if (!pSwapData->clientGone)
+	DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
+
     free_swap_complete_data(pDraw, pSwapData);
 }
 
@@ -817,6 +830,7 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
     DRI2DrawablePtr         pPriv;
     DRI2BufferPtr           pDestBuffer = NULL, pSrcBuffer = NULL;
     DRI2SwapCompleteDataPtr pSwapData;
+    struct list *          clientEvents = DRI2GetClientEventList(client);
     int                     ret, i;
     CARD64                  ust, current_msc;
 
@@ -855,6 +869,8 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
     pSwapData->src = pSrcBuffer;
     pSwapData->dest = pDestBuffer;
     pSwapData->data = data;
+    pSwapData->clientGone = FALSE;
+    list_add (&pSwapData->link, clientEvents);
 
     /* Old DDX or no swap interval, just blit */
     if (!ds->ScheduleSwap || !pPriv->swap_interval) {
@@ -1137,6 +1153,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;
@@ -1226,6 +1245,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->clientGone = TRUE;
+		    list_del(&ref->link);
+		}
+	    }
+	    break;
+	default:
+	    break;
+    }
+}
+
 extern ExtensionModule dri2ExtensionModule;
 
 static pointer
@@ -1238,6 +1285,7 @@ DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin)
     if (!setupDone)
     {
 	setupDone = TRUE;
+	AddCallback(&ClientStateCallback, DRI2ClientCallback, NULL);
 	LoadExtension(&dri2ExtensionModule, FALSE);
     }
     else
-- 
1.7.2.3



More information about the xorg-devel mailing list