diff --git a/ChangeLog b/ChangeLog index bcdb7325..ac292ef3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ 31/8/12 started 7.31.0 - work on moving colour to vips8 +4/9/12 started 7.30.2 +- sequential stops all threads on error +- sequential delays ahead threads rather than blocking them completely + 6/8/12 started 7.30.1 - fixes to dzsave: shrink down to a 1x1 pixel tile, round image size up on shrink, write a .dzi file with the pyramid params, default tile size and @@ -51,10 +55,7 @@ - png save compression range was wrong - more/moreeq was wrong - vips7 ppm save with options was broken -<<<<<<< HEAD -======= - don't cache write operations ->>>>>>> origin/master 18/6/12 started 7.28.9 - slightly more memory debugging output diff --git a/TODO b/TODO index 5ce56da5..450a4566 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ colour -====== colour operations: @@ -72,7 +71,6 @@ how about a base colour class with 1 in, 1 out, - blocking bugs ============= diff --git a/libvips/conversion/embed.c b/libvips/conversion/embed.c index e90203a9..81641b2e 100644 --- a/libvips/conversion/embed.c +++ b/libvips/conversion/embed.c @@ -402,12 +402,11 @@ vips_embed_build( VipsObject *object ) if( vips_image_copy_fields( conversion->out, embed->in ) ) return( -1 ); - /* embed is used in many places. SMALLTILE would force most - * pipelines into SMALLTILE mode, so stick with THINSTRIP, - * even though SMALLTILE might be a little faster for us. + /* embed is used in many places. We don't really care about + * geometry, so use ANY to avoid disturbing all pipelines. */ vips_demand_hint( conversion->out, - VIPS_DEMAND_STYLE_FATSTRIP, embed->in, NULL ); + VIPS_DEMAND_STYLE_ANY, embed->in, NULL ); conversion->out->Xsize = embed->width; conversion->out->Ysize = embed->height; diff --git a/libvips/conversion/insert.c b/libvips/conversion/insert.c index eb74ddb3..be73b7db 100644 --- a/libvips/conversion/insert.c +++ b/libvips/conversion/insert.c @@ -285,7 +285,7 @@ vips_insert_build( VipsObject *object ) if( vips_image_copy_fields_array( conversion->out, arry ) ) return( -1 ); vips_demand_hint_array( conversion->out, - VIPS_DEMAND_STYLE_SMALLTILE, arry ); + VIPS_DEMAND_STYLE_ANY, arry ); /* Calculate geometry. */ diff --git a/libvips/conversion/sequential.c b/libvips/conversion/sequential.c index 09865122..1056a4f7 100644 --- a/libvips/conversion/sequential.c +++ b/libvips/conversion/sequential.c @@ -13,6 +13,9 @@ * - remove skip forward, instead do thread stalling and have an * integrated cache * - use linecache + * 4/9/12 + * - stop all threads on error + * - don't stall forever, just delay ahead threads */ /* @@ -60,6 +63,10 @@ #include "conversion.h" +/* Stall threads that run ahead for this long, in seconds. + */ +#define STALL_TIME (0.1) + typedef struct _VipsSequential { VipsConversion parent_instance; @@ -77,6 +84,11 @@ typedef struct _VipsSequential { * when we start. */ int y_pos; + + /* If one thread gets an error, we must stop all threads, otherwise we + * can stall and never wake. + */ + int error; } VipsSequential; typedef VipsConversionClass VipsSequentialClass; @@ -109,27 +121,41 @@ vips_sequential_generate( VipsRegion *or, vips_diag( "VipsSequential", "request for %d lines, starting at line %d", r->height, r->top ); -retry: g_mutex_lock( sequential->lock ); VIPS_DEBUG_MSG( "thread %p has lock ...\n", g_thread_self() ); + /* If we've seen an error, everything must stop. + */ + if( sequential->error ) { + g_mutex_unlock( sequential->lock ); + return( -1 ); + } + if( r->top > sequential->y_pos && sequential->y_pos > 0 ) { + GTimeVal time; + /* We have started reading (y_pos > 0) and this request is for - * stuff beyond that, stall. + * stuff beyond that, stall for a short while to give other + * threads time to catch up. */ - VIPS_DEBUG_MSG( "thread %p stalling ...\n", g_thread_self() ); - g_cond_wait( sequential->ready, sequential->lock ); - VIPS_DEBUG_MSG( "thread %p awake again, retrying ...\n", + VIPS_DEBUG_MSG( "thread %p stalling for up to %gs ...\n", + STALL_TIME, g_thread_self() ); + g_get_current_time( &time ); + g_time_val_add( &time, STALL_TIME * 1000000 ); + g_cond_timed_wait( sequential->ready, + sequential->lock, &time ); + VIPS_DEBUG_MSG( "thread %p awake again ...\n", g_thread_self() ); - g_mutex_unlock( sequential->lock ); - goto retry; } /* This is a request for something some way down the image, and we've - * not read anything yet. Probably the operation is something like + * either not read anything yet or fallen through from the stall + * above. + * + * Probably the operation is something like * extract_area and we should skip the initial part of the image. In * fact we read to cache. */ @@ -144,8 +170,14 @@ retry: area.top = sequential->y_pos; area.width = 1; area.height = r->top - sequential->y_pos; - if( vips_region_prepare( ir, &area ) ) + if( vips_region_prepare( ir, &area ) ) { + VIPS_DEBUG_MSG( "thread %p error, unlocking ...\n", + g_thread_self() ); + sequential->error = -1; + g_cond_broadcast( sequential->ready ); + g_mutex_unlock( sequential->lock ); return( -1 ); + } sequential->y_pos = VIPS_RECT_BOTTOM( &area ); } @@ -156,7 +188,10 @@ retry: VIPS_DEBUG_MSG( "thread %p reading ...\n", g_thread_self() ); if( vips_region_prepare( ir, r ) || vips_region_region( or, ir, r, r->left, r->top ) ) { - VIPS_DEBUG_MSG( "thread %p unlocking ...\n", g_thread_self() ); + VIPS_DEBUG_MSG( "thread %p error, unlocking ...\n", + g_thread_self() ); + sequential->error = -1; + g_cond_broadcast( sequential->ready ); g_mutex_unlock( sequential->lock ); return( -1 ); } @@ -262,6 +297,7 @@ vips_sequential_init( VipsSequential *sequential ) sequential->lock = g_mutex_new(); sequential->ready = g_cond_new(); sequential->tile_height = 1; + sequential->error = 0; } /** diff --git a/libvips/deprecated/im_tile_cache.c b/libvips/deprecated/im_tile_cache.c index f5ee9c75..1fdc7b89 100644 --- a/libvips/deprecated/im_tile_cache.c +++ b/libvips/deprecated/im_tile_cache.c @@ -401,7 +401,7 @@ im_tile_cache( IMAGE *in, IMAGE *out, if( im_piocheck( in, out ) || im_cp_desc( out, in ) || - im_demand_hint( out, IM_SMALLTILE, in, NULL ) || + im_demand_hint( out, IM_ANY, in, NULL ) || !(read = read_new( in, out, tile_width, tile_height, max_tiles )) || im_generate( out, diff --git a/libvips/iofuncs/generate.c b/libvips/iofuncs/generate.c index 24f55717..3aae1068 100644 --- a/libvips/iofuncs/generate.c +++ b/libvips/iofuncs/generate.c @@ -325,7 +325,7 @@ vips_demand_hint_array( VipsImage *image, VipsDemandStyle hint, VipsImage **in ) #ifdef DEBUG printf( "vips_demand_hint_array: set dhint for \"%s\" to %s\n", - im->filename, + image->filename, vips_enum_nick( VIPS_TYPE_DEMAND_STYLE, image->dhint ) ); printf( "\toperation requested %s\n", vips_enum_nick( VIPS_TYPE_DEMAND_STYLE, hint ) ); diff --git a/tools/vipsthumbnail.c b/tools/vipsthumbnail.c index 67f034c4..17e0cc0b 100644 --- a/tools/vipsthumbnail.c +++ b/tools/vipsthumbnail.c @@ -48,7 +48,7 @@ static int thumbnail_size = 128; static char *output_format = "tn_%s.jpg"; -static char *interpolator = "bilinear";; +static char *interpolator = "bilinear"; static gboolean nosharpen = FALSE; static char *export_profile = NULL; static char *import_profile = NULL;