- the fix kernel panics caused by screenimage in devdraw being temporarily nil. properly acquire the drawlock while setting screensize. the patch to screen.c will even work if devdraw.c is not updated, as the interface was not changed. all what happens is that the softscreen will never get freed as devdraw will create its own Memdata/Memimage so the refcount will not drop on gscreen when deletescreenimage() is called. the patch to screen.c also simplifies screensize() as we dont need to keep track of the softscreen anymore. just calling freememimage(gscreen) on the old gscreen will do the job. the gscreendata was made a local static variable as its only used when we create gscreen with hardscreen framebuffer in screensize(). Reference: /n/sources/patch/maybe/devdraw-soft-memimage Date: Mon Mar 14 18:17:08 CET 2011 Signed-off-by: cinap_lenrek@gmx.de --- /sys/src/9/pc/screen.c Mon Mar 14 17:50:54 2011 +++ /sys/src/9/pc/screen.c Mon Mar 14 18:29:17 2011 @@ -19,7 +19,6 @@ Rectangle physgscreenr; -Memdata gscreendata; Memimage *gscreen; VGAscr vgascreen[1]; @@ -40,13 +39,18 @@ int didswcursorinit; -static void *softscreen; - int -screensize(int x, int y, int z, ulong chan) +screensize(int x, int y, int, ulong chan) { VGAscr *scr; - void *oldsoft; + + qlock(&drawlock); + if(waserror()){ + qunlock(&drawlock); + nexterror(); + } + + memimageinit(); lock(&vgascreenlock); if(waserror()){ @@ -54,54 +58,50 @@ nexterror(); } - memimageinit(); scr = &vgascreen[0]; - oldsoft = softscreen; + scr->gscreendata = nil; + scr->gscreen = nil; + if(gscreen){ + freememimage(gscreen); + gscreen = nil; + } if(scr->paddr == 0){ - int width = (x*z)/BI2WD; - void *p; - - p = xalloc(width*BY2WD*y); - if(p == nil) - error("no memory for vga soft screen"); - gscreendata.bdata = softscreen = p; + gscreen = allocmemimage(Rect(0,0,x,y), chan); if(scr->dev && scr->dev->page){ scr->vaddr = KADDR(VGAMEM()); scr->apsize = 1<<16; } scr->useflush = 1; - } - else{ - gscreendata.bdata = scr->vaddr; + }else{ + static Memdata md; + + md.ref = 1; + md.bdata = scr->vaddr; + gscreen = allocmemimaged(Rect(0,0,x,y), chan, &md); scr->useflush = scr->dev && scr->dev->flush; } - - scr->gscreen = nil; - if(gscreen) - freememimage(gscreen); - gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata); if(gscreen == nil) error("no memory for vga memimage"); + vgaimageinit(chan); scr->palettedepth = 6; /* default */ - scr->gscreendata = &gscreendata; scr->memdefont = getmemdefont(); scr->gscreen = gscreen; + scr->gscreendata = gscreen->data; physgscreenr = gscreen->r; unlock(&vgascreenlock); poperror(); - if(oldsoft) - xfree(oldsoft); - - memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S); - flushmemscreen(gscreen->r); + drawcmap(); if(didswcursorinit) swcursorinit(); - drawcmap(); + + qunlock(&drawlock); + poperror(); + return 0; } @@ -152,8 +152,17 @@ *chan = scr->gscreen->chan; *d = scr->gscreen->depth; *width = scr->gscreen->width; - *softscreen = scr->useflush; - + if(scr->gscreendata->allocd){ + /* + * we use a memimage as softscreen. devdraw will create its own + * screen image on the backing store of that image. when our gscreen + * and devdraws screenimage gets freed, the imagedata will + * be released. + */ + *softscreen = 0xa110c; + scr->gscreendata->ref++; + } else + *softscreen = scr->useflush ? 1 : 0; return scr->gscreendata->bdata; } @@ -360,34 +369,27 @@ Memimage *dst, *src, *mask; int m; - if(hwaccel == 0) - return 0; - scr = &vgascreen[0]; if((dst=par->dst) == nil || dst->data == nil) return 0; if((src=par->src) == nil || src->data == nil) - return 0; + src = nil; if((mask=par->mask) == nil || mask->data == nil) + mask = nil; + if(scr->gscreen == nil || scr->gscreendata == nil) return 0; - if(scr->cur == &swcursor){ - /* - * always calling swcursorhide here doesn't cure - * leaving cursor tracks nor failing to refresh menus - * with the latest libmemdraw/draw.c. - */ - if(dst->data->bdata == gscreendata.bdata) + if(dst->data->bdata == scr->gscreendata->bdata) swcursoravoid(par->r); - if(src->data->bdata == gscreendata.bdata) + if(src && src->data->bdata == scr->gscreendata->bdata) swcursoravoid(par->sr); - if(mask->data->bdata == gscreendata.bdata) + if(mask && mask->data->bdata == scr->gscreendata->bdata) swcursoravoid(par->mr); } - - if(dst->data->bdata != gscreendata.bdata) + if(hwaccel == 0) + return 0; + if(dst->data->bdata != scr->gscreendata->bdata || src == nil || mask == nil) return 0; - if(scr->fill==nil && scr->scroll==nil) return 0; @@ -607,29 +609,6 @@ swvisible = 1; } -/* - * Need to lock drawlock for ourselves. - */ -void -swenable(VGAscr*) -{ - swenabled = 1; - if(canqlock(&drawlock)){ - swcursordraw(); - qunlock(&drawlock); - } -} - -void -swdisable(VGAscr*) -{ - swenabled = 0; - if(canqlock(&drawlock)){ - swcursorhide(); - qunlock(&drawlock); - } -} - void swload(VGAscr*, Cursor *curs) { @@ -693,7 +672,7 @@ void swcursorinit(void) { - static int init, warned; + static int init; VGAscr *scr; didswcursorinit = 1; @@ -701,40 +680,54 @@ init = 1; addclock0link(swcursorclock, 10); } - scr = &vgascreen[0]; - if(scr==nil || scr->gscreen==nil) - return; - if(scr->dev == nil || scr->dev->linear == nil){ - if(!warned){ - print("cannot use software cursor on non-linear vga screen\n"); - warned = 1; - } + scr = &vgascreen[0]; + if(scr->gscreen==nil) return; - } if(swback){ freememimage(swback); freememimage(swmask); freememimage(swmask1); freememimage(swimg); - freememimage(swimg1); + freememimage(swimg1); } - swback = allocmemimage(Rect(0,0,32,32), gscreen->chan); swmask = allocmemimage(Rect(0,0,16,16), GREY8); swmask1 = allocmemimage(Rect(0,0,16,16), GREY1); swimg = allocmemimage(Rect(0,0,16,16), GREY8); swimg1 = allocmemimage(Rect(0,0,16,16), GREY1); - if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){ + if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil) print("software cursor: allocmemimage fails"); - return; - } - + memfillcolor(swback, DTransparent); memfillcolor(swmask, DOpaque); memfillcolor(swmask1, DOpaque); memfillcolor(swimg, DBlack); memfillcolor(swimg1, DBlack); +} + +/* + * Need to lock drawlock for ourselves. + */ +void +swenable(VGAscr *scr) +{ + swenabled = 1; + if(canqlock(&drawlock)){ + swload(scr, &arrow); + swcursordraw(); + qunlock(&drawlock); + } +} + +void +swdisable(VGAscr*) +{ + swenabled = 0; + if(canqlock(&drawlock)){ + swcursorhide(); + qunlock(&drawlock); + } } VGAcur swcursor = --- /sys/src/9/port/devdraw.c Mon Mar 14 17:51:04 2011 +++ /sys/src/9/port/devdraw.c Mon Mar 14 17:50:58 2011 @@ -365,7 +365,7 @@ int abb, ar, anbb; Rectangle nbb; - if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r)) + if(screenimage == nil || sdraw.softscreen==0 || !rectclip(&r, screenimage->r)) return; if(flushrect.min.x >= flushrect.max.x){ @@ -413,13 +413,7 @@ combinerect(&flushrect, r); return; } - /* how can this happen? -rsc, dec 12 2002 */ - if(dst == 0){ - print("nil dstflush\n"); - return; - } - l = dst->layer; - if(l == nil) + if(screenimage == nil || dst == nil || (l = dst->layer) == nil) return; do{ if(l->screen->image->data != screenimage->data) @@ -676,12 +670,10 @@ drawfreedimage(dimage->fromname); goto Return; } -// if(dimage->image == screenimage) /* don't free the display */ -// goto Return; ds = dimage->dscreen; if(ds){ l = dimage->image; - if(l->data == screenimage->data) + if(screenimage && l->data == screenimage->data) addflush(l->layer->screenr); if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */ free(l->layer->refreshptr); @@ -929,26 +921,36 @@ Memdata *md; Memimage *i; Rectangle r; + uchar *data; - md = malloc(sizeof *md); - if(md == nil) - return nil; - md->allocd = 1; - md->base = nil; - md->bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen); - if(md->bdata == nil){ - free(md); - return nil; - } - md->ref = 1; - i = allocmemimaged(r, chan, md); - if(i == nil){ - free(md); + if((data = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen)) == nil) return nil; + if(sdraw.softscreen == 0xa110c){ + /* hack: softscreen is memimage. */ + md = *((Memdata**)(data - sizeof(ulong) - sizeof(Memdata*))); + + assert(md->bdata == data); + assert(md->ref > 1); + assert(md->allocd); + + if((i = allocmemimaged(r, chan, md)) == nil){ + md->ref--; + return nil; + } + }else{ + if((md = malloc(sizeof *md)) == nil) + return nil; + md->allocd = 1; + md->base = nil; + md->bdata = data; + md->ref = 1; + if((i = allocmemimaged(r, chan, md)) == nil){ + free(md); + return nil; + } } i->width = width; i->clipr = r; - di = allocdimage(i); if(di == nil){ freememimage(i); /* frees md */ @@ -1859,7 +1861,7 @@ if(pp == nil) error(Enomem); doflush = 0; - if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data)) + if(dstid==0 || (screenimage && dst->layer && dst->layer->screen->image->data == screenimage->data)) doflush = 1; /* simplify test in loop */ ox = oy = 0; esize = 0; @@ -2048,7 +2050,7 @@ memltofrontn(lp, nw); else memltorearn(lp, nw); - if(lp[0]->layer->screen->image->data == screenimage->data) + if(screenimage && lp[0]->layer->screen->image->data == screenimage->data) for(j=0; jlayer->screenr); ll = drawlookup(client, BGLONG(a+1+1+2), 1);