From 2ffa9f0bc903c314d2fc5999090510f6f566318b Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Mon, 9 Aug 2010 13:47:07 -0400 Subject: [PATCH] xfree86: Move Xv's AdjustFrame work to BlockHandler (#4652) 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 --- 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