diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 546111d1..b83edc42 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -5703,16 +5703,3 @@ vips_popenf( const char *fmt, const char *mode, ... ) return( NULL ); } -GThread * -vips_g_thread_new( const char *domain, GThreadFunc func, gpointer data ) -{ - vips_error( "vips_g_thread_new", "%s", _( "deprecated" ) ); - return( NULL ); -} - -void * -vips_g_thread_join( GThread *thread ) -{ - vips_error( "vips_g_thread_join", "%s", _( "deprecated" ) ); - return( NULL ); -} diff --git a/libvips/include/vips/thread.h b/libvips/include/vips/thread.h index ae51b652..63ba23c4 100644 --- a/libvips/include/vips/thread.h +++ b/libvips/include/vips/thread.h @@ -47,6 +47,11 @@ void vips_g_mutex_free( GMutex * ); GCond *vips_g_cond_new( void ); void vips_g_cond_free( GCond * ); +/* ... and for GThread. + */ +GThread *vips_g_thread_new( const char *, GThreadFunc, gpointer ); +void *vips_g_thread_join( GThread *thread ); + gboolean vips_thread_isworker( void ); #ifdef __cplusplus diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index a591a84c..ac34a710 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -1224,11 +1224,6 @@ VipsWindow *vips_window_ref( VipsImage *im, int top, int height ); FILE *vips_popenf( const char *fmt, const char *mode, ... ) __attribute__((format(printf, 1, 3))); -/* old GThread API. - */ -GThread *vips_g_thread_new( const char *, GThreadFunc, gpointer ); -void *vips_g_thread_join( GThread *thread ); - /* This stuff is very, very old and should not be used by anyone now. */ #ifdef VIPS_ENABLE_ANCIENT diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index aa1146d9..660446e2 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -167,29 +167,22 @@ typedef struct _RenderThreadStateClass { G_DEFINE_TYPE( RenderThreadState, render_thread_state, VIPS_TYPE_THREAD_STATE ); -/* A boolean indicating if the bg render thread is running. +/* The BG thread which sits waiting to do some calculations, and the semaphore + * it waits on holding the number of renders with dirty tiles. */ -static gboolean render_running = FALSE; +static GThread *render_thread = NULL; /* Set this to ask the render thread to quit. */ static gboolean render_kill = FALSE; -/* All the renders with dirty tiles. +/* All the renders with dirty tiles, and a semaphore that the bg render thread + * waits on. */ static GMutex *render_dirty_lock = NULL; static GSList *render_dirty_all = NULL; - -/* A semaphore where the bg render thread waits on holding the number of - * renders with dirty tiles - */ static VipsSemaphore n_render_dirty_sem; -/* A semaphore where the main thread waits for when the bg render thread - * is shutdown. - */ -static VipsSemaphore render_finish; - /* Set this to make the bg thread stop and reschedule. */ static gboolean render_reschedule = FALSE; @@ -452,7 +445,10 @@ vips__render_shutdown( void ) if( render_dirty_lock ) { g_mutex_lock( render_dirty_lock ); - if( render_running ) { + if( render_thread ) { + GThread *thread; + + thread = render_thread; render_reschedule = TRUE; render_kill = TRUE; @@ -460,16 +456,13 @@ vips__render_shutdown( void ) vips_semaphore_up( &n_render_dirty_sem ); - vips_semaphore_down( &render_finish ); - - render_running = FALSE; + (void) vips_g_thread_join( thread ); } else g_mutex_unlock( render_dirty_lock ); VIPS_FREEF( vips_g_mutex_free, render_dirty_lock ); vips_semaphore_destroy( &n_render_dirty_sem ); - vips_semaphore_destroy( &render_finish ); } } @@ -1008,8 +1001,8 @@ render_dirty_get( void ) /* Loop for the background render manager thread. */ -static void -render_thread_main( void *data, void *user_data ) +static void * +render_thread_main( void *client ) { Render *render; @@ -1044,29 +1037,23 @@ render_thread_main( void *data, void *user_data ) } } - /* We are exiting: tell the main thread. + /* We are exiting, so render_thread must now be NULL. */ - vips_semaphore_up( &render_finish ); + render_thread = NULL; + + return( NULL ); } static void * vips__sink_screen_init( void *data ) { - g_assert( !render_running ); + g_assert( !render_thread ); g_assert( !render_dirty_lock ); render_dirty_lock = vips_g_mutex_new(); vips_semaphore_init( &n_render_dirty_sem, 0, "n_render_dirty" ); - vips_semaphore_init( &render_finish, 0, "render_finish" ); - - if( vips__thread_execute( "sink_screen", render_thread_main, - NULL ) ) { - vips_error( "vips_sink_screen_init", - "%s", _( "unable to init render thread" ) ); - return( NULL ); - } - - render_running = TRUE; + render_thread = vips_g_thread_new( "sink_screen", + render_thread_main, NULL ); return( NULL ); } diff --git a/libvips/iofuncs/threadpool.c b/libvips/iofuncs/threadpool.c index 39c2687a..9fa53881 100644 --- a/libvips/iofuncs/threadpool.c +++ b/libvips/iofuncs/threadpool.c @@ -182,6 +182,77 @@ vips_thread_isworker( void ) return( g_private_get( is_worker_key ) != NULL ); } +typedef struct { + const char *domain; + GThreadFunc func; + gpointer data; +} VipsThreadInfo; + +static void * +vips_thread_run( gpointer data ) +{ + VipsThreadInfo *info = (VipsThreadInfo *) data; + + void *result; + + /* Set this to something (anything) to tag this thread as a vips + * worker. + */ + g_private_set( is_worker_key, data ); + + if( vips__thread_profile ) + vips__thread_profile_attach( info->domain ); + + result = info->func( info->data ); + + g_free( info ); + + vips_thread_shutdown(); + + return( result ); +} + +GThread * +vips_g_thread_new( const char *domain, GThreadFunc func, gpointer data ) +{ + GThread *thread; + VipsThreadInfo *info; + GError *error = NULL; + + info = g_new( VipsThreadInfo, 1 ); + info->domain = domain; + info->func = func; + info->data = data; + + thread = g_thread_try_new( domain, vips_thread_run, info, &error ); + + VIPS_DEBUG_MSG_RED( "vips_g_thread_new: g_thread_create( %s ) = %p\n", + domain, thread ); + + if( !thread ) { + if( error ) + vips_g_error( &error ); + else + vips_error( domain, + "%s", _( "unable to create thread" ) ); + } + + return( thread ); +} + +void * +vips_g_thread_join( GThread *thread ) +{ + void *result; + + result = g_thread_join( thread ); + + VIPS_DEBUG_MSG_RED( "vips_g_thread_join: g_thread_join( %p )\n", + thread ); + + return( result ); +} + typedef struct { /* An name for this thread. */