Move sink_disc and sink_screen threads to threadpool
And deprecate the vips_g_thread_new and vips_g_thread_join functions.
This commit is contained in:
parent
4144049174
commit
d1b4d12388
@ -5694,7 +5694,7 @@ vips_get_option_group( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We used to use this for system() back in the day. But it's awkward to make
|
/* We used to use this for system() back in the day. But it's awkward to make
|
||||||
* it work properly on win32, so this is nonw deprecated.
|
* it work properly on win32, so this is now deprecated.
|
||||||
*/
|
*/
|
||||||
FILE *
|
FILE *
|
||||||
vips_popenf( const char *fmt, const char *mode, ... )
|
vips_popenf( const char *fmt, const char *mode, ... )
|
||||||
@ -5703,3 +5703,16 @@ vips_popenf( const char *fmt, const char *mode, ... )
|
|||||||
return( NULL );
|
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 );
|
||||||
|
}
|
||||||
|
@ -108,8 +108,6 @@ extern char *vips__disc_threshold;
|
|||||||
extern gboolean vips__cache_dump;
|
extern gboolean vips__cache_dump;
|
||||||
extern gboolean vips__cache_trace;
|
extern gboolean vips__cache_trace;
|
||||||
|
|
||||||
extern int vips__n_active_threads;
|
|
||||||
|
|
||||||
void vips__threadpool_init( void );
|
void vips__threadpool_init( void );
|
||||||
void vips__threadpool_shutdown( void );
|
void vips__threadpool_shutdown( void );
|
||||||
|
|
||||||
|
@ -47,11 +47,6 @@ void vips_g_mutex_free( GMutex * );
|
|||||||
GCond *vips_g_cond_new( void );
|
GCond *vips_g_cond_new( void );
|
||||||
void vips_g_cond_free( GCond * );
|
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 );
|
gboolean vips_thread_isworker( void );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -1224,6 +1224,11 @@ VipsWindow *vips_window_ref( VipsImage *im, int top, int height );
|
|||||||
FILE *vips_popenf( const char *fmt, const char *mode, ... )
|
FILE *vips_popenf( const char *fmt, const char *mode, ... )
|
||||||
__attribute__((format(printf, 1, 3)));
|
__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.
|
/* This stuff is very, very old and should not be used by anyone now.
|
||||||
*/
|
*/
|
||||||
#ifdef VIPS_ENABLE_ANCIENT
|
#ifdef VIPS_ENABLE_ANCIENT
|
||||||
|
@ -641,12 +641,6 @@ vips_leak( void )
|
|||||||
n_leaks += strlen( vips_error_buffer() );
|
n_leaks += strlen( vips_error_buffer() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( vips__n_active_threads > 0 ) {
|
|
||||||
vips_buf_appendf( &buf, "threads: %d not joined\n",
|
|
||||||
vips__n_active_threads );
|
|
||||||
n_leaks += vips__n_active_threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf( stderr, "%s", vips_buf_all( &buf ) );
|
fprintf( stderr, "%s", vips_buf_all( &buf ) );
|
||||||
|
|
||||||
n_leaks += vips__print_renders();
|
n_leaks += vips__print_renders();
|
||||||
|
@ -171,7 +171,7 @@ sink_area_position( SinkArea *area, int top, int height )
|
|||||||
static gboolean
|
static gboolean
|
||||||
sink_area_allocate_fn( VipsThreadState *state, void *a, gboolean *stop )
|
sink_area_allocate_fn( VipsThreadState *state, void *a, gboolean *stop )
|
||||||
{
|
{
|
||||||
SinkThreadState *wstate = (SinkThreadState *) state;
|
SinkThreadState *sstate = (SinkThreadState *) state;
|
||||||
Sink *sink = (Sink *) a;
|
Sink *sink = (Sink *) a;
|
||||||
SinkBase *sink_base = (SinkBase *) sink;
|
SinkBase *sink_base = (SinkBase *) sink;
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ sink_area_allocate_fn( VipsThreadState *state, void *a, gboolean *stop )
|
|||||||
|
|
||||||
/* The thread needs to know which area it's writing to.
|
/* The thread needs to know which area it's writing to.
|
||||||
*/
|
*/
|
||||||
wstate->area = sink->area;
|
sstate->area = sink->area;
|
||||||
|
|
||||||
VIPS_DEBUG_MSG( " %p allocated %d x %d:\n",
|
VIPS_DEBUG_MSG( " %p allocated %d x %d:\n",
|
||||||
g_thread_self(), state->pos.left, state->pos.top );
|
g_thread_self(), state->pos.left, state->pos.top );
|
||||||
|
@ -75,8 +75,9 @@ typedef struct _WriteBuffer {
|
|||||||
VipsSemaphore go; /* Start bg thread loop */
|
VipsSemaphore go; /* Start bg thread loop */
|
||||||
VipsSemaphore nwrite; /* Number of threads writing to region */
|
VipsSemaphore nwrite; /* Number of threads writing to region */
|
||||||
VipsSemaphore done; /* Bg thread has done write */
|
VipsSemaphore done; /* Bg thread has done write */
|
||||||
|
VipsSemaphore finish; /* Bg thread has finished */
|
||||||
int write_errno; /* Save write errors here */
|
int write_errno; /* Save write errors here */
|
||||||
GThread *thread; /* BG writer thread */
|
gboolean running; /* Whether the bg writer thread is running */
|
||||||
gboolean kill; /* Set to ask thread to exit */
|
gboolean kill; /* Set to ask thread to exit */
|
||||||
} WriteBuffer;
|
} WriteBuffer;
|
||||||
|
|
||||||
@ -141,22 +142,22 @@ wbuffer_free( WriteBuffer *wbuffer )
|
|||||||
{
|
{
|
||||||
/* Is there a thread running this region? Kill it!
|
/* Is there a thread running this region? Kill it!
|
||||||
*/
|
*/
|
||||||
if( wbuffer->thread ) {
|
if( wbuffer->running ) {
|
||||||
wbuffer->kill = TRUE;
|
wbuffer->kill = TRUE;
|
||||||
vips_semaphore_up( &wbuffer->go );
|
vips_semaphore_up( &wbuffer->go );
|
||||||
|
|
||||||
/* Return value is always NULL (see wbuffer_write_thread).
|
vips_semaphore_down( &wbuffer->finish );
|
||||||
*/
|
|
||||||
(void) vips_g_thread_join( wbuffer->thread );
|
|
||||||
VIPS_DEBUG_MSG( "wbuffer_free: vips_g_thread_join()\n" );
|
|
||||||
|
|
||||||
wbuffer->thread = NULL;
|
VIPS_DEBUG_MSG( "wbuffer_free:\n" );
|
||||||
|
|
||||||
|
wbuffer->running = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIPS_UNREF( wbuffer->region );
|
VIPS_UNREF( wbuffer->region );
|
||||||
vips_semaphore_destroy( &wbuffer->go );
|
vips_semaphore_destroy( &wbuffer->go );
|
||||||
vips_semaphore_destroy( &wbuffer->nwrite );
|
vips_semaphore_destroy( &wbuffer->nwrite );
|
||||||
vips_semaphore_destroy( &wbuffer->done );
|
vips_semaphore_destroy( &wbuffer->done );
|
||||||
|
vips_semaphore_destroy( &wbuffer->finish );
|
||||||
g_free( wbuffer );
|
g_free( wbuffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,8 +179,8 @@ wbuffer_write( WriteBuffer *wbuffer )
|
|||||||
|
|
||||||
/* Run this as a thread to do a BG write.
|
/* Run this as a thread to do a BG write.
|
||||||
*/
|
*/
|
||||||
static void *
|
static void
|
||||||
wbuffer_write_thread( void *data )
|
wbuffer_write_thread( void *data, void *user_data )
|
||||||
{
|
{
|
||||||
WriteBuffer *wbuffer = (WriteBuffer *) data;
|
WriteBuffer *wbuffer = (WriteBuffer *) data;
|
||||||
|
|
||||||
@ -202,7 +203,9 @@ wbuffer_write_thread( void *data )
|
|||||||
vips_semaphore_up( &wbuffer->done );
|
vips_semaphore_up( &wbuffer->done );
|
||||||
}
|
}
|
||||||
|
|
||||||
return( NULL );
|
/* We are exiting: tell the main thread.
|
||||||
|
*/
|
||||||
|
vips_semaphore_up( &wbuffer->finish );
|
||||||
}
|
}
|
||||||
|
|
||||||
static WriteBuffer *
|
static WriteBuffer *
|
||||||
@ -217,8 +220,9 @@ wbuffer_new( Write *write )
|
|||||||
vips_semaphore_init( &wbuffer->go, 0, "go" );
|
vips_semaphore_init( &wbuffer->go, 0, "go" );
|
||||||
vips_semaphore_init( &wbuffer->nwrite, 0, "nwrite" );
|
vips_semaphore_init( &wbuffer->nwrite, 0, "nwrite" );
|
||||||
vips_semaphore_init( &wbuffer->done, 0, "done" );
|
vips_semaphore_init( &wbuffer->done, 0, "done" );
|
||||||
|
vips_semaphore_init( &wbuffer->finish, 0, "finish" );
|
||||||
wbuffer->write_errno = 0;
|
wbuffer->write_errno = 0;
|
||||||
wbuffer->thread = NULL;
|
wbuffer->running = FALSE;
|
||||||
wbuffer->kill = FALSE;
|
wbuffer->kill = FALSE;
|
||||||
|
|
||||||
if( !(wbuffer->region = vips_region_new( write->sink_base.im )) ) {
|
if( !(wbuffer->region = vips_region_new( write->sink_base.im )) ) {
|
||||||
@ -232,12 +236,14 @@ wbuffer_new( Write *write )
|
|||||||
|
|
||||||
/* Make this last (picks up parts of wbuffer on startup).
|
/* Make this last (picks up parts of wbuffer on startup).
|
||||||
*/
|
*/
|
||||||
if( !(wbuffer->thread = vips_g_thread_new( "wbuffer",
|
if( vips_threadpool_push( "wbuffer", wbuffer_write_thread,
|
||||||
wbuffer_write_thread, wbuffer )) ) {
|
wbuffer ) ) {
|
||||||
wbuffer_free( wbuffer );
|
wbuffer_free( wbuffer );
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wbuffer->running = TRUE;
|
||||||
|
|
||||||
return( wbuffer );
|
return( wbuffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ sink_memory_area_position( SinkMemoryArea *area, int top, int height )
|
|||||||
static gboolean
|
static gboolean
|
||||||
sink_memory_area_allocate_fn( VipsThreadState *state, void *a, gboolean *stop )
|
sink_memory_area_allocate_fn( VipsThreadState *state, void *a, gboolean *stop )
|
||||||
{
|
{
|
||||||
SinkMemoryThreadState *wstate = (SinkMemoryThreadState *) state;
|
SinkMemoryThreadState *smstate = (SinkMemoryThreadState *) state;
|
||||||
SinkMemory *memory = (SinkMemory *) a;
|
SinkMemory *memory = (SinkMemory *) a;
|
||||||
SinkBase *sink_base = (SinkBase *) memory;
|
SinkBase *sink_base = (SinkBase *) memory;
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ sink_memory_area_allocate_fn( VipsThreadState *state, void *a, gboolean *stop )
|
|||||||
|
|
||||||
/* The thread needs to know which area it's writing to.
|
/* The thread needs to know which area it's writing to.
|
||||||
*/
|
*/
|
||||||
wstate->area = memory->area;
|
smstate->area = memory->area;
|
||||||
|
|
||||||
VIPS_DEBUG_MSG( " %p allocated %d x %d:\n",
|
VIPS_DEBUG_MSG( " %p allocated %d x %d:\n",
|
||||||
g_thread_self(), state->pos.left, state->pos.top );
|
g_thread_self(), state->pos.left, state->pos.top );
|
||||||
@ -255,8 +255,8 @@ static int
|
|||||||
sink_memory_area_work_fn( VipsThreadState *state, void *a )
|
sink_memory_area_work_fn( VipsThreadState *state, void *a )
|
||||||
{
|
{
|
||||||
SinkMemory *memory = (SinkMemory *) a;
|
SinkMemory *memory = (SinkMemory *) a;
|
||||||
SinkMemoryThreadState *wstate = (SinkMemoryThreadState *) state;
|
SinkMemoryThreadState *smstate = (SinkMemoryThreadState *) state;
|
||||||
SinkMemoryArea *area = wstate->area;
|
SinkMemoryArea *area = smstate->area;
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -162,22 +162,29 @@ typedef struct _RenderThreadStateClass {
|
|||||||
|
|
||||||
G_DEFINE_TYPE( RenderThreadState, render_thread_state, VIPS_TYPE_THREAD_STATE );
|
G_DEFINE_TYPE( RenderThreadState, render_thread_state, VIPS_TYPE_THREAD_STATE );
|
||||||
|
|
||||||
/* The BG thread which sits waiting to do some calculations, and the semaphore
|
/* A boolean indicating if the bg render thread is running.
|
||||||
* it waits on holding the number of renders with dirty tiles.
|
|
||||||
*/
|
*/
|
||||||
static GThread *render_thread = NULL;
|
static gboolean render_running = FALSE;
|
||||||
|
|
||||||
/* Set this to ask the render thread to quit.
|
/* Set this to ask the render thread to quit.
|
||||||
*/
|
*/
|
||||||
static gboolean render_kill = FALSE;
|
static gboolean render_kill = FALSE;
|
||||||
|
|
||||||
/* All the renders with dirty tiles, and a semaphore that the bg render thread
|
/* All the renders with dirty tiles.
|
||||||
* waits on.
|
|
||||||
*/
|
*/
|
||||||
static GMutex *render_dirty_lock = NULL;
|
static GMutex *render_dirty_lock = NULL;
|
||||||
static GSList *render_dirty_all = 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;
|
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.
|
/* Set this to make the bg thread stop and reschedule.
|
||||||
*/
|
*/
|
||||||
static gboolean render_reschedule = FALSE;
|
static gboolean render_reschedule = FALSE;
|
||||||
@ -435,10 +442,7 @@ vips__render_shutdown( void )
|
|||||||
if( render_dirty_lock ) {
|
if( render_dirty_lock ) {
|
||||||
g_mutex_lock( render_dirty_lock );
|
g_mutex_lock( render_dirty_lock );
|
||||||
|
|
||||||
if( render_thread ) {
|
if( render_running ) {
|
||||||
GThread *thread;
|
|
||||||
|
|
||||||
thread = render_thread;
|
|
||||||
render_reschedule = TRUE;
|
render_reschedule = TRUE;
|
||||||
render_kill = TRUE;
|
render_kill = TRUE;
|
||||||
|
|
||||||
@ -446,13 +450,16 @@ vips__render_shutdown( void )
|
|||||||
|
|
||||||
vips_semaphore_up( &n_render_dirty_sem );
|
vips_semaphore_up( &n_render_dirty_sem );
|
||||||
|
|
||||||
(void) vips_g_thread_join( thread );
|
vips_semaphore_down( &render_finish );
|
||||||
|
|
||||||
|
render_running = FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
g_mutex_unlock( render_dirty_lock );
|
g_mutex_unlock( render_dirty_lock );
|
||||||
|
|
||||||
VIPS_FREEF( vips_g_mutex_free, render_dirty_lock );
|
VIPS_FREEF( vips_g_mutex_free, render_dirty_lock );
|
||||||
vips_semaphore_destroy( &n_render_dirty_sem );
|
vips_semaphore_destroy( &n_render_dirty_sem );
|
||||||
|
vips_semaphore_destroy( &render_finish );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,10 +992,10 @@ render_dirty_get( void )
|
|||||||
return( render );
|
return( render );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop for the background render mananger thread.
|
/* Loop for the background render manager thread.
|
||||||
*/
|
*/
|
||||||
static void *
|
static void
|
||||||
render_thread_main( void *client )
|
render_thread_main( void *data, void *user_data )
|
||||||
{
|
{
|
||||||
Render *render;
|
Render *render;
|
||||||
|
|
||||||
@ -1023,23 +1030,29 @@ render_thread_main( void *client )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We are exiting, so render_thread must now be NULL.
|
/* We are exiting: tell the main thread.
|
||||||
*/
|
*/
|
||||||
render_thread = NULL;
|
vips_semaphore_up( &render_finish );
|
||||||
|
|
||||||
return( NULL );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
vips__sink_screen_init( void *data )
|
vips__sink_screen_init( void *data )
|
||||||
{
|
{
|
||||||
g_assert( !render_thread );
|
g_assert( !render_running );
|
||||||
g_assert( !render_dirty_lock );
|
g_assert( !render_dirty_lock );
|
||||||
|
|
||||||
render_dirty_lock = vips_g_mutex_new();
|
render_dirty_lock = vips_g_mutex_new();
|
||||||
vips_semaphore_init( &n_render_dirty_sem, 0, "n_render_dirty" );
|
vips_semaphore_init( &n_render_dirty_sem, 0, "n_render_dirty" );
|
||||||
render_thread = vips_g_thread_new( "sink_screen",
|
vips_semaphore_init( &render_finish, 0, "render_finish" );
|
||||||
render_thread_main, NULL );
|
|
||||||
|
if ( vips_threadpool_push( "sink_screen", render_thread_main,
|
||||||
|
NULL ) ) {
|
||||||
|
vips_error("vips_sink_screen_init", "%s",
|
||||||
|
_("unable to init render thread"));
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
render_running = TRUE;
|
||||||
|
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#define DEBUG_OUT_OF_THREADS
|
|
||||||
#define VIPS_DEBUG
|
#define VIPS_DEBUG
|
||||||
#define VIPS_DEBUG_RED
|
#define VIPS_DEBUG_RED
|
||||||
*/
|
*/
|
||||||
@ -121,10 +120,6 @@ int vips__thinstrip_height = VIPS__THINSTRIP_HEIGHT;
|
|||||||
*/
|
*/
|
||||||
int vips__concurrency = 0;
|
int vips__concurrency = 0;
|
||||||
|
|
||||||
/* Count the number of threads we have active and report on leak test.
|
|
||||||
*/
|
|
||||||
int vips__n_active_threads = 0;
|
|
||||||
|
|
||||||
/* Set this GPrivate to indicate that this is a vips worker.
|
/* Set this GPrivate to indicate that this is a vips worker.
|
||||||
*/
|
*/
|
||||||
static GPrivate *is_worker_key = NULL;
|
static GPrivate *is_worker_key = NULL;
|
||||||
@ -186,109 +181,6 @@ vips_thread_isworker( void )
|
|||||||
return( g_private_get( is_worker_key ) != NULL );
|
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 )
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_OUT_OF_THREADS
|
|
||||||
static int n_threads = 0;
|
|
||||||
#endif /*DEBUG_OUT_OF_THREADS*/
|
|
||||||
|
|
||||||
GThread *thread;
|
|
||||||
VipsThreadInfo *info;
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
info = g_new( VipsThreadInfo, 1 );
|
|
||||||
info->domain = domain;
|
|
||||||
info->func = func;
|
|
||||||
info->data = data;
|
|
||||||
|
|
||||||
#ifdef DEBUG_OUT_OF_THREADS
|
|
||||||
n_threads += 1;
|
|
||||||
if( n_threads > 10 )
|
|
||||||
thread = NULL;
|
|
||||||
else {
|
|
||||||
#endif /*DEBUG_OUT_OF_THREADS*/
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
#ifdef DEBUG_OUT_OF_THREADS
|
|
||||||
}
|
|
||||||
#endif /*DEBUG_OUT_OF_THREADS*/
|
|
||||||
|
|
||||||
if( !thread ) {
|
|
||||||
if( error )
|
|
||||||
vips_g_error( &error );
|
|
||||||
else
|
|
||||||
vips_error( domain,
|
|
||||||
"%s", _( "unable to create thread" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( thread &&
|
|
||||||
vips__leak ) {
|
|
||||||
g_mutex_lock( vips__global_lock );
|
|
||||||
|
|
||||||
vips__n_active_threads += 1;
|
|
||||||
|
|
||||||
g_mutex_unlock( vips__global_lock );
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
if( vips__leak ) {
|
|
||||||
g_mutex_lock( vips__global_lock );
|
|
||||||
|
|
||||||
vips__n_active_threads -= 1;
|
|
||||||
|
|
||||||
g_mutex_unlock( vips__global_lock );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( result );
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* An name for this thread.
|
/* An name for this thread.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user