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
- embed has '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
- remove options from format string in .dzi (thanks Martin)
- vipsCC.pc required the wrong version of vips (thanks Alessandro)
- larger max tile size for dzsave
13/9/12 started 7.30.3
- 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)
PACKAGES_USED="$PACKAGES_USED glib-2.0 gmodule-2.0 libxml-2.0 gobject-2.0"
# option to eval without threads
AC_ARG_ENABLE(threads,
AS_HELP_STRING([--enable-threads], [evaluate with threads (default: yes)]))
if test x"$enable_threads" != "xno"; then
AC_DEFINE(HAVE_THREADS,1,[threaded evaluation])
PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
PACKAGES_USED="$PACKAGES_USED gthread-2.0"
enable_threads=yes
fi
# 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().])
AC_DEFINE(HAVE_THREAD_NEW,1,[define if your glib has g_thread_new().])
AC_DEFINE(HAVE_PRIVATE_INIT,1,[define if your glib has G_PRIVATE_INIT().])
AC_DEFINE(HAVE_VALUE_GET_SCHAR,1,[define if your glib has g_value_get_schar().])
])
# check for gtk-doc
GTK_DOC_CHECK(1.9)
@ -734,7 +732,6 @@ native win32: $vips_os_win32
native OS X: $vips_os_darwin
open files in binary mode: $vips_binary_open
enable debug: $enable_debug
evaluate with threads: $enable_threads
build C++ components: $enable_cxx
build docs with gtkdoc: $enable_gtk_doc
gobject introspection: $found_introspection

View File

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

View File

@ -169,7 +169,7 @@ vips_icc_dispose( GObject *gobject )
VIPS_FREEF( cmsDeleteTransform, icc->trans );
VIPS_FREEF( cmsCloseProfile, icc->in_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 );
}
@ -324,7 +324,7 @@ vips_icc_class_init( VipsIccClass *class )
static void
vips_icc_init( VipsIcc *icc )
{
icc->lock = g_mutex_new();
icc->lock = vips_g_mutex_new();
icc->intent = VIPS_INTENT_RELATIVE;
icc->depth = 8;
}

View File

@ -100,8 +100,8 @@ vips_sequential_dispose( GObject *gobject )
{
VipsSequential *sequential = (VipsSequential *) gobject;
VIPS_FREEF( g_mutex_free, sequential->lock );
VIPS_FREEF( g_cond_free, sequential->ready );
VIPS_FREEF( vips_g_mutex_free, sequential->lock );
VIPS_FREEF( vips_g_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_g_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;
@ -293,8 +292,8 @@ static void
vips_sequential_init( VipsSequential *sequential )
{
sequential->trace = FALSE;
sequential->lock = g_mutex_new();
sequential->ready = g_cond_new();
sequential->lock = vips_g_mutex_new();
sequential->ready = vips_g_cond_new();
sequential->tile_height = 1;
sequential->error = 0;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -131,7 +131,7 @@ read_destroy( VipsImage *im, Read *read )
VIPS_FREEF( DestroyImageInfo, read->image_info );
VIPS_FREE( read->frames );
DestroyExceptionInfo( &read->exception );
VIPS_FREEF( g_mutex_free, read->lock );
VIPS_FREEF( vips_g_mutex_free, read->lock );
return( 0 );
}
@ -161,7 +161,7 @@ read_new( const char *filename, VipsImage *im )
read->n_frames = 0;
read->frames = NULL;
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 );

View File

@ -1075,7 +1075,7 @@ write_tif_tilewise( TiffWrite *tw )
return( -1 );
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.
*/
@ -1179,7 +1179,7 @@ free_tiff_write( TiffWrite *tw )
VIPS_FREEF( TIFFClose, tw->tif );
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( vips_free, tw->icc_profile );
}

View File

@ -35,48 +35,21 @@
extern "C" {
#endif /*__cplusplus*/
/* Stack size for each thread. We need to set this explicitly because some
* systems have a very low default.
FIXME ... should have an environment variable for this?
/* We need wrappers over g_mutex_new(), it was replaced by g_mutex_init() in
* glib 2.32+
*/
#define VIPS__DEFAULT_STACK_SIZE (2 * 1024 * 1024)
GMutex *vips_g_mutex_new( void );
void vips_g_mutex_free( GMutex * );
#ifndef HAVE_THREADS
#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().
/* Same for GCond. And we need a wrapper for waiting too.
*/
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 );
gpointer vips__g_thread_join( GThread * );
gpointer vips__g_thread_self( void );
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*/
/* ... and for GThread.
*/
GThread *vips_g_thread_new( const char *, GThreadFunc, gpointer );
#ifdef __cplusplus
}

View File

@ -72,15 +72,8 @@ static GSList *vips__buffers_all = NULL;
static int buffer_cache_n = 0;
#endif /*DEBUG_CREATE*/
#ifdef HAVE_THREADS
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
buffer_cache_free( VipsBufferCache *cache )
{
@ -95,7 +88,6 @@ buffer_cache_free( VipsBufferCache *cache )
VIPS_FREEF( g_hash_table_destroy, cache->hash );
VIPS_FREE( cache );
}
#endif /*HAVE_THREADS*/
static void
buffer_cache_list_free( VipsBufferCacheList *cache_list )
@ -163,16 +155,10 @@ buffer_cache_get( void )
{
VipsBufferCache *cache;
#ifdef HAVE_THREADS
if( !(cache = g_private_get( thread_buffer_cache_key )) ) {
cache = buffer_cache_new();
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 );
}
@ -474,9 +460,14 @@ vips_buffer_print( VipsBuffer *buffer )
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 )
thread_buffer_cache_key = g_private_new(
(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 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
* held in a GParamSpec allowing OBJECT, but the value could be of type
* VipsImage. generics are much faster to compare.
@ -128,7 +136,7 @@ vips_value_hash( GParamSpec *pspec, GValue *value )
if( generic == G_TYPE_PARAM_BOOLEAN )
return( (unsigned int) g_value_get_boolean( value ) );
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 )
return( (unsigned int) g_value_get_uchar( value ) );
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 ) ==
g_value_get_boolean( v2 ) );
else if( generic == G_TYPE_PARAM_CHAR )
return( g_value_get_char( v1 ) ==
g_value_get_char( v2 ) );
return( VIPS_VALUE_GET_CHAR( v1 ) ==
VIPS_VALUE_GET_CHAR( v2 ) );
if( generic == G_TYPE_PARAM_UCHAR )
return( g_value_get_uchar( v1 ) ==
g_value_get_uchar( v2 ) );
@ -416,7 +424,7 @@ void
vips__cache_init( void )
{
if( !vips_cache_table ) {
vips_cache_lock = g_mutex_new();
vips_cache_lock = vips_g_mutex_new();
vips_cache_table = g_hash_table_new(
(GHashFunc) vips_operation_hash,

View File

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

View File

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

View File

@ -240,21 +240,13 @@ vips_tracked_free( void *s )
g_free( s );
}
/* g_mutex_new() is a macro.
*/
static void *
vips_tracked_mutex_new( void *data )
{
return( g_mutex_new() );
}
static void
vips_tracked_init( void )
{
static GOnce vips_tracked_once = G_ONCE_INIT;
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 ) {
vips__object_all = g_hash_table_new(
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;

View File

@ -58,19 +58,15 @@ vips_semaphore_init( VipsSemaphore *s, int v, char *name )
{
s->v = v;
s->name = name;
#ifdef HAVE_THREADS
s->mutex = g_mutex_new();
s->cond = g_cond_new();
#endif /*HAVE_THREADS*/
s->mutex = vips_g_mutex_new();
s->cond = vips_g_cond_new();
}
void
vips_semaphore_destroy( VipsSemaphore *s )
{
#ifdef HAVE_THREADS
VIPS_FREEF( g_mutex_free, s->mutex );
VIPS_FREEF( g_cond_free, s->cond );
#endif /*HAVE_THREADS*/
VIPS_FREEF( vips_g_mutex_free, s->mutex );
VIPS_FREEF( vips_g_cond_free, s->cond );
}
/* 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;
#ifdef HAVE_THREADS
g_mutex_lock( s->mutex );
#endif /*HAVE_THREADS*/
s->v += n;
value_after_op = s->v;
#ifdef HAVE_THREADS
/* 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.
*/
@ -95,7 +89,6 @@ vips_semaphore_upn( VipsSemaphore *s, int n )
else
g_cond_broadcast( s->cond );
g_mutex_unlock( s->mutex );
#endif /*HAVE_THREADS*/
#ifdef DEBUG_IO
printf( "vips_semaphore_upn(\"%s\",%d) = %d\n",
@ -122,16 +115,14 @@ vips_semaphore_downn( VipsSemaphore *s, int n )
{
int value_after_op;
#ifdef HAVE_THREADS
g_mutex_lock( s->mutex );
while( s->v < n )
g_cond_wait( s->cond, s->mutex );
#endif /*HAVE_THREADS*/
s->v -= n;
value_after_op = s->v;
#ifdef HAVE_THREADS
g_mutex_unlock( s->mutex );
#endif /*HAVE_THREADS*/
#ifdef DEBUG_IO
printf( "vips_semaphore_downn(\"%s\",%d): %d\n",

View File

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

View File

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

View File

@ -101,25 +101,104 @@ int vips__thinstrip_height = VIPS__THINSTRIP_HEIGHT;
*/
int vips__concurrency = 0;
#ifndef HAVE_THREADS
/* 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.
/* Glib 2.32 revised the thread API. We need some compat functions.
*/
void vips__g_thread_init( GThreadFunctions *vtable ) {}
gpointer vips__g_thread_join( GThread *dummy ) { return( NULL ); }
gpointer vips__g_thread_self( void ) { return( NULL ); }
GThread *vips__g_thread_create_full( GThreadFunc d1,
gpointer d2, gulong d3, gboolean d4, gboolean d5, GThreadPriority d6,
GError **d7 )
{ return( NULL ); }
GMutex *
vips_g_mutex_new( void )
{
GMutex *mutex;
GMutex *vips__g_mutex_new( void ) { return( NULL ); }
void vips__g_mutex_free( GMutex *d ) {}
void vips__g_mutex_lock( GMutex *d ) {}
void vips__g_mutex_unlock( GMutex *d ) {}
#endif /*!HAVE_THREADS*/
#ifdef HAVE_MUTEX_INIT
mutex = g_new( GMutex, 1 );
g_mutex_init( mutex );
#else
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:
@ -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.
*/
static void *
@ -592,7 +670,6 @@ vips_thread_main_loop( void *a )
return( NULL );
}
#endif /*HAVE_THREADS*/
/* Attach another thread to a threadpool.
*/
@ -628,22 +705,13 @@ vips_thread_new( VipsThreadpool *pool )
}
#endif /*TIME_THREAD*/
#ifdef HAVE_THREADS
/* Make a worker thread. We have to use g_thread_create_full() because
* 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" ) );
if( !(thr->thread = vips_g_thread_new( "worker",
vips_thread_main_loop, thr )) ) {
vips_thread_free( thr );
return( NULL );
}
VIPS_DEBUG_MSG_RED( "vips_thread_new: g_thread_create_full()\n" );
#endif /*HAVE_THREADS*/
VIPS_DEBUG_MSG_RED( "vips_thread_new: vips_g_thread_new()\n" );
return( thr );
}
@ -674,7 +742,7 @@ vips_threadpool_free( VipsThreadpool *pool )
pool->im->filename, 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->tick );
@ -699,7 +767,7 @@ vips_threadpool_new( VipsImage *im )
pool->im = im;
pool->allocate = NULL;
pool->work = NULL;
pool->allocate_lock = g_mutex_new();
pool->allocate_lock = vips_g_mutex_new();
pool->nthr = vips_concurrency_get();
pool->thr = NULL;
vips_semaphore_init( &pool->finish, 0, "finish" );
@ -879,15 +947,9 @@ vips_threadpool_run( VipsImage *im,
}
for(;;) {
#ifdef HAVE_THREADS
/* Wait for a tick from a worker.
*/
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" );

View File

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

View File

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

View File

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