[PATCH] xfree86: Move Xv's AdjustFrame work to BlockHandler (#4652)

Adam Jackson ajax at redhat.com
Mon Aug 9 11:09:53 PDT 2010


If the SIGIO handler interrupts the drivers XVPutImage hook, we can end
up calling RemovePortFromWindow(NULL), which will fault.  That's nasty
enough, but calling RegionDestroy is also verboten since that races with
malloc.

Move it all to the block handler, being careful to block SIGIO
processing during the difficult bit of the work.  Note that there's an
unavoidable race here between reading the "do I need to finish" variable
and going back to select(), which means in the worst case we can be one
frame behind in updates until the next time we hit select().  Serves you
right for using panning.

Signed-off-by: Adam Jackson <ajax at redhat.com>
---
 hw/xfree86/common/xf86xv.c     |   48 ++++++++++++++++++++++++++++++---------
 hw/xfree86/common/xf86xvpriv.h |    2 +
 2 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/hw/xfree86/common/xf86xv.c b/hw/xfree86/common/xf86xv.c
index c1d3199..c6333d6 100644
--- a/hw/xfree86/common/xf86xv.c
+++ b/hw/xfree86/common/xf86xv.c
@@ -92,6 +92,8 @@ static int xf86XVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr,
 static int xf86XVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr,
 				CARD16*, CARD16*, int*, int*);
 
+static void
+xf86XVBlockHandler(int screen, void *block, void *timeout, void *read);
 
 /* ScreenRec fields */
 
@@ -235,7 +237,6 @@ xf86XVFreeVideoAdaptorRec(XF86VideoAdaptorPtr ptr)
     free(ptr);
 }
 
-
 Bool
 xf86XVScreenInit(
    ScreenPtr pScreen,
@@ -287,7 +288,10 @@ xf86XVScreenInit(
   ScreenPriv->EnterVT = pScrn->EnterVT;
   ScreenPriv->LeaveVT = pScrn->LeaveVT;
   ScreenPriv->AdjustFrame = pScrn->AdjustFrame;
+  ScreenPriv->BlockHandler = pScreen->BlockHandler;
+  ScreenPriv->finishAdjustFrame = 0;
 
+  pScreen->BlockHandler = xf86XVBlockHandler;
   pScreen->DestroyWindow = xf86XVDestroyWindow;
   pScreen->WindowExposures = xf86XVWindowExposures;
   pScreen->ClipNotify = xf86XVClipNotify;
@@ -1286,28 +1290,33 @@ xf86XVLeaveVT(int index, int flags)
 }
 
 static void
-xf86XVAdjustFrame(int index, int x, int y, int flags)
+xf86XVBlockHandler(int screen, void *block, void *timeout, void *read)
 {
-  ScrnInfoPtr pScrn = xf86Screens[index];
+  ScrnInfoPtr pScrn = xf86Screens[screen];
   ScreenPtr pScreen = pScrn->pScreen;
   XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
   XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
   WindowPtr pWin;
   XvAdaptorPtr pa;
-  int c, i;
+  int c, i, wasset;
 
-  if(ScreenPriv->AdjustFrame) {
-	pScrn->AdjustFrame = ScreenPriv->AdjustFrame;
-	(*pScrn->AdjustFrame)(index, x, y, flags);
-	pScrn->AdjustFrame = xf86XVAdjustFrame;
+  if (ScreenPriv->BlockHandler) {
+    pScreen->BlockHandler = ScreenPriv->BlockHandler;
+    pScreen->BlockHandler(screen, block, timeout, read);
+    pScreen->BlockHandler = xf86XVBlockHandler;
   }
 
+  if (!ScreenPriv->finishAdjustFrame)
+    return;
+
+  wasset = xf86BlockSIGIO();
+
   for(c = pxvs->nAdaptors, pa = pxvs->pAdaptors; c > 0; c--, pa++) {
       XvPortPtr pPort = pa->pPorts;
       XvPortRecPrivatePtr pPriv;
 
       for(i = pa->nPorts; i > 0; i--, pPort++) {
-	pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr;
+	pPriv = pPort->devPriv.ptr;
 
 	if(!pPriv->type && (pPriv->isOn != XV_OFF)) { /* overlaid still/image */
 
@@ -1320,8 +1329,7 @@ xf86XVAdjustFrame(int index, int x, int y, int flags)
 
 	  if ((pPriv->AdaptorRec->ReputImage) &&
 	     ((pWin->visibility == VisibilityUnobscured) ||
-	      (pWin->visibility == VisibilityPartiallyObscured)))
-	  {
+	      (pWin->visibility == VisibilityPartiallyObscured))) {
 	      xf86XVReputImage(pPriv);
 	  } else if (pPriv->isOn == XV_ON) {
 	     (*pPriv->AdaptorRec->StopVideo)(
@@ -1333,8 +1341,26 @@ xf86XVAdjustFrame(int index, int x, int y, int flags)
 	}
      }
   }
+
+  ScreenPriv->finishAdjustFrame = 0;
+  xf86UnblockSIGIO(wasset);
 }
 
+static void
+xf86XVAdjustFrame(int index, int x, int y, int flags)
+{
+  ScrnInfoPtr pScrn = xf86Screens[index];
+  ScreenPtr pScreen = pScrn->pScreen;
+  XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
+
+  if(ScreenPriv->AdjustFrame) {
+	pScrn->AdjustFrame = ScreenPriv->AdjustFrame;
+	(*pScrn->AdjustFrame)(index, x, y, flags);
+	pScrn->AdjustFrame = xf86XVAdjustFrame;
+  }
+
+  ScreenPriv->finishAdjustFrame = 1;
+}
 
 /**** XvAdaptorRec fields ****/
 
diff --git a/hw/xfree86/common/xf86xvpriv.h b/hw/xfree86/common/xf86xvpriv.h
index 7623d29..25dd431 100644
--- a/hw/xfree86/common/xf86xvpriv.h
+++ b/hw/xfree86/common/xf86xvpriv.h
@@ -44,6 +44,8 @@ typedef struct {
    Bool                         (*EnterVT)(int, int);
    void                         (*LeaveVT)(int, int);
    GCPtr			videoGC;
+   ScreenBlockHandlerProcPtr	BlockHandler;
+   int				finishAdjustFrame;
 } XF86XVScreenRec, *XF86XVScreenPtr;
 
 typedef struct {
-- 
1.7.2



More information about the xorg-devel mailing list