diff --git a/doc/ref/api-smobs.texi b/doc/ref/api-smobs.texi index 345bf7cbd..cfabd3988 100644 --- a/doc/ref/api-smobs.texi +++ b/doc/ref/api-smobs.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 2013 +@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 2013, 2014 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @@ -60,6 +60,36 @@ memory is automatically reclaimed by the garbage collector when it is no longer needed (@pxref{Memory Blocks, @code{scm_gc_malloc}}). @end deftypefn +Smob free functions must be thread-safe. @xref{Garbage Collecting +Smobs}, for a discussion on finalizers and concurrency. If you are +embedding Guile in an application that is not thread-safe, and you +define smob types that need finalization, you might want to disable +automatic finalization, and arrange to call +@code{scm_manually_run_finalizers ()} yourself. + +@deftypefn {C Function} int scm_set_automatic_finalization_enabled (int enabled_p) +Enable or disable automatic finalization. By default, Guile arranges to +invoke object finalizers automatically, in a separate thread if +possible. Passing a zero value for @var{enabled_p} will disable +automatic finalization for Guile as a whole. If you disable automatic +finalization, you will have to call @code{scm_run_finalizers ()} +periodically. + +Unlike most other Guile functions, you can call +@code{scm_set_automatic_finalization_enabled} before Guile has been +initialized. + +Return the previous status of automatic finalization. +@end deftypefn + +@deftypefn {C Function} int scm_run_finalizers (void) +Invoke any pending finalizers. Returns the number of finalizers that +were invoked. This function should be called when automatic +finalization is disabled, though it may be called if it is enabled as +well. +@end deftypefn + + @cindex precise marking @deftypefn {C Function} void scm_set_smob_mark (scm_t_bits tc, SCM (*mark) (SCM obj)) diff --git a/doc/ref/libguile-smobs.texi b/doc/ref/libguile-smobs.texi index 572bcf316..d68b71812 100644 --- a/doc/ref/libguile-smobs.texi +++ b/doc/ref/libguile-smobs.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2010, 2011, 2013 +@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2010, 2011, 2013, 2014 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @@ -385,6 +385,28 @@ During the sweep phase, the garbage collector will clear the mark bits on all live objects. The code which implements a smob need not do this itself. +@cindex finalizer +@cindex finalization + +Note that the free function can be called in any context. In +particular, if your Guile is built with support for threads, the +finalizer will be called from a dedicated finalization thread. This +ensures that the finalization doesn't run within the critical section of +any other thread known to Guile. It also lowers latency, as your Guile +program doesn't have to wait for finalizers to run. However, if your +Guile is built without threads, the finalizers may be called within the +critical section of some other piece of code. + +In either case, finalizers (free functions) run concurrently with the +main program, and so they need to be thread-safe. If for some reason +this is impossible, perhaps because you are embedding Guile in some +application that is not itself thread-safe, you have a few options. One +is to use guardians instead of free functions, and arrange to pump the +guardians for finalizable objects. @xref{Guardians}, for more +information. The other option is to disable automatic finalization +entirely, and arrange to call @code{scm_run_finalizers ()} at +appropriate points. @xref{Smobs}, for more on these interfaces. + There is no way for smob code to be notified when collection is complete. diff --git a/libguile/finalizers.c b/libguile/finalizers.c index eaea1392f..b37dbde6b 100644 --- a/libguile/finalizers.c +++ b/libguile/finalizers.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2012, 2013 Free Software Foundation, Inc. +/* Copyright (C) 2012, 2013, 2014 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,6 +38,8 @@ +static int automatic_finalization_p = 1; + static size_t finalization_count; @@ -137,7 +139,7 @@ static SCM finalizer_async_cell; static SCM run_finalizers_async_thunk (void) { - finalization_count += GC_invoke_finalizers (); + scm_run_finalizers (); return SCM_UNSPECIFIED; } @@ -226,7 +228,7 @@ finalization_thread_proc (void *unused) switch (data.byte) { case 0: - finalization_count += GC_invoke_finalizers (); + scm_run_finalizers (); break; case 1: return NULL; @@ -291,8 +293,11 @@ void scm_i_finalizer_pre_fork (void) { #if SCM_USE_PTHREAD_THREADS - stop_finalization_thread (); - GC_set_finalizer_notifier (spawn_finalizer_thread); + if (automatic_finalization_p) + { + stop_finalization_thread (); + GC_set_finalizer_notifier (spawn_finalizer_thread); + } #endif } @@ -355,6 +360,59 @@ scm_i_register_weak_gc_callback (SCM obj, void (*callback) (SCM)) } +int +scm_set_automatic_finalization_enabled (int enabled_p) +{ + int was_enabled_p = automatic_finalization_p; + + if (enabled_p == was_enabled_p) + return was_enabled_p; + + if (!scm_initialized_p) + { + automatic_finalization_p = enabled_p; + return was_enabled_p; + } + + if (enabled_p) + { +#if SCM_USE_PTHREAD_THREADS + if (pipe2 (finalization_pipe, O_CLOEXEC) != 0) + scm_syserror (NULL); + GC_set_finalizer_notifier (spawn_finalizer_thread); +#else + GC_set_finalizer_notifier (queue_finalizer_async); +#endif + } + else + { + GC_set_finalizer_notifier (0); + +#if SCM_USE_PTHREAD_THREADS + stop_finalization_thread (); + close (finalization_pipe[0]); + close (finalization_pipe[1]); + finalization_pipe[0] = -1; + finalization_pipe[1] = -1; +#endif + } + + automatic_finalization_p = enabled_p; + + return was_enabled_p; +} + +int +scm_run_finalizers (void) +{ + int finalized = GC_invoke_finalizers (); + + finalization_count += finalized; + + return finalized; +} + + void @@ -366,15 +424,20 @@ scm_init_finalizers (void) scm_cons (scm_c_make_gsubr ("%run-finalizers", 0, 0, 0, run_finalizers_async_thunk), SCM_BOOL_F); - GC_set_finalizer_notifier (queue_finalizer_async); + + if (automatic_finalization_p) + GC_set_finalizer_notifier (queue_finalizer_async); } void scm_init_finalizer_thread (void) { #if SCM_USE_PTHREAD_THREADS - if (pipe2 (finalization_pipe, O_CLOEXEC) != 0) - scm_syserror (NULL); - GC_set_finalizer_notifier (spawn_finalizer_thread); + if (automatic_finalization_p) + { + if (pipe2 (finalization_pipe, O_CLOEXEC) != 0) + scm_syserror (NULL); + GC_set_finalizer_notifier (spawn_finalizer_thread); + } #endif } diff --git a/libguile/finalizers.h b/libguile/finalizers.h index 2ef075197..d01d1b734 100644 --- a/libguile/finalizers.h +++ b/libguile/finalizers.h @@ -1,7 +1,7 @@ #ifndef SCM_FINALIZERS_H #define SCM_FINALIZERS_H -/* Copyright (C) 2012, 2013 Free Software Foundation, Inc. +/* Copyright (C) 2012, 2013, 2014 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -41,6 +41,9 @@ SCM_INTERNAL void scm_i_finalizer_pre_fork (void); be from an async or from another thread. */ SCM_INTERNAL void scm_i_register_weak_gc_callback (SCM obj, void (*callback) (SCM)); +SCM_API int scm_set_automatic_finalization_enabled (int enabled_p); +SCM_API int scm_run_finalizers (void); + SCM_INTERNAL void scm_init_finalizers (void); SCM_INTERNAL void scm_init_finalizer_thread (void);