improve vips_sink_screen() shutdown

is now very careful not to do anything to output images after they've
been unreffed ... fixes a crash in vipsdisp
This commit is contained in:
John Cupitt 2015-12-01 13:12:07 +00:00
parent 2409767679
commit c57a03d8a6
2 changed files with 26 additions and 23 deletions

View File

@ -1417,6 +1417,8 @@ vips_image_invalidate_all_cb( VipsImage *image )
void
vips_image_invalidate_all( VipsImage *image )
{
VIPS_DEBUG_MSG( "vips_image_invalidate_all: %p\n", image );
(void) vips__link_map( image, FALSE,
(VipsSListMap2Fn) vips_image_invalidate_all_cb, NULL, NULL );
}

View File

@ -7,6 +7,8 @@
* mem use
* 20/1/14
* - bg render thread quits on shutdown
* 1/12/15
* - don't do anything to out or mask after they have closed
*/
/*
@ -135,6 +137,11 @@ typedef struct _Render {
/* Hash of tiles with positions. Tiles can be dirty or painted.
*/
GHashTable *tiles;
/* A shutdown flag. If ->out or ->mask close, we must no longer do
* anything to them until we shut down too.
*/
gboolean shutdown;
} Render;
/* Our per-thread state.
@ -433,13 +440,16 @@ render_work( VipsThreadState *state, void *a )
/* All downstream images must drop caches, since we've (effectively)
* modified render->out.
*/
vips_image_invalidate_all( render->out );
if( render->mask )
if( !render->shutdown )
vips_image_invalidate_all( render->out );
if( !render->shutdown &&
render->mask )
vips_image_invalidate_all( render->mask );
/* Now clients can update.
*/
if( render->notify )
if( !render->shutdown &&
render->notify )
render->notify( render->out, &tile->area, render->a );
return( 0 );
@ -590,6 +600,13 @@ render_close_cb( VipsImage *image, Render *render )
{
VIPS_DEBUG_MSG_AMBER( "render_close_cb\n" );
/* The output image or mask are closing. This render will stick
* around for a while, since threads can still be running, but it
* must no longer reference ->out or ->mask (for example, invalidating
* them).
*/
render->shutdown = TRUE;
render_unref( render );
/* If this render is being worked on, we want to jog the bg thread,
@ -639,6 +656,8 @@ render_new( VipsImage *in, VipsImage *out, VipsImage *mask,
render->dirty = NULL;
render->shutdown = FALSE;
/* Both out and mask must close before we can free the render.
*/
g_signal_connect( out, "close",
@ -918,20 +937,12 @@ tile_copy( Tile *tile, VipsRegion *to )
}
}
static void *
image_start( IMAGE *out, void *a, void *b )
{
Render *render = (Render *) a;
return( vips_region_new( render->in ) );
}
/* Loop over the output region, filling with data from cache.
*/
static int
image_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
{
Render *render = (Render *) a;
Render *render = (Render *) b;
int tile_width = render->tile_width;
int tile_height = render->tile_height;
VipsRegion *reg = (VipsRegion *) seq;
@ -979,16 +990,6 @@ image_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
return( 0 );
}
static int
image_stop( void *seq, void *a, void *b )
{
VipsRegion *reg = (VipsRegion *) seq;
g_object_unref( reg );
return( 0 );
}
/* The mask image is 255 / 0 for the state of painted for each tile.
*/
static int
@ -1131,7 +1132,7 @@ vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,
VIPS_DEBUG_MSG( "vips_sink_screen: max = %d, %p\n", max_tiles, render );
if( vips_image_generate( out,
image_start, image_fill, image_stop, render, NULL ) )
vips_start_one, image_fill, vips_stop_one, in, render ) )
return( -1 );
if( mask &&
vips_image_generate( mask,