fix the bg render thread in sinkscreen
it could exit under heavy load, resulting in black everywhere ... now let it exit when there's no work, and restart next time a dirty tile appears
This commit is contained in:
parent
c57a03d8a6
commit
8ebed8fe03
6
TODO
6
TODO
@ -1,6 +1,12 @@
|
||||
- get some brightly coloured spots with nohalo / vsqbs on wobble.ws ... very
|
||||
odd, the interpolation shouldn't change between bands
|
||||
|
||||
- try:
|
||||
|
||||
$ ./test_resample.py TestResample.test_mapim
|
||||
** VIPS:ERROR:interpolate.c:518:vips_interpolate_bilinear_interpolate: assertion failed: ((int) x + 1 < VIPS_RECT_RIGHT( &in->valid ))
|
||||
Aborted (core dumped)
|
||||
|
||||
- still not happy about float->int mask conversion in im_vips2mask.c
|
||||
|
||||
- looks like we have a race in tiled threadcache? see
|
||||
|
@ -193,7 +193,7 @@ vips__link_break_all( VipsImage *image )
|
||||
|
||||
typedef struct _LinkMap {
|
||||
gboolean upstream;
|
||||
int *serial;
|
||||
int serial;
|
||||
VipsSListMap2Fn fn;
|
||||
void *a;
|
||||
void *b;
|
||||
@ -206,9 +206,9 @@ vips__link_mapp( VipsImage *image, LinkMap *map )
|
||||
|
||||
/* Loop?
|
||||
*/
|
||||
if( image->serial == *map->serial )
|
||||
if( image->serial == map->serial )
|
||||
return( NULL );
|
||||
image->serial = *map->serial;
|
||||
image->serial = map->serial;
|
||||
|
||||
if( (res = map->fn( image, map->a, map->b )) )
|
||||
return( res );
|
||||
@ -240,8 +240,6 @@ vips__link_map( VipsImage *image, gboolean upstream,
|
||||
GSList *p;
|
||||
void *result;
|
||||
|
||||
serial += 1;
|
||||
|
||||
images = NULL;
|
||||
|
||||
/* The function might do anything, including removing images
|
||||
@ -251,13 +249,19 @@ vips__link_map( VipsImage *image, gboolean upstream,
|
||||
*/
|
||||
|
||||
map.upstream = upstream;
|
||||
map.serial = &serial;
|
||||
map.fn = (VipsSListMap2Fn) vips__link_map_cb;
|
||||
map.a = (void *) &images;
|
||||
map.b = NULL;
|
||||
|
||||
/* We will be walking the tree of images and updating the ->serial
|
||||
* member. There will be intense confusion if two threads try to do
|
||||
* this at the same time.
|
||||
*/
|
||||
g_mutex_lock( vips__global_lock );
|
||||
|
||||
serial += 1;
|
||||
map.serial = serial;
|
||||
|
||||
vips__link_mapp( image, &map );
|
||||
|
||||
for( p = images; p; p = p->next )
|
||||
|
@ -9,6 +9,7 @@
|
||||
* - bg render thread quits on shutdown
|
||||
* 1/12/15
|
||||
* - don't do anything to out or mask after they have closed
|
||||
* - only run the bg render thread when there's work to do
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -165,10 +166,6 @@ G_DEFINE_TYPE( RenderThreadState, render_thread_state, VIPS_TYPE_THREAD_STATE );
|
||||
*/
|
||||
static GThread *render_thread = NULL;
|
||||
|
||||
/* Number of renders with dirty tiles. render_thread queues up on this.
|
||||
*/
|
||||
static VipsSemaphore render_dirty_sem;
|
||||
|
||||
/* Set this to ask the render thread to quit.
|
||||
*/
|
||||
static gboolean render_kill = FALSE;
|
||||
@ -224,14 +221,8 @@ render_free( Render *render )
|
||||
g_assert( render->ref_count == 0 );
|
||||
|
||||
g_mutex_lock( render_dirty_lock );
|
||||
if( g_slist_find( render_dirty_all, render ) ) {
|
||||
if( g_slist_find( render_dirty_all, render ) )
|
||||
render_dirty_all = g_slist_remove( render_dirty_all, render );
|
||||
|
||||
/* We could vips_semaphore_upn( &render_dirty_sem, -1 ), but
|
||||
* what's the point. We'd just wake up the bg thread
|
||||
* for no reason.
|
||||
*/
|
||||
}
|
||||
g_mutex_unlock( render_dirty_lock );
|
||||
|
||||
vips_g_mutex_free( render->ref_count_lock );
|
||||
@ -282,22 +273,16 @@ render_unref( Render *render )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Wait for a render with dirty tiles.
|
||||
/* Get the first render with dirty tiles.
|
||||
*/
|
||||
static Render *
|
||||
render_dirty_get( void )
|
||||
{
|
||||
Render *render;
|
||||
|
||||
/* Wait for a render with dirty tiles.
|
||||
*/
|
||||
vips_semaphore_down( &render_dirty_sem );
|
||||
|
||||
g_mutex_lock( render_dirty_lock );
|
||||
|
||||
/* Just take the head of the jobs list ... we sort when we add. If
|
||||
* render_free() is called between our semaphore letting us in
|
||||
* and the _lock(), render_dirty_all can be NULL.
|
||||
/* Just take the head of the jobs list ... we sort when we add.
|
||||
*/
|
||||
render = NULL;
|
||||
if( render_dirty_all ) {
|
||||
@ -455,39 +440,7 @@ render_work( VipsThreadState *state, void *a )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
render_dirty_sort( Render *a, Render *b )
|
||||
{
|
||||
return( b->priority - a->priority );
|
||||
}
|
||||
|
||||
/* Add to the jobs list, if it has work to be done.
|
||||
*/
|
||||
static void
|
||||
render_dirty_put( Render *render )
|
||||
{
|
||||
g_mutex_lock( render_dirty_lock );
|
||||
|
||||
if( render->dirty ) {
|
||||
if( !g_slist_find( render_dirty_all, render ) ) {
|
||||
render_dirty_all = g_slist_prepend( render_dirty_all,
|
||||
render );
|
||||
render_dirty_all = g_slist_sort( render_dirty_all,
|
||||
(GCompareFunc) render_dirty_sort );
|
||||
|
||||
/* Ask the bg thread to stop and reschedule, if it's
|
||||
* running.
|
||||
*/
|
||||
VIPS_DEBUG_MSG_GREEN( "render_dirty_put: "
|
||||
"reschedule\n" );
|
||||
render_reschedule = TRUE;
|
||||
|
||||
vips_semaphore_up( &render_dirty_sem );
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock( render_dirty_lock );
|
||||
}
|
||||
static void render_dirty_put( Render *render );
|
||||
|
||||
/* Main loop for RenderThreads.
|
||||
*/
|
||||
@ -525,9 +478,15 @@ render_thread_main( void *client )
|
||||
render_unref( render );
|
||||
}
|
||||
|
||||
/* We are exiting, so render_thread must now be NULL.
|
||||
*/
|
||||
render_thread = NULL;
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/* Called from vips_shutdown().
|
||||
*/
|
||||
void
|
||||
vips__render_shutdown( void )
|
||||
{
|
||||
@ -542,36 +501,52 @@ vips__render_shutdown( void )
|
||||
GThread *thread;
|
||||
|
||||
thread = render_thread;
|
||||
render_thread = NULL;
|
||||
|
||||
g_mutex_unlock( render_dirty_lock );
|
||||
|
||||
render_reschedule = TRUE;
|
||||
render_kill = TRUE;
|
||||
vips_semaphore_up( &render_dirty_sem );
|
||||
(void) g_thread_join( thread );
|
||||
}
|
||||
else
|
||||
g_mutex_unlock( render_dirty_lock );
|
||||
}
|
||||
|
||||
/* Create our set of RenderThread. Assume we're single-threaded here.
|
||||
*/
|
||||
static int
|
||||
render_thread_create( void )
|
||||
static int
|
||||
render_dirty_sort( Render *a, Render *b )
|
||||
{
|
||||
if( !render_dirty_lock ) {
|
||||
render_dirty_lock = vips_g_mutex_new();
|
||||
vips_semaphore_init( &render_dirty_sem, 0, "render_dirty_sem" );
|
||||
return( b->priority - a->priority );
|
||||
}
|
||||
|
||||
/* Add to the jobs list, if it has work to be done.
|
||||
*/
|
||||
static void
|
||||
render_dirty_put( Render *render )
|
||||
{
|
||||
g_mutex_lock( render_dirty_lock );
|
||||
|
||||
if( render->dirty ) {
|
||||
if( !g_slist_find( render_dirty_all, render ) ) {
|
||||
render_dirty_all = g_slist_prepend( render_dirty_all,
|
||||
render );
|
||||
render_dirty_all = g_slist_sort( render_dirty_all,
|
||||
(GCompareFunc) render_dirty_sort );
|
||||
|
||||
/* Make sure there is a bg render thread, and get it to
|
||||
* reschedule.
|
||||
*/
|
||||
if( !render_thread ) {
|
||||
render_thread = vips_g_thread_new( "sink_screen",
|
||||
render_thread_main, NULL );
|
||||
g_assert( render_thread );
|
||||
}
|
||||
VIPS_DEBUG_MSG_GREEN( "render_dirty_put: "
|
||||
"reschedule\n" );
|
||||
render_reschedule = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if( !render_thread ) {
|
||||
if( !(render_thread = vips_g_thread_new( "sink_screen",
|
||||
render_thread_main, NULL )) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
g_mutex_unlock( render_dirty_lock );
|
||||
}
|
||||
|
||||
static guint
|
||||
@ -1039,6 +1014,12 @@ mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_sink_screen_init( void )
|
||||
{
|
||||
render_dirty_lock = vips_g_mutex_new();
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_sink_screen:
|
||||
* @in: input image
|
||||
@ -1096,12 +1077,11 @@ vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,
|
||||
int priority,
|
||||
VipsSinkNotify notify_fn, void *a )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
Render *render;
|
||||
|
||||
/* Make sure the bg work threads are ready.
|
||||
*/
|
||||
if( render_thread_create() )
|
||||
return( -1 );
|
||||
g_once( &once, (GThreadFunc) vips_sink_screen_init, NULL );
|
||||
|
||||
if( tile_width <= 0 || tile_height <= 0 ||
|
||||
max_tiles < -1 ) {
|
||||
|
Loading…
Reference in New Issue
Block a user