1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

Add interface to disable automatic finalization

* libguile/finalizers.h:
* libguile/finalizers.c (run_finalizers_async_thunk)
  (finalization_thread_proc): Call the new scm_run_finalizers helper.
  (scm_i_finalizer_pre_fork): Only spawn the thread if automatic
  finalization is enabled.
  (scm_set_automatic_finalization_enabled, scm_run_finalizers): New
  functions.
  (scm_init_finalizers, scm_init_finalizer_thread): Only set a finalizer
  notifier if automatic finalization is enabled.

* doc/ref/libguile-smobs.texi (Garbage Collecting Smobs): Add discussion
  of concurrency.

* doc/ref/api-smobs.texi (Smobs): Document new functions.
This commit is contained in:
Andy Wingo 2014-04-17 15:29:13 +02:00
parent f5765cc25e
commit d6651f6903
4 changed files with 130 additions and 12 deletions

View file

@ -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))

View file

@ -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.

View file

@ -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
}

View file

@ -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);