diff --git a/ChangeLog b/ChangeLog index 3f847095..918b6f2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,7 @@ - openslide2vips gets underlying tile size from openslide - embed has 'background' option - dzsave --layout google has a @background option -- use vips_mutex_new()/_free() over g_mutex_new()/_free() +- update for new glib threading API - remove no threads option 2/10/12 started 7.30.4 diff --git a/configure.in b/configure.in index 184df20a..670fc415 100644 --- a/configure.in +++ b/configure.in @@ -318,9 +318,10 @@ AC_CHECK_LIB(m,hypot,[AC_DEFINE(HAVE_HYPOT,1,[have hypot() in libm.])]) PKG_CHECK_MODULES(REQUIRED, glib-2.0 >= 2.6 gmodule-2.0 >= 2.4 libxml-2.0 gobject-2.0) PACKAGES_USED="$PACKAGES_USED glib-2.0 gmodule-2.0 libxml-2.0 gobject-2.0" -# after 2.32 g_mutex_new() becomes g_mutex_init(), annoyingly +# after 2.32 there are a new set of thread functions, annoyingly PKG_CHECK_MODULES(THREADS, glib-2.0 >= 2.32,[ AC_DEFINE(HAVE_MUTEX_INIT,1,[define if your glib has g_mutex_init().]) + AC_DEFINE(HAVE_COND_INIT,1,[define if your glib has g_cond_init().]) ]) # check for gtk-doc diff --git a/libvips/conversion/sequential.c b/libvips/conversion/sequential.c index e99afb65..81b30897 100644 --- a/libvips/conversion/sequential.c +++ b/libvips/conversion/sequential.c @@ -101,7 +101,7 @@ vips_sequential_dispose( GObject *gobject ) VipsSequential *sequential = (VipsSequential *) gobject; VIPS_FREEF( vips_mutex_free, sequential->lock ); - VIPS_FREEF( g_cond_free, sequential->ready ); + VIPS_FREEF( vips_cond_free, sequential->ready ); G_OBJECT_CLASS( vips_sequential_parent_class )->dispose( gobject ); } @@ -135,18 +135,16 @@ vips_sequential_generate( VipsRegion *or, 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 for a short while to give other * threads time to catch up. + * + * The stall can be cancelled by a signal on @ready. */ 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_cond_timed_wait( sequential->ready, + sequential->lock, STALL_TIME * 1000000 ); VIPS_DEBUG_MSG( "thread %p awake again ...\n", g_thread_self() ); } @@ -156,7 +154,8 @@ vips_sequential_generate( VipsRegion *or, * 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. + * skip the initial part of the image. In fact, we read to cache, + * since it may be useful. */ if( r->top > sequential->y_pos ) { VipsRect area; @@ -294,7 +293,7 @@ vips_sequential_init( VipsSequential *sequential ) { sequential->trace = FALSE; sequential->lock = vips_mutex_new(); - sequential->ready = g_cond_new(); + sequential->ready = vips_cond_new(); sequential->tile_height = 1; sequential->error = 0; } diff --git a/libvips/conversion/tilecache.c b/libvips/conversion/tilecache.c index de2128c7..d666c833 100644 --- a/libvips/conversion/tilecache.c +++ b/libvips/conversion/tilecache.c @@ -145,7 +145,7 @@ vips_block_cache_dispose( GObject *gobject ) vips_block_cache_drop_all( cache ); VIPS_FREEF( vips_mutex_free, cache->lock ); - VIPS_FREEF( g_cond_free, cache->new_tile ); + VIPS_FREEF( vips_cond_free, cache->new_tile ); G_OBJECT_CLASS( vips_block_cache_parent_class )->dispose( gobject ); } @@ -490,7 +490,7 @@ vips_block_cache_init( VipsBlockCache *cache ) cache->time = 0; cache->ntiles = 0; cache->lock = vips_mutex_new(); - cache->new_tile = g_cond_new(); + cache->new_tile = vips_cond_new(); cache->tiles = g_hash_table_new_full( (GHashFunc) vips_rect_hash, (GEqualFunc) vips_rect_equal, diff --git a/libvips/include/vips/thread.h b/libvips/include/vips/thread.h index 3a057370..3819a53c 100644 --- a/libvips/include/vips/thread.h +++ b/libvips/include/vips/thread.h @@ -49,6 +49,12 @@ extern "C" { GMutex *vips_mutex_new( void ); void vips_mutex_free( GMutex * ); +/* Same for GCond. And we need a wrapper for waiting too. + */ +GCond *vips_cond_new( void ); +void vips_cond_free( GCond * ); +void vips_cond_timed_wait( GCond *, GMutex *, gint64 ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/iofuncs/semaphore.c b/libvips/iofuncs/semaphore.c index 5ea8184c..57be1e03 100644 --- a/libvips/iofuncs/semaphore.c +++ b/libvips/iofuncs/semaphore.c @@ -59,14 +59,14 @@ vips_semaphore_init( VipsSemaphore *s, int v, char *name ) s->v = v; s->name = name; s->mutex = vips_mutex_new(); - s->cond = g_cond_new(); + s->cond = vips_cond_new(); } void vips_semaphore_destroy( VipsSemaphore *s ) { VIPS_FREEF( vips_mutex_free, s->mutex ); - VIPS_FREEF( g_cond_free, s->cond ); + VIPS_FREEF( vips_cond_free, s->cond ); } /* Add n to the semaphore and signal any threads that are blocked waiting diff --git a/libvips/iofuncs/threadpool.c b/libvips/iofuncs/threadpool.c index 7588de05..ceb35da5 100644 --- a/libvips/iofuncs/threadpool.c +++ b/libvips/iofuncs/threadpool.c @@ -130,6 +130,52 @@ vips_mutex_free( GMutex *mutex ) #endif } +GCond * +vips_cond_new( void ) +{ + GCond *cond; + +#ifdef HAVE_COND_INIT + cond = g_new( GCond, 1 ); + g_cond_init( cond ); +#else + cond = g_cond_new(); +#endif + + return( cond ); +} + +void +vips_cond_free( GCond *cond ) +{ +#ifdef HAVE_COND_INIT + g_cond_clear( cond ); + g_free( cond ); +#else + g_cond_free( cond ); +#endif +} + +/* Wait until cond is signalled, or timeout us have passed. + * + * You can get spurious wakeups, use this in a loop. + */ +void +vips_cond_timed_wait( GCond *cond, GMutex *mutex, gint64 timeout ) +{ +#ifdef HAVE_COND_INIT + gint64 end_time = g_get_monotonic_time() + timeout; + + g_cond_wait_until( cond, mutex, end_time ); +#else + GTimeVal time; + + g_get_current_time( &time ); + g_time_val_add( &time, timeout ); + g_cond_timed_wait( cond, mutex, &time ); +#endif +} + /** * vips_concurrency_set: * @concurrency: number of threads to run