diff options
Diffstat (limited to 'libguile/finalizers.c')
-rw-r--r-- | libguile/finalizers.c | 152 |
1 files changed, 149 insertions, 3 deletions
diff --git a/libguile/finalizers.c b/libguile/finalizers.c index 295f977b8..25aadf431 100644 --- a/libguile/finalizers.c +++ b/libguile/finalizers.c @@ -23,6 +23,13 @@ # include <config.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> + +#include <full-write.h> + #include "libguile/bdw-gc.h" #include "libguile/_scm.h" #include "libguile/finalizers.h" @@ -36,6 +43,17 @@ static size_t finalization_count; +#ifndef HAVE_GC_SET_FINALIZER_NOTIFIER +static void +GC_set_finalizer_notifier (void (*notifier) (void)) +{ + GC_finalizer_notifier = notifier; +} +#endif + + + + void scm_i_set_finalizer (void *obj, scm_t_finalizer_proc proc, void *data) { @@ -161,13 +179,131 @@ queue_finalizer_async (void) -#ifndef HAVE_GC_SET_FINALIZER_NOTIFIER +#if SCM_USE_PTHREAD_THREADS + +static int finalization_pipe[2]; +static scm_i_pthread_mutex_t finalization_thread_lock = + SCM_I_PTHREAD_MUTEX_INITIALIZER; +static pthread_t finalization_thread; + static void -GC_set_finalizer_notifier (void (*notifier) (void)) +notify_finalizers_to_run (void) { - GC_finalizer_notifier = notifier; + char byte = 0; + full_write (finalization_pipe[1], &byte, 1); +} + +static void +notify_about_to_fork (void) +{ + char byte = 1; + full_write (finalization_pipe[1], &byte, 1); } + +struct finalization_pipe_data +{ + char byte; + ssize_t n; + int err; +}; + +static void* +read_finalization_pipe_data (void *data) +{ + struct finalization_pipe_data *fdata = data; + + fdata->n = read (finalization_pipe[0], &fdata->byte, 1); + fdata->err = errno; + + return NULL; +} + +static void* +finalization_thread_proc (void *unused) +{ + while (1) + { + struct finalization_pipe_data data; + + scm_without_guile (read_finalization_pipe_data, &data); + + if (data.n <= 0 && data.err != EINTR) + { + perror ("error in finalization thread"); + return NULL; + } + + switch (data.byte) + { + case 0: + finalization_count += GC_invoke_finalizers (); + break; + case 1: + return NULL; + default: + abort (); + } + } +} + +static void* +run_finalization_thread (void *arg) +{ + return scm_with_guile (finalization_thread_proc, arg); +} + +static void +start_finalization_thread (void) +{ + scm_i_pthread_mutex_lock (&finalization_thread_lock); + if (!finalization_thread) + /* Use the raw pthread API and scm_with_guile, because we don't want + to block on any lock that scm_spawn_thread might want to take, + and we don't want to inherit the dynamic state (fluids) of the + caller. */ + if (pthread_create (&finalization_thread, NULL, + run_finalization_thread, NULL)) + perror ("error creating finalization thread"); + scm_i_pthread_mutex_unlock (&finalization_thread_lock); +} + +static void +stop_finalization_thread (void) +{ + scm_i_pthread_mutex_lock (&finalization_thread_lock); + if (finalization_thread) + { + notify_about_to_fork (); + if (pthread_join (finalization_thread, NULL)) + perror ("joining finalization thread"); + finalization_thread = 0; + } + scm_i_pthread_mutex_unlock (&finalization_thread_lock); +} + +static void +spawn_finalizer_thread (void) +{ + GC_set_finalizer_notifier (notify_finalizers_to_run); + start_finalization_thread (); +} + +#endif /* SCM_USE_PTHREAD_THREADS */ + + + + +void +scm_i_finalizer_pre_fork (void) +{ +#if SCM_USE_PTHREAD_THREADS + stop_finalization_thread (); + GC_set_finalizer_notifier (spawn_finalizer_thread); #endif +} + + + void scm_init_finalizers (void) @@ -180,3 +316,13 @@ scm_init_finalizers (void) SCM_BOOL_F); 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); +#endif +} |