experiment with removing shutdown from atexit (#2439)
remove shutdown from atexit Because atexit() can be called at almost any point during process termination, including after worker threads have been force-quit, we can't use it for cleanup. New policy: use vips_shutdown() explicitly if you need to clean up, though it's optional. Only use atexit() for leak checking.
This commit is contained in:
parent
b221830b5a
commit
af61d375bc
@ -387,6 +387,10 @@ int vips__progress = 0;
|
||||
*/
|
||||
char *vips__disc_threshold = NULL;
|
||||
|
||||
/* Minimise needs a lock.
|
||||
*/
|
||||
static GMutex *vips__minimise_lock = NULL;
|
||||
|
||||
static guint vips_image_signals[SIG_LAST] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE( VipsImage, vips_image, VIPS_TYPE_OBJECT );
|
||||
@ -1322,8 +1326,7 @@ vips_image_class_init( VipsImageClass *class )
|
||||
*
|
||||
* The ::minimise signal is emitted when an image has been asked to
|
||||
* minimise memory usage. All non-essential caches are dropped.
|
||||
* See
|
||||
* vips_image_minimise_all().
|
||||
* See vips_image_minimise_all().
|
||||
*/
|
||||
vips_image_signals[SIG_MINIMISE] = g_signal_new( "minimise",
|
||||
G_TYPE_FROM_CLASS( class ),
|
||||
@ -1333,6 +1336,7 @@ vips_image_class_init( VipsImageClass *class )
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0 );
|
||||
|
||||
vips__minimise_lock = vips_g_mutex_new();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1446,8 +1450,15 @@ vips_image_minimise_all_cb( VipsImage *image, void *a, void *b )
|
||||
void
|
||||
vips_image_minimise_all( VipsImage *image )
|
||||
{
|
||||
/* Minimisation will modify things like sources, so we can't run it
|
||||
* from many threads.
|
||||
*/
|
||||
g_mutex_lock( vips__minimise_lock );
|
||||
|
||||
(void) vips__link_map( image, TRUE,
|
||||
(VipsSListMap2Fn) vips_image_minimise_all_cb, NULL, NULL );
|
||||
|
||||
g_mutex_unlock( vips__minimise_lock );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,9 +230,6 @@ vips_get_prgname( void )
|
||||
* + loads any plugins from $libdir/vips-x.y/, where x and y are the
|
||||
* major and minor version numbers for this VIPS.
|
||||
*
|
||||
* + if your platform supports atexit(), VIPS_INIT() will ask for
|
||||
* vips_shutdown() to be called on program exit
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* |[
|
||||
@ -367,6 +364,74 @@ vips_verbose( void )
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vips_leak( void )
|
||||
{
|
||||
char txt[1024];
|
||||
VipsBuf buf = VIPS_BUF_STATIC( txt );
|
||||
int n_leaks;
|
||||
|
||||
n_leaks = 0;
|
||||
|
||||
n_leaks += vips__object_leak();
|
||||
n_leaks += vips__type_leak();
|
||||
n_leaks += vips_tracked_get_allocs();
|
||||
n_leaks += vips_tracked_get_mem();
|
||||
n_leaks += vips_tracked_get_files();
|
||||
|
||||
if( vips_tracked_get_allocs() ||
|
||||
vips_tracked_get_mem() ||
|
||||
vips_tracked_get_files() ) {
|
||||
vips_buf_appendf( &buf, "memory: %d allocations, %zd bytes\n",
|
||||
vips_tracked_get_allocs(), vips_tracked_get_mem() );
|
||||
vips_buf_appendf( &buf, "files: %d open\n",
|
||||
vips_tracked_get_files() );
|
||||
}
|
||||
|
||||
vips_buf_appendf( &buf, "memory: high-water mark " );
|
||||
vips_buf_append_size( &buf, vips_tracked_get_mem_highwater() );
|
||||
vips_buf_appends( &buf, "\n" );
|
||||
|
||||
if( strlen( vips_error_buffer() ) > 0 ) {
|
||||
vips_buf_appendf( &buf, "error buffer: %s",
|
||||
vips_error_buffer() );
|
||||
n_leaks += strlen( vips_error_buffer() );
|
||||
}
|
||||
|
||||
fprintf( stderr, "%s", vips_buf_all( &buf ) );
|
||||
|
||||
n_leaks += vips__print_renders();
|
||||
|
||||
#ifdef DEBUG
|
||||
vips_buffer_dump_all();
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( n_leaks );
|
||||
}
|
||||
|
||||
/* This is not guaranteed to be called, and might be called after many parts
|
||||
* of libvips have been freed. Threads can be in an indeterminate state.
|
||||
* You must be very careful to avoid segvs.
|
||||
*/
|
||||
static void
|
||||
vips__atexit( void )
|
||||
{
|
||||
/* In dev releases, always show leaks. But not more than once, it's
|
||||
* annoying.
|
||||
*/
|
||||
#ifndef DEBUG_LEAK
|
||||
if( vips__leak )
|
||||
#endif /*DEBUG_LEAK*/
|
||||
{
|
||||
static gboolean done = FALSE;
|
||||
|
||||
if( !done ) {
|
||||
done = TRUE;
|
||||
vips_leak();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_init:
|
||||
* @argv0: name of application
|
||||
@ -583,11 +648,8 @@ vips_init( const char *argv0 )
|
||||
gsf_init();
|
||||
#endif /*HAVE_GSF*/
|
||||
|
||||
/* Register vips_shutdown(). This may well not get called and many
|
||||
* platforms don't support it anyway.
|
||||
*/
|
||||
#ifdef HAVE_ATEXIT
|
||||
atexit( vips_shutdown );
|
||||
atexit( vips__atexit );
|
||||
#endif /*HAVE_ATEXIT*/
|
||||
|
||||
#ifdef DEBUG_LEAK
|
||||
@ -635,51 +697,6 @@ vips_check_init( void )
|
||||
vips_error_clear();
|
||||
}
|
||||
|
||||
static int
|
||||
vips_leak( void )
|
||||
{
|
||||
char txt[1024];
|
||||
VipsBuf buf = VIPS_BUF_STATIC( txt );
|
||||
int n_leaks;
|
||||
|
||||
n_leaks = 0;
|
||||
|
||||
n_leaks += vips__object_leak();
|
||||
n_leaks += vips__type_leak();
|
||||
n_leaks += vips_tracked_get_allocs();
|
||||
n_leaks += vips_tracked_get_mem();
|
||||
n_leaks += vips_tracked_get_files();
|
||||
|
||||
if( vips_tracked_get_allocs() ||
|
||||
vips_tracked_get_mem() ||
|
||||
vips_tracked_get_files() ) {
|
||||
vips_buf_appendf( &buf, "memory: %d allocations, %zd bytes\n",
|
||||
vips_tracked_get_allocs(), vips_tracked_get_mem() );
|
||||
vips_buf_appendf( &buf, "files: %d open\n",
|
||||
vips_tracked_get_files() );
|
||||
}
|
||||
|
||||
vips_buf_appendf( &buf, "memory: high-water mark " );
|
||||
vips_buf_append_size( &buf, vips_tracked_get_mem_highwater() );
|
||||
vips_buf_appends( &buf, "\n" );
|
||||
|
||||
if( strlen( vips_error_buffer() ) > 0 ) {
|
||||
vips_buf_appendf( &buf, "error buffer: %s",
|
||||
vips_error_buffer() );
|
||||
n_leaks += strlen( vips_error_buffer() );
|
||||
}
|
||||
|
||||
fprintf( stderr, "%s", vips_buf_all( &buf ) );
|
||||
|
||||
n_leaks += vips__print_renders();
|
||||
|
||||
#ifdef DEBUG
|
||||
vips_buffer_dump_all();
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( n_leaks );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_thread_shutdown:
|
||||
*
|
||||
@ -748,22 +765,6 @@ vips_shutdown( void )
|
||||
gsf_shutdown();
|
||||
#endif /*HAVE_GSF*/
|
||||
|
||||
/* In dev releases, always show leaks. But not more than once, it's
|
||||
* annoying.
|
||||
*/
|
||||
#ifndef DEBUG_LEAK
|
||||
if( vips__leak )
|
||||
#endif /*DEBUG_LEAK*/
|
||||
{
|
||||
static gboolean done = FALSE;
|
||||
|
||||
if( !done &&
|
||||
vips_leak() )
|
||||
exit( 1 );
|
||||
|
||||
done = TRUE;
|
||||
}
|
||||
|
||||
VIPS_FREE( vips__argv0 );
|
||||
VIPS_FREE( vips__prgname );
|
||||
VIPS_FREEF( vips_g_mutex_free, vips__global_lock );
|
||||
|
@ -1054,8 +1054,7 @@ vips__sink_screen_once( void *data )
|
||||
vips_semaphore_init( &n_render_dirty_sem, 0, "n_render_dirty" );
|
||||
|
||||
/* Don't use vips__thread_execute() since this thread will only be
|
||||
* ended by _shutdown, and that isn't always called early enough on
|
||||
* windows from atexit().
|
||||
* ended by vips_shutdown, and that isn't always called.
|
||||
*/
|
||||
render_thread = vips_g_thread_new( "sink_screen",
|
||||
render_thread_main, NULL );
|
||||
|
Loading…
Reference in New Issue
Block a user