group all non-worker buffers

have a single place to keep all non-worker buffers, and guard it with a
lock
This commit is contained in:
John Cupitt 2016-10-11 10:47:01 +01:00
parent ccfe4cb215
commit 7883e30d68

View File

@ -84,8 +84,15 @@ static GSList *vips__buffer_cache_all = NULL;
*/ */
static const int buffer_cache_max_reserve = 2; static const int buffer_cache_max_reserve = 2;
/* Workers have a buffer_thread in a GPrivate they have exclusive access to.
*/
static GPrivate *buffer_thread_key = NULL; static GPrivate *buffer_thread_key = NULL;
/* All non-worker threads share a single global set of buffers protected by a
* mutex.
*/
static VipsBufferThread *vips_buffer_thread_global = NULL;
#ifdef DEBUG #ifdef DEBUG
static void * static void *
vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive ) vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive )
@ -176,6 +183,8 @@ vips_buffer_free( VipsBuffer *buffer )
static void static void
buffer_thread_free( VipsBufferThread *buffer_thread ) buffer_thread_free( VipsBufferThread *buffer_thread )
{ {
/* We only come here from workers, so no need to lock.
*/
VIPS_FREEF( g_hash_table_destroy, buffer_thread->hash ); VIPS_FREEF( g_hash_table_destroy, buffer_thread->hash );
VIPS_FREE( buffer_thread ); VIPS_FREE( buffer_thread );
} }
@ -236,7 +245,14 @@ buffer_cache_image_postclose( VipsImage *im, VipsBufferCache *cache )
g_assert( cache->im == im ); g_assert( cache->im == im );
g_assert( !vips_thread_isworker() ); g_assert( !vips_thread_isworker() );
/* All non-worker threads come through here, so we need to lock around
* changes to the global buffer_thread.
*/
g_mutex_lock( vips__global_lock );
g_hash_table_remove( buffer_thread->hash, im ); g_hash_table_remove( buffer_thread->hash, im );
g_mutex_unlock( vips__global_lock );
} }
static VipsBufferCache * static VipsBufferCache *
@ -257,7 +273,7 @@ buffer_cache_new( VipsBufferThread *buffer_thread, VipsImage *im )
* from the main thread, since (obviously) thread shutdown will never * from the main thread, since (obviously) thread shutdown will never
* happen. In this case, we need to free resources on image close. * happen. In this case, we need to free resources on image close.
*/ */
if( !vips_thread_isworker() ) if( !vips_thread_isworker() )
g_signal_connect( im, "postclose", g_signal_connect( im, "postclose",
G_CALLBACK( buffer_cache_image_postclose ), cache ); G_CALLBACK( buffer_cache_image_postclose ), cache );
@ -295,12 +311,32 @@ buffer_thread_get( void )
{ {
VipsBufferThread *buffer_thread; VipsBufferThread *buffer_thread;
if( !(buffer_thread = g_private_get( buffer_thread_key )) ) { if( vips_thread_isworker() ) {
buffer_thread = buffer_thread_new(); /* Workers get a private set of buffers.
g_private_set( buffer_thread_key, buffer_thread ); */
} if( !(buffer_thread = g_private_get( buffer_thread_key )) ) {
buffer_thread = buffer_thread_new();
g_private_set( buffer_thread_key, buffer_thread );
}
g_assert( buffer_thread->thread == g_thread_self() ); g_assert( buffer_thread->thread == g_thread_self() );
}
else {
/* All main threads share a single set of buffers.
*/
g_mutex_lock( vips__global_lock );
if( !vips_buffer_thread_global ) {
vips_buffer_thread_global = buffer_thread_new();
/* Shared by many threads, so no checking.
*/
vips_buffer_thread_global->thread = NULL;
}
buffer_thread = vips_buffer_thread_global;
g_mutex_unlock( vips__global_lock );
}
return( buffer_thread ); return( buffer_thread );
} }
@ -312,13 +348,20 @@ buffer_cache_get( VipsImage *im )
VipsBufferCache *cache; VipsBufferCache *cache;
if( !vips_thread_isworker() )
g_mutex_lock( vips__global_lock );
if( !(cache = (VipsBufferCache *) if( !(cache = (VipsBufferCache *)
g_hash_table_lookup( buffer_thread->hash, im )) ) { g_hash_table_lookup( buffer_thread->hash, im )) ) {
cache = buffer_cache_new( buffer_thread, im ); cache = buffer_cache_new( buffer_thread, im );
g_hash_table_insert( buffer_thread->hash, im, cache ); g_hash_table_insert( buffer_thread->hash, im, cache );
} }
g_assert( cache->thread == g_thread_self() ); if( !vips_thread_isworker() )
g_mutex_unlock( vips__global_lock );
g_assert( !cache->thread ||
cache->thread == g_thread_self() );
return( cache ); return( cache );
} }
@ -362,8 +405,10 @@ vips_buffer_undone( VipsBuffer *buffer )
g_thread_self(), buffer, cache ); g_thread_self(), buffer, cache );
#endif /*DEBUG_VERBOSE*/ #endif /*DEBUG_VERBOSE*/
g_assert( cache->thread == g_thread_self() ); g_assert( !cache->thread ||
g_assert( cache->buffer_thread->thread == cache->thread ); cache->thread == g_thread_self() );
g_assert( !cache->thread ||
cache->buffer_thread->thread == cache->thread );
g_assert( g_slist_find( cache->buffers, buffer ) ); g_assert( g_slist_find( cache->buffers, buffer ) );
g_assert( cache->buffer_thread == buffer_thread_get() ); g_assert( cache->buffer_thread == buffer_thread_get() );
@ -621,7 +666,8 @@ buffer_thread_destroy_notify( VipsBufferThread *buffer_thread )
/* We only come here if vips_thread_shutdown() was not called for this /* We only come here if vips_thread_shutdown() was not called for this
* thread. Do our best to clean up. * thread. Do our best to clean up.
* *
* GPrivate has stopped working, be careful not to touch that. * GPrivate has stopped working by this point in destruction, be
* careful not to touch that.
*/ */
buffer_thread_free( buffer_thread ); buffer_thread_free( buffer_thread );
} }