Merge remote-tracking branch 'origin/master' into colour

Conflicts:
	libvips/colour/im_icc_transform.c
This commit is contained in:
John Cupitt 2012-10-25 08:58:17 +01:00
commit 40604e776a
25 changed files with 198 additions and 216 deletions

View File

@ -10,10 +10,13 @@
- openslide2vips gets underlying tile size from openslide - openslide2vips gets underlying tile size from openslide
- embed has 'background' option - embed has 'background' option
- dzsave --layout google has a @background option - dzsave --layout google has a @background option
- update for new glib threading API
- remove no threads option
2/10/12 started 7.30.4 2/10/12 started 7.30.4
- remove options from format string in .dzi (thanks Martin) - remove options from format string in .dzi (thanks Martin)
- vipsCC.pc required the wrong version of vips (thanks Alessandro) - vipsCC.pc required the wrong version of vips (thanks Alessandro)
- larger max tile size for dzsave
13/9/12 started 7.30.3 13/9/12 started 7.30.3
- linecache sized itself too large - linecache sized itself too large

View File

@ -318,16 +318,14 @@ 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) 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" PACKAGES_USED="$PACKAGES_USED glib-2.0 gmodule-2.0 libxml-2.0 gobject-2.0"
# option to eval without threads # after 2.32 there are a new set of thread functions, annoyingly
AC_ARG_ENABLE(threads, PKG_CHECK_MODULES(THREADS, glib-2.0 >= 2.32,[
AS_HELP_STRING([--enable-threads], [evaluate with threads (default: yes)])) 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().])
if test x"$enable_threads" != "xno"; then AC_DEFINE(HAVE_THREAD_NEW,1,[define if your glib has g_thread_new().])
AC_DEFINE(HAVE_THREADS,1,[threaded evaluation]) AC_DEFINE(HAVE_PRIVATE_INIT,1,[define if your glib has G_PRIVATE_INIT().])
PKG_CHECK_MODULES(GTHREAD, gthread-2.0) AC_DEFINE(HAVE_VALUE_GET_SCHAR,1,[define if your glib has g_value_get_schar().])
PACKAGES_USED="$PACKAGES_USED gthread-2.0" ])
enable_threads=yes
fi
# check for gtk-doc # check for gtk-doc
GTK_DOC_CHECK(1.9) GTK_DOC_CHECK(1.9)
@ -734,7 +732,6 @@ native win32: $vips_os_win32
native OS X: $vips_os_darwin native OS X: $vips_os_darwin
open files in binary mode: $vips_binary_open open files in binary mode: $vips_binary_open
enable debug: $enable_debug enable debug: $enable_debug
evaluate with threads: $enable_threads
build C++ components: $enable_cxx build C++ components: $enable_cxx
build docs with gtkdoc: $enable_gtk_doc build docs with gtkdoc: $enable_gtk_doc
gobject introspection: $found_introspection gobject introspection: $found_introspection

View File

@ -39,7 +39,7 @@ $(PDF): $(SRC)
pdflatex vipsmanual.tex pdflatex vipsmanual.tex
pdflatex vipsmanual.tex pdflatex vipsmanual.tex
.PHONEY: html .PHONY: html
html: html:
-rm -rf vipsmanual -rm -rf vipsmanual
mkdir vipsmanual mkdir vipsmanual
@ -48,7 +48,7 @@ html:
-rm vipsmanual/figs/*.svg -rm vipsmanual/figs/*.svg
-rm vipsmanual/*.png -rm vipsmanual/*.png
.PHONEY: clean .PHONY: clean
clean: clean:
-rm -f *.4ct -rm -f *.4ct
-rm -f *.4tc -rm -f *.4tc

View File

@ -169,7 +169,7 @@ vips_icc_dispose( GObject *gobject )
VIPS_FREEF( cmsDeleteTransform, icc->trans ); VIPS_FREEF( cmsDeleteTransform, icc->trans );
VIPS_FREEF( cmsCloseProfile, icc->in_profile ); VIPS_FREEF( cmsCloseProfile, icc->in_profile );
VIPS_FREEF( cmsCloseProfile, icc->out_profile ); VIPS_FREEF( cmsCloseProfile, icc->out_profile );
VIPS_FREEF( g_mutex_free, icc->lock ); VIPS_FREEF( vips_g_mutex_free, icc->lock );
G_OBJECT_CLASS( vips_icc_parent_class )->dispose( gobject ); G_OBJECT_CLASS( vips_icc_parent_class )->dispose( gobject );
} }
@ -324,7 +324,7 @@ vips_icc_class_init( VipsIccClass *class )
static void static void
vips_icc_init( VipsIcc *icc ) vips_icc_init( VipsIcc *icc )
{ {
icc->lock = g_mutex_new(); icc->lock = vips_g_mutex_new();
icc->intent = VIPS_INTENT_RELATIVE; icc->intent = VIPS_INTENT_RELATIVE;
icc->depth = 8; icc->depth = 8;
} }

View File

@ -100,8 +100,8 @@ vips_sequential_dispose( GObject *gobject )
{ {
VipsSequential *sequential = (VipsSequential *) gobject; VipsSequential *sequential = (VipsSequential *) gobject;
VIPS_FREEF( g_mutex_free, sequential->lock ); VIPS_FREEF( vips_g_mutex_free, sequential->lock );
VIPS_FREEF( g_cond_free, sequential->ready ); VIPS_FREEF( vips_g_cond_free, sequential->ready );
G_OBJECT_CLASS( vips_sequential_parent_class )->dispose( gobject ); G_OBJECT_CLASS( vips_sequential_parent_class )->dispose( gobject );
} }
@ -135,18 +135,16 @@ vips_sequential_generate( VipsRegion *or,
if( r->top > sequential->y_pos && if( r->top > sequential->y_pos &&
sequential->y_pos > 0 ) { sequential->y_pos > 0 ) {
GTimeVal time;
/* We have started reading (y_pos > 0) and this request is for /* We have started reading (y_pos > 0) and this request is for
* stuff beyond that, stall for a short while to give other * stuff beyond that, stall for a short while to give other
* threads time to catch up. * 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", VIPS_DEBUG_MSG( "thread %p stalling for up to %gs ...\n",
STALL_TIME, g_thread_self() ); STALL_TIME, g_thread_self() );
g_get_current_time( &time ); vips_g_cond_timed_wait( sequential->ready,
g_time_val_add( &time, STALL_TIME * 1000000 ); sequential->lock, STALL_TIME * 1000000 );
g_cond_timed_wait( sequential->ready,
sequential->lock, &time );
VIPS_DEBUG_MSG( "thread %p awake again ...\n", VIPS_DEBUG_MSG( "thread %p awake again ...\n",
g_thread_self() ); g_thread_self() );
} }
@ -156,7 +154,8 @@ vips_sequential_generate( VipsRegion *or,
* above. * above.
* *
* Probably the operation is something like extract_area and we should * 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 ) { if( r->top > sequential->y_pos ) {
VipsRect area; VipsRect area;
@ -293,8 +292,8 @@ static void
vips_sequential_init( VipsSequential *sequential ) vips_sequential_init( VipsSequential *sequential )
{ {
sequential->trace = FALSE; sequential->trace = FALSE;
sequential->lock = g_mutex_new(); sequential->lock = vips_g_mutex_new();
sequential->ready = g_cond_new(); sequential->ready = vips_g_cond_new();
sequential->tile_height = 1; sequential->tile_height = 1;
sequential->error = 0; sequential->error = 0;
} }

View File

@ -144,8 +144,8 @@ vips_block_cache_dispose( GObject *gobject )
VipsBlockCache *cache = (VipsBlockCache *) gobject; VipsBlockCache *cache = (VipsBlockCache *) gobject;
vips_block_cache_drop_all( cache ); vips_block_cache_drop_all( cache );
VIPS_FREEF( g_mutex_free, cache->lock ); VIPS_FREEF( vips_g_mutex_free, cache->lock );
VIPS_FREEF( g_cond_free, cache->new_tile ); VIPS_FREEF( vips_g_cond_free, cache->new_tile );
G_OBJECT_CLASS( vips_block_cache_parent_class )->dispose( gobject ); G_OBJECT_CLASS( vips_block_cache_parent_class )->dispose( gobject );
} }
@ -489,8 +489,8 @@ vips_block_cache_init( VipsBlockCache *cache )
cache->time = 0; cache->time = 0;
cache->ntiles = 0; cache->ntiles = 0;
cache->lock = g_mutex_new(); cache->lock = vips_g_mutex_new();
cache->new_tile = g_cond_new(); cache->new_tile = vips_g_cond_new();
cache->tiles = g_hash_table_new_full( cache->tiles = g_hash_table_new_full(
(GHashFunc) vips_rect_hash, (GHashFunc) vips_rect_hash,
(GEqualFunc) vips_rect_equal, (GEqualFunc) vips_rect_equal,

View File

@ -105,7 +105,7 @@ tile_destroy( Tile *tile )
static void static void
read_destroy( Read *read ) read_destroy( Read *read )
{ {
IM_FREEF( g_mutex_free, read->lock ); IM_FREEF( vips_g_mutex_free, read->lock );
while( read->cache ) { while( read->cache ) {
Tile *tile = (Tile *) read->cache->data; Tile *tile = (Tile *) read->cache->data;
@ -131,7 +131,7 @@ read_new( IMAGE *in, IMAGE *out,
read->max_tiles = max_tiles; read->max_tiles = max_tiles;
read->time = 0; read->time = 0;
read->ntiles = 0; read->ntiles = 0;
read->lock = g_mutex_new(); read->lock = vips_g_mutex_new();
read->cache = NULL; read->cache = NULL;
if( im_add_close_callback( out, if( im_add_close_callback( out,

View File

@ -1129,7 +1129,7 @@ vips_foreign_save_dz_class_init( VipsForeignSaveDzClass *class )
_( "Tile overlap in pixels" ), _( "Tile overlap in pixels" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveDz, overlap ), G_STRUCT_OFFSET( VipsForeignSaveDz, overlap ),
0, 1024, 0 ); 0, 8192, 0 );
VIPS_ARG_INT( class, "tile_size", 11, VIPS_ARG_INT( class, "tile_size", 11,
_( "Tile size" ), _( "Tile size" ),

View File

@ -133,7 +133,7 @@ static void
vips_fits_close( VipsFits *fits ) vips_fits_close( VipsFits *fits )
{ {
VIPS_FREE( fits->filename ); VIPS_FREE( fits->filename );
VIPS_FREEF( g_mutex_free, fits->lock ); VIPS_FREEF( vips_g_mutex_free, fits->lock );
if( fits->fptr ) { if( fits->fptr ) {
int status; int status;
@ -180,7 +180,7 @@ vips_fits_new_read( const char *filename, VipsImage *out, int band_select )
return( NULL ); return( NULL );
} }
fits->lock = g_mutex_new(); fits->lock = vips_g_mutex_new();
return( fits ); return( fits );
} }
@ -578,7 +578,7 @@ vips_fits_new_write( VipsImage *in, const char *filename )
return( NULL ); return( NULL );
} }
fits->lock = g_mutex_new(); fits->lock = vips_g_mutex_new();
return( fits ); return( fits );
} }

View File

@ -131,7 +131,7 @@ read_destroy( VipsImage *im, Read *read )
VIPS_FREEF( DestroyImageInfo, read->image_info ); VIPS_FREEF( DestroyImageInfo, read->image_info );
VIPS_FREE( read->frames ); VIPS_FREE( read->frames );
DestroyExceptionInfo( &read->exception ); DestroyExceptionInfo( &read->exception );
VIPS_FREEF( g_mutex_free, read->lock ); VIPS_FREEF( vips_g_mutex_free, read->lock );
return( 0 ); return( 0 );
} }
@ -161,7 +161,7 @@ read_new( const char *filename, VipsImage *im )
read->n_frames = 0; read->n_frames = 0;
read->frames = NULL; read->frames = NULL;
read->frame_height = 0; read->frame_height = 0;
read->lock = g_mutex_new(); read->lock = vips_g_mutex_new();
g_signal_connect( im, "close", G_CALLBACK( read_destroy ), read ); g_signal_connect( im, "close", G_CALLBACK( read_destroy ), read );

View File

@ -1075,7 +1075,7 @@ write_tif_tilewise( TiffWrite *tw )
return( -1 ); return( -1 );
g_assert( !tw->write_lock ); g_assert( !tw->write_lock );
tw->write_lock = g_mutex_new(); tw->write_lock = vips_g_mutex_new();
/* Write pyramid too? Only bother if bigger than tile size. /* Write pyramid too? Only bother if bigger than tile size.
*/ */
@ -1179,7 +1179,7 @@ free_tiff_write( TiffWrite *tw )
VIPS_FREEF( TIFFClose, tw->tif ); VIPS_FREEF( TIFFClose, tw->tif );
VIPS_FREEF( vips_free, tw->tbuf ); VIPS_FREEF( vips_free, tw->tbuf );
VIPS_FREEF( g_mutex_free, tw->write_lock ); VIPS_FREEF( vips_g_mutex_free, tw->write_lock );
VIPS_FREEF( free_pyramid, tw->layer ); VIPS_FREEF( free_pyramid, tw->layer );
VIPS_FREEF( vips_free, tw->icc_profile ); VIPS_FREEF( vips_free, tw->icc_profile );
} }

View File

@ -35,48 +35,21 @@
extern "C" { extern "C" {
#endif /*__cplusplus*/ #endif /*__cplusplus*/
/* Stack size for each thread. We need to set this explicitly because some /* We need wrappers over g_mutex_new(), it was replaced by g_mutex_init() in
* systems have a very low default. * glib 2.32+
FIXME ... should have an environment variable for this?
*/ */
#define VIPS__DEFAULT_STACK_SIZE (2 * 1024 * 1024) GMutex *vips_g_mutex_new( void );
void vips_g_mutex_free( GMutex * );
#ifndef HAVE_THREADS /* Same for GCond. And we need a wrapper for waiting too.
#undef g_thread_supported
#define g_thread_supported() (0)
#define g_thread_init vips__g_thread_init
#define g_thread_join vips__g_thread_join
#define g_thread_self vips__g_thread_self
#define g_thread_create_full vips__g_thread_create_full
/* We don't need a shadow imlementation of g_thread_create(), even though we
* use it, because it's just a macro over g_thread_create_full().
*/ */
GCond *vips_g_cond_new( void );
void vips_g_cond_free( GCond * );
void vips_g_cond_timed_wait( GCond *, GMutex *, gint64 );
void vips__g_thread_init( GThreadFunctions *vtable ); /* ... and for GThread.
gpointer vips__g_thread_join( GThread * ); */
gpointer vips__g_thread_self( void ); GThread *vips_g_thread_new( const char *, GThreadFunc, gpointer );
GThread *vips__g_thread_create_full( GThreadFunc,
gpointer, gulong, gboolean, gboolean, GThreadPriority, GError ** );
#undef g_mutex_new
#undef g_mutex_free
#undef g_mutex_lock
#undef g_mutex_unlock
#define g_mutex_new vips__g_mutex_new
#define g_mutex_free vips__g_mutex_free
#define g_mutex_lock vips__g_mutex_lock
#define g_mutex_unlock vips__g_mutex_unlock
GMutex *vips__g_mutex_new( void );
void vips__g_mutex_free( GMutex * );
void vips__g_mutex_lock( GMutex * );
void vips__g_mutex_unlock( GMutex * );
#endif /*!HAVE_THREADS*/
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -72,15 +72,8 @@ static GSList *vips__buffers_all = NULL;
static int buffer_cache_n = 0; static int buffer_cache_n = 0;
#endif /*DEBUG_CREATE*/ #endif /*DEBUG_CREATE*/
#ifdef HAVE_THREADS
static GPrivate *thread_buffer_cache_key = NULL; static GPrivate *thread_buffer_cache_key = NULL;
#else /*!HAVE_THREADS*/
static VipsBufferCache *thread_buffer_cache = NULL;
#endif /*HAVE_THREADS*/
/* Only need this if we're threading and need to do a lot of start/stop.
*/
#ifdef HAVE_THREADS
static void static void
buffer_cache_free( VipsBufferCache *cache ) buffer_cache_free( VipsBufferCache *cache )
{ {
@ -95,7 +88,6 @@ buffer_cache_free( VipsBufferCache *cache )
VIPS_FREEF( g_hash_table_destroy, cache->hash ); VIPS_FREEF( g_hash_table_destroy, cache->hash );
VIPS_FREE( cache ); VIPS_FREE( cache );
} }
#endif /*HAVE_THREADS*/
static void static void
buffer_cache_list_free( VipsBufferCacheList *cache_list ) buffer_cache_list_free( VipsBufferCacheList *cache_list )
@ -163,16 +155,10 @@ buffer_cache_get( void )
{ {
VipsBufferCache *cache; VipsBufferCache *cache;
#ifdef HAVE_THREADS
if( !(cache = g_private_get( thread_buffer_cache_key )) ) { if( !(cache = g_private_get( thread_buffer_cache_key )) ) {
cache = buffer_cache_new(); cache = buffer_cache_new();
g_private_set( thread_buffer_cache_key, cache ); g_private_set( thread_buffer_cache_key, cache );
} }
#else /*!HAVE_THREADS*/
if( !thread_buffer_cache )
thread_buffer_cache = buffer_cache_new();
cache = thread_buffer_cache;
#endif /*HAVE_THREADS*/
return( cache ); return( cache );
} }
@ -474,9 +460,14 @@ vips_buffer_print( VipsBuffer *buffer )
void void
vips__buffer_init( void ) vips__buffer_init( void )
{ {
#ifdef HAVE_THREADS #ifdef HAVE_PRIVATE_INIT
static GPrivate private =
G_PRIVATE_INIT( (GDestroyNotify) buffer_cache_free );
thread_buffer_cache_key = &private;
#else
if( !thread_buffer_cache_key ) if( !thread_buffer_cache_key )
thread_buffer_cache_key = g_private_new( thread_buffer_cache_key = g_private_new(
(GDestroyNotify) buffer_cache_free ); (GDestroyNotify) buffer_cache_free );
#endif /*HAVE_THREADS*/ #endif
} }

View File

@ -112,6 +112,14 @@ static GMutex *vips_cache_lock = NULL;
#define INT64_HASH(X) (g_direct_hash(X)) #define INT64_HASH(X) (g_direct_hash(X))
#define DOUBLE_HASH(X) (g_direct_hash(X)) #define DOUBLE_HASH(X) (g_direct_hash(X))
/* Old glibs use g_value_get_char(), new ones g_value_get_schar().
*/
#ifdef HAVE_VALUE_GET_SCHAR
#define VIPS_VALUE_GET_CHAR g_value_get_schar
#else
#define VIPS_VALUE_GET_CHAR g_value_get_char
#endif
/* Pass in the pspec so we can get the generic type. For example, a /* Pass in the pspec so we can get the generic type. For example, a
* held in a GParamSpec allowing OBJECT, but the value could be of type * held in a GParamSpec allowing OBJECT, but the value could be of type
* VipsImage. generics are much faster to compare. * VipsImage. generics are much faster to compare.
@ -128,7 +136,7 @@ vips_value_hash( GParamSpec *pspec, GValue *value )
if( generic == G_TYPE_PARAM_BOOLEAN ) if( generic == G_TYPE_PARAM_BOOLEAN )
return( (unsigned int) g_value_get_boolean( value ) ); return( (unsigned int) g_value_get_boolean( value ) );
else if( generic == G_TYPE_PARAM_CHAR ) else if( generic == G_TYPE_PARAM_CHAR )
return( (unsigned int) g_value_get_char( value ) ); return( (unsigned int) VIPS_VALUE_GET_CHAR( value ) );
else if( generic == G_TYPE_PARAM_UCHAR ) else if( generic == G_TYPE_PARAM_UCHAR )
return( (unsigned int) g_value_get_uchar( value ) ); return( (unsigned int) g_value_get_uchar( value ) );
else if( generic == G_TYPE_PARAM_INT ) else if( generic == G_TYPE_PARAM_INT )
@ -230,8 +238,8 @@ vips_value_equal( GParamSpec *pspec, GValue *v1, GValue *v2 )
return( g_value_get_boolean( v1 ) == return( g_value_get_boolean( v1 ) ==
g_value_get_boolean( v2 ) ); g_value_get_boolean( v2 ) );
else if( generic == G_TYPE_PARAM_CHAR ) else if( generic == G_TYPE_PARAM_CHAR )
return( g_value_get_char( v1 ) == return( VIPS_VALUE_GET_CHAR( v1 ) ==
g_value_get_char( v2 ) ); VIPS_VALUE_GET_CHAR( v2 ) );
if( generic == G_TYPE_PARAM_UCHAR ) if( generic == G_TYPE_PARAM_UCHAR )
return( g_value_get_uchar( v1 ) == return( g_value_get_uchar( v1 ) ==
g_value_get_uchar( v2 ) ); g_value_get_uchar( v2 ) );
@ -416,7 +424,7 @@ void
vips__cache_init( void ) vips__cache_init( void )
{ {
if( !vips_cache_table ) { if( !vips_cache_table ) {
vips_cache_lock = g_mutex_new(); vips_cache_lock = vips_g_mutex_new();
vips_cache_table = g_hash_table_new( vips_cache_table = g_hash_table_new(
(GHashFunc) vips_operation_hash, (GHashFunc) vips_operation_hash,

View File

@ -241,7 +241,7 @@ vips_image_finalize( GObject *gobject )
*/ */
vips_image_delete( image ); vips_image_delete( image );
VIPS_FREEF( g_mutex_free, image->sslock ); VIPS_FREEF( vips_g_mutex_free, image->sslock );
VIPS_FREE( image->Hist ); VIPS_FREE( image->Hist );
VIPS_FREEF( vips__gslist_gvalue_free, image->history_list ); VIPS_FREEF( vips__gslist_gvalue_free, image->history_list );
@ -1057,7 +1057,7 @@ vips_image_init( VipsImage *image )
image->Yres = 1.0; image->Yres = 1.0;
image->fd = -1; /* since 0 is stdout */ image->fd = -1; /* since 0 is stdout */
image->sslock = g_mutex_new(); image->sslock = vips_g_mutex_new();
image->sizeof_header = VIPS_SIZEOF_HEADER; image->sizeof_header = VIPS_SIZEOF_HEADER;

View File

@ -195,13 +195,13 @@ vips_init( const char *argv0 )
/* Older glibs need this. /* Older glibs need this.
*/ */
#ifdef G_THREADS_ENABLED #ifndef HAVE_THREAD_NEW
if( !g_thread_supported() ) if( !g_thread_supported() )
g_thread_init( NULL ); g_thread_init( NULL );
#endif /*G_THREADS_ENABLED*/ #endif
if( !vips__global_lock ) if( !vips__global_lock )
vips__global_lock = g_mutex_new(); vips__global_lock = vips_g_mutex_new();
VIPS_SETSTR( vips__argv0, argv0 ); VIPS_SETSTR( vips__argv0, argv0 );

View File

@ -240,21 +240,13 @@ vips_tracked_free( void *s )
g_free( s ); g_free( s );
} }
/* g_mutex_new() is a macro.
*/
static void *
vips_tracked_mutex_new( void *data )
{
return( g_mutex_new() );
}
static void static void
vips_tracked_init( void ) vips_tracked_init( void )
{ {
static GOnce vips_tracked_once = G_ONCE_INIT; static GOnce vips_tracked_once = G_ONCE_INIT;
vips_tracked_mutex = g_once( &vips_tracked_once, vips_tracked_mutex = g_once( &vips_tracked_once,
vips_tracked_mutex_new, NULL ); (GThreadFunc) vips_g_mutex_new, NULL );
} }
/** /**

View File

@ -1271,7 +1271,7 @@ vips_object_class_init( VipsObjectClass *class )
if( !vips__object_all ) { if( !vips__object_all ) {
vips__object_all = g_hash_table_new( vips__object_all = g_hash_table_new(
g_direct_hash, g_direct_equal ); g_direct_hash, g_direct_equal );
vips__object_all_lock = g_mutex_new(); vips__object_all_lock = vips_g_mutex_new();
} }
gobject_class->dispose = vips_object_dispose; gobject_class->dispose = vips_object_dispose;

View File

@ -58,19 +58,15 @@ vips_semaphore_init( VipsSemaphore *s, int v, char *name )
{ {
s->v = v; s->v = v;
s->name = name; s->name = name;
#ifdef HAVE_THREADS s->mutex = vips_g_mutex_new();
s->mutex = g_mutex_new(); s->cond = vips_g_cond_new();
s->cond = g_cond_new();
#endif /*HAVE_THREADS*/
} }
void void
vips_semaphore_destroy( VipsSemaphore *s ) vips_semaphore_destroy( VipsSemaphore *s )
{ {
#ifdef HAVE_THREADS VIPS_FREEF( vips_g_mutex_free, s->mutex );
VIPS_FREEF( g_mutex_free, s->mutex ); VIPS_FREEF( vips_g_cond_free, s->cond );
VIPS_FREEF( g_cond_free, s->cond );
#endif /*HAVE_THREADS*/
} }
/* Add n to the semaphore and signal any threads that are blocked waiting /* Add n to the semaphore and signal any threads that are blocked waiting
@ -81,12 +77,10 @@ vips_semaphore_upn( VipsSemaphore *s, int n )
{ {
int value_after_op; int value_after_op;
#ifdef HAVE_THREADS
g_mutex_lock( s->mutex ); g_mutex_lock( s->mutex );
#endif /*HAVE_THREADS*/
s->v += n; s->v += n;
value_after_op = s->v; value_after_op = s->v;
#ifdef HAVE_THREADS
/* If we are only incrementing by one, we only need to wake a single /* If we are only incrementing by one, we only need to wake a single
* thread. If we are incrementing by a lot, we must wake all threads. * thread. If we are incrementing by a lot, we must wake all threads.
*/ */
@ -95,7 +89,6 @@ vips_semaphore_upn( VipsSemaphore *s, int n )
else else
g_cond_broadcast( s->cond ); g_cond_broadcast( s->cond );
g_mutex_unlock( s->mutex ); g_mutex_unlock( s->mutex );
#endif /*HAVE_THREADS*/
#ifdef DEBUG_IO #ifdef DEBUG_IO
printf( "vips_semaphore_upn(\"%s\",%d) = %d\n", printf( "vips_semaphore_upn(\"%s\",%d) = %d\n",
@ -122,16 +115,14 @@ vips_semaphore_downn( VipsSemaphore *s, int n )
{ {
int value_after_op; int value_after_op;
#ifdef HAVE_THREADS
g_mutex_lock( s->mutex ); g_mutex_lock( s->mutex );
while( s->v < n ) while( s->v < n )
g_cond_wait( s->cond, s->mutex ); g_cond_wait( s->cond, s->mutex );
#endif /*HAVE_THREADS*/
s->v -= n; s->v -= n;
value_after_op = s->v; value_after_op = s->v;
#ifdef HAVE_THREADS
g_mutex_unlock( s->mutex ); g_mutex_unlock( s->mutex );
#endif /*HAVE_THREADS*/
#ifdef DEBUG_IO #ifdef DEBUG_IO
printf( "vips_semaphore_downn(\"%s\",%d): %d\n", printf( "vips_semaphore_downn(\"%s\",%d): %d\n",

View File

@ -171,7 +171,6 @@ wbuffer_write( WriteBuffer *wbuffer )
&wbuffer->area, write->a ); &wbuffer->area, write->a );
} }
#ifdef HAVE_THREADS
/* Run this as a thread to do a BG write. /* Run this as a thread to do a BG write.
*/ */
static void * static void *
@ -200,7 +199,6 @@ wbuffer_write_thread( void *data )
return( NULL ); return( NULL );
} }
#endif /*HAVE_THREADS*/
static WriteBuffer * static WriteBuffer *
wbuffer_new( Write *write ) wbuffer_new( Write *write )
@ -227,17 +225,13 @@ wbuffer_new( Write *write )
*/ */
vips__region_no_ownership( wbuffer->region ); vips__region_no_ownership( wbuffer->region );
#ifdef HAVE_THREADS
/* Make this last (picks up parts of wbuffer on startup). /* Make this last (picks up parts of wbuffer on startup).
*/ */
if( !(wbuffer->thread = g_thread_create( wbuffer_write_thread, wbuffer, if( !(wbuffer->thread = vips_g_thread_new( "wbuffer",
TRUE, NULL )) ) { wbuffer_write_thread, wbuffer )) ) {
vips_error( "wbuffer_new",
"%s", _( "unable to create thread" ) );
wbuffer_free( wbuffer ); wbuffer_free( wbuffer );
return( NULL ); return( NULL );
} }
#endif /*HAVE_THREADS*/
return( wbuffer ); return( wbuffer );
} }
@ -266,13 +260,7 @@ wbuffer_flush( Write *write )
/* Set the background writer going for this buffer. /* Set the background writer going for this buffer.
*/ */
#ifdef HAVE_THREADS
vips_semaphore_up( &write->buf->go ); vips_semaphore_up( &write->buf->go );
#else
/* No threads? Write ourselves synchronously.
*/
wbuffer_write( write->buf );
#endif /*HAVE_THREADS*/
return( 0 ); return( 0 );
} }

View File

@ -66,14 +66,6 @@
#include <vips/thread.h> #include <vips/thread.h>
#include <vips/debug.h> #include <vips/debug.h>
/* A have-threads we can test in if().
*/
#ifdef HAVE_THREADS
static const int have_threads = 1;
#else /*!HAVE_THREADS*/
static const int have_threads = 0;
#endif /*HAVE_THREADS*/
#ifdef VIPS_DEBUG_AMBER #ifdef VIPS_DEBUG_AMBER
static int render_num_renders = 0; static int render_num_renders = 0;
#endif /*VIPS_DEBUG_AMBER*/ #endif /*VIPS_DEBUG_AMBER*/
@ -228,8 +220,8 @@ render_free( Render *render )
} }
g_mutex_unlock( render_dirty_lock ); g_mutex_unlock( render_dirty_lock );
g_mutex_free( render->ref_count_lock ); vips_g_mutex_free( render->ref_count_lock );
g_mutex_free( render->lock ); vips_g_mutex_free( render->lock );
vips_slist_map2( render->all, (VipsSListMap2Fn) tile_free, NULL, NULL ); vips_slist_map2( render->all, (VipsSListMap2Fn) tile_free, NULL, NULL );
VIPS_FREEF( g_slist_free, render->all ); VIPS_FREEF( g_slist_free, render->all );
@ -520,23 +512,15 @@ render_thread_main( void *client )
static int static int
render_thread_create( void ) render_thread_create( void )
{ {
if( !have_threads )
return( 0 );
if( !render_dirty_lock ) { if( !render_dirty_lock ) {
render_dirty_lock = g_mutex_new(); render_dirty_lock = vips_g_mutex_new();
vips_semaphore_init( &render_dirty_sem, 0, "render_dirty_sem" ); vips_semaphore_init( &render_dirty_sem, 0, "render_dirty_sem" );
} }
if( !render_thread && have_threads ) { if( !render_thread ) {
if( !(render_thread = g_thread_create_full( if( !(render_thread = vips_g_thread_new( "sink_screen",
render_thread_main, NULL, render_thread_main, NULL )) )
VIPS__DEFAULT_STACK_SIZE, TRUE, FALSE,
G_THREAD_PRIORITY_NORMAL, NULL )) ) {
vips_error( "sink_screen",
"%s", _( "unable to create thread" ) );
return( -1 ); return( -1 );
}
} }
return( 0 ); return( 0 );
@ -595,7 +579,7 @@ render_new( VipsImage *in, VipsImage *out, VipsImage *mask,
return( NULL ); return( NULL );
render->ref_count = 1; render->ref_count = 1;
render->ref_count_lock = g_mutex_new(); render->ref_count_lock = vips_g_mutex_new();
render->in = in; render->in = in;
render->out = out; render->out = out;
@ -607,7 +591,7 @@ render_new( VipsImage *in, VipsImage *out, VipsImage *mask,
render->notify = notify; render->notify = notify;
render->a = a; render->a = a;
render->lock = g_mutex_new(); render->lock = vips_g_mutex_new();
render->all = NULL; render->all = NULL;
render->ntiles = 0; render->ntiles = 0;
@ -746,7 +730,7 @@ tile_queue( Tile *tile, VipsRegion *reg )
tile->painted = FALSE; tile->painted = FALSE;
tile_touch( tile ); tile_touch( tile );
if( render->notify && have_threads ) { if( render->notify ) {
/* Add to the list of renders with dirty tiles. The bg /* Add to the list of renders with dirty tiles. The bg
* thread will pick it up and paint it. It can be already on * thread will pick it up and paint it. It can be already on
* the dirty list. * the dirty list.
@ -755,7 +739,7 @@ tile_queue( Tile *tile, VipsRegion *reg )
render_dirty_put( render ); render_dirty_put( render );
} }
else { else {
/* No threads, or no notify ... paint the tile ourselves /* no notify ... paint the tile ourselves
* sychronously. No need to notify the client since they'll * sychronously. No need to notify the client since they'll
* never see black tiles. * never see black tiles.
*/ */
@ -968,7 +952,6 @@ image_stop( void *seq, void *a, void *b )
static int static int
mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop ) mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
{ {
#ifdef HAVE_THREADS
Render *render = (Render *) a; Render *render = (Render *) a;
VipsRect *r = &out->valid; VipsRect *r = &out->valid;
int x, y; int x, y;
@ -1006,9 +989,6 @@ mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
} }
g_mutex_unlock( render->lock ); g_mutex_unlock( render->lock );
#else /*!HAVE_THREADS*/
vips_region_paint( out, &out->valid, 255 );
#endif /*HAVE_THREADS*/
return( 0 ); return( 0 );
} }

View File

@ -101,25 +101,104 @@ int vips__thinstrip_height = VIPS__THINSTRIP_HEIGHT;
*/ */
int vips__concurrency = 0; int vips__concurrency = 0;
#ifndef HAVE_THREADS /* Glib 2.32 revised the thread API. We need some compat functions.
/* If we're building without gthread, we need stubs for the g_thread_*() and
* g_mutex_*() functions. <vips/thread.h> has #defines which point the g_
* names here.
*/ */
void vips__g_thread_init( GThreadFunctions *vtable ) {} GMutex *
gpointer vips__g_thread_join( GThread *dummy ) { return( NULL ); } vips_g_mutex_new( void )
gpointer vips__g_thread_self( void ) { return( NULL ); } {
GThread *vips__g_thread_create_full( GThreadFunc d1, GMutex *mutex;
gpointer d2, gulong d3, gboolean d4, gboolean d5, GThreadPriority d6,
GError **d7 )
{ return( NULL ); }
GMutex *vips__g_mutex_new( void ) { return( NULL ); } #ifdef HAVE_MUTEX_INIT
void vips__g_mutex_free( GMutex *d ) {} mutex = g_new( GMutex, 1 );
void vips__g_mutex_lock( GMutex *d ) {} g_mutex_init( mutex );
void vips__g_mutex_unlock( GMutex *d ) {} #else
#endif /*!HAVE_THREADS*/ mutex = g_mutex_new();
#endif
return( mutex );
}
void
vips_g_mutex_free( GMutex *mutex )
{
#ifdef HAVE_MUTEX_INIT
g_mutex_clear( mutex );
g_free( mutex );
#else
g_mutex_free( mutex );
#endif
}
GCond *
vips_g_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_g_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_g_cond_timed_wait( GCond *cond, GMutex *mutex, gint64 timeout )
{
#ifdef HAVE_COND_INIT
g_cond_wait_until( cond, mutex,
g_get_monotonic_time() + timeout );
#else
GTimeVal time;
g_get_current_time( &time );
g_time_val_add( &time, timeout );
g_cond_timed_wait( cond, mutex, &time );
#endif
}
GThread *
vips_g_thread_new( const char *domain, GThreadFunc func, gpointer data )
{
GThread *thread;
GError *error = NULL;
#ifdef HAVE_THREAD_NEW
thread = g_thread_try_new( domain, func, data, &error );
#else
thread = g_thread_create( func, data, TRUE, &error );
#endif
if( !thread ) {
if( error ) {
vips_error( domain, "%s", error->message );
g_error_free( error );
}
else
vips_error( domain,
"%s", _( "unable to create thread" ) );
}
return( thread );
}
/** /**
* vips_concurrency_set: * vips_concurrency_set:
@ -564,7 +643,6 @@ vips_thread_work_unit( VipsThread *thr )
} }
} }
#ifdef HAVE_THREADS
/* What runs as a thread ... loop, waiting to be told to do stuff. /* What runs as a thread ... loop, waiting to be told to do stuff.
*/ */
static void * static void *
@ -592,7 +670,6 @@ vips_thread_main_loop( void *a )
return( NULL ); return( NULL );
} }
#endif /*HAVE_THREADS*/
/* Attach another thread to a threadpool. /* Attach another thread to a threadpool.
*/ */
@ -628,22 +705,13 @@ vips_thread_new( VipsThreadpool *pool )
} }
#endif /*TIME_THREAD*/ #endif /*TIME_THREAD*/
#ifdef HAVE_THREADS if( !(thr->thread = vips_g_thread_new( "worker",
/* Make a worker thread. We have to use g_thread_create_full() because vips_thread_main_loop, thr )) ) {
* we need to insist on a non-tiny stack. Some platforms default to
* very small values (eg. various BSDs).
*/
if( !(thr->thread = g_thread_create_full( vips_thread_main_loop, thr,
VIPS__DEFAULT_STACK_SIZE, TRUE, FALSE,
G_THREAD_PRIORITY_NORMAL, NULL )) ) {
vips_error( "vips_thread_new",
"%s", _( "unable to create thread" ) );
vips_thread_free( thr ); vips_thread_free( thr );
return( NULL ); return( NULL );
} }
VIPS_DEBUG_MSG_RED( "vips_thread_new: g_thread_create_full()\n" ); VIPS_DEBUG_MSG_RED( "vips_thread_new: vips_g_thread_new()\n" );
#endif /*HAVE_THREADS*/
return( thr ); return( thr );
} }
@ -674,7 +742,7 @@ vips_threadpool_free( VipsThreadpool *pool )
pool->im->filename, pool ); pool->im->filename, pool );
vips_threadpool_kill_threads( pool ); vips_threadpool_kill_threads( pool );
VIPS_FREEF( g_mutex_free, pool->allocate_lock ); VIPS_FREEF( vips_g_mutex_free, pool->allocate_lock );
vips_semaphore_destroy( &pool->finish ); vips_semaphore_destroy( &pool->finish );
vips_semaphore_destroy( &pool->tick ); vips_semaphore_destroy( &pool->tick );
@ -699,7 +767,7 @@ vips_threadpool_new( VipsImage *im )
pool->im = im; pool->im = im;
pool->allocate = NULL; pool->allocate = NULL;
pool->work = NULL; pool->work = NULL;
pool->allocate_lock = g_mutex_new(); pool->allocate_lock = vips_g_mutex_new();
pool->nthr = vips_concurrency_get(); pool->nthr = vips_concurrency_get();
pool->thr = NULL; pool->thr = NULL;
vips_semaphore_init( &pool->finish, 0, "finish" ); vips_semaphore_init( &pool->finish, 0, "finish" );
@ -879,15 +947,9 @@ vips_threadpool_run( VipsImage *im,
} }
for(;;) { for(;;) {
#ifdef HAVE_THREADS
/* Wait for a tick from a worker. /* Wait for a tick from a worker.
*/ */
vips_semaphore_down( &pool->tick ); vips_semaphore_down( &pool->tick );
#else
/* No threads, do the work ourselves in the main thread.
*/
vips_thread_work_unit( pool->thr[0] );
#endif /*HAVE_THREADS*/
VIPS_DEBUG_MSG( "vips_threadpool_run: tick\n" ); VIPS_DEBUG_MSG( "vips_threadpool_run: tick\n" );

View File

@ -680,7 +680,7 @@ lr_blend_labpack( REGION *or, MergeInfo *inf, Overlapping *ovlap, Rect *oreg )
static void * static void *
lock_free( GMutex *lock ) lock_free( GMutex *lock )
{ {
g_mutex_free( lock ); vips_g_mutex_free( lock );
return( NULL ); return( NULL );
} }
@ -767,10 +767,10 @@ im__build_mergestate( const char *domain,
for( x = 0; x < ovlap->flsize; x++ ) for( x = 0; x < ovlap->flsize; x++ )
ovlap->first[x] = -1; ovlap->first[x] = -1;
ovlap->fl_lock = g_mutex_new(); ovlap->fl_lock = vips_g_mutex_new();
if( im_add_close_callback( out, if( im_add_close_callback( out,
(im_callback_fn) lock_free, ovlap->fl_lock, NULL ) ) { (im_callback_fn) lock_free, ovlap->fl_lock, NULL ) ) {
g_mutex_free( ovlap->fl_lock ); vips_g_mutex_free( ovlap->fl_lock );
return( NULL ); return( NULL );
} }

View File

@ -24,7 +24,6 @@ libvipsCC_la_LIBADD = \
# swap the 'awk' line for this: # swap the 'awk' line for this:
# awk '{if($$1!="deprecated") print $$1}'` ; \ # awk '{if($$1!="deprecated") print $$1}'` ; \
# to not generate the wrappers for deprecated functions # to not generate the wrappers for deprecated functions
.PHONEY:
vipsc++.cc: vipsc++.cc:
packages=`vips list packages | \ packages=`vips list packages | \
awk '{print $$1}'` ; \ awk '{print $$1}'` ; \

View File

@ -10,7 +10,6 @@ pkginclude_HEADERS = \
# swap the 'awk' line for this: # swap the 'awk' line for this:
# awk '{if($$1!="deprecated") print $$1}'` ; \ # awk '{if($$1!="deprecated") print $$1}'` ; \
# to not generate the wrappers for deprecated functions # to not generate the wrappers for deprecated functions
.PHONEY:
vipsc++.h: vipsc++.h:
packages=`vips list packages | \ packages=`vips list packages | \
awk '{print $$1}'` ; \ awk '{print $$1}'` ; \