diff --git a/libguile/finalizers.c b/libguile/finalizers.c index 6e44b37fe..45b063f30 100644 --- a/libguile/finalizers.c +++ b/libguile/finalizers.c @@ -33,20 +33,24 @@ #include "async.h" #include "atomics-internal.h" -#include "bdw-gc.h" +#include "continuations.h" #include "eval.h" #include "extensions.h" #include "foreign.h" -#include "gc.h" +#include "gc-internal.h" #include "gsubr.h" +#include "guardians.h" #include "init.h" #include "numbers.h" #include "ports.h" -#include "struct.h" #include "smob.h" +#include "struct.h" +#include "symbols.h" #include "threads.h" #include "version.h" +#include + #include "finalizers.h" @@ -67,116 +71,40 @@ enum finalizer_priority FINALIZER_PRIORITY_DEFAULT }; +enum builtin_finalizer_kind + { + FINALIZE_KIND_STRUCT, + FINALIZE_KIND_SMOB, + FINALIZE_KIND_PORT, + }; -void -scm_i_set_finalizer (void *obj, scm_t_finalizer_proc proc, void *data) +static inline SCM ref_to_scm (struct gc_ref ref) { - GC_finalization_proc prev; - void *prev_data; - GC_REGISTER_FINALIZER_NO_ORDER (obj, proc, data, &prev, &prev_data); + return SCM_PACK (gc_ref_value (ref)); +} +static inline struct gc_ref scm_to_ref (SCM scm) +{ + return gc_ref (SCM_UNPACK (scm)); } -struct scm_t_chained_finalizer +static SCM +add_finalizer (struct scm_thread *thread, SCM obj, SCM closure, + enum finalizer_priority priority) { - int resuscitating_p; - scm_t_finalizer_proc proc; - void *data; - scm_t_finalizer_proc prev; - void *prev_data; -}; - -static void -chained_finalizer (void *obj, void *data) -{ - struct scm_t_chained_finalizer *chained_data = data; - if (chained_data->resuscitating_p) - { - if (chained_data->prev) - scm_i_set_finalizer (obj, chained_data->prev, chained_data->prev_data); - chained_data->proc (obj, chained_data->data); - } - else - { - chained_data->proc (obj, chained_data->data); - if (chained_data->prev) - chained_data->prev (obj, chained_data->prev_data); - } + struct gc_finalizer *finalizer = gc_allocate_finalizer (thread->mutator); + SCM ret = SCM_PACK_POINTER (finalizer); + SCM_SET_CELL_WORD_0 (ret, scm_tc7_finalizer); + gc_finalizer_attach (thread->mutator, finalizer, priority, + scm_to_ref (obj), scm_to_ref (closure)); + return ret; } -void -scm_i_add_resuscitator (void *obj, scm_t_finalizer_proc proc, void *data) +static SCM +add_builtin_finalizer (struct scm_thread *thread, SCM obj, + enum builtin_finalizer_kind kind) { - struct scm_t_chained_finalizer *chained_data; - chained_data = scm_gc_malloc (sizeof (*chained_data), "chained finalizer"); - chained_data->resuscitating_p = 1; - chained_data->proc = proc; - chained_data->data = data; - GC_REGISTER_FINALIZER_NO_ORDER (obj, chained_finalizer, chained_data, - &chained_data->prev, - &chained_data->prev_data); -} - -static void -shuffle_resuscitators_to_front (struct scm_t_chained_finalizer *cd) -{ - while (cd->prev == chained_finalizer) - { - struct scm_t_chained_finalizer *prev = cd->prev_data; - scm_t_finalizer_proc proc = cd->proc; - void *data = cd->data; - - if (!prev->resuscitating_p) - break; - - cd->resuscitating_p = 1; - cd->proc = prev->proc; - cd->data = prev->data; - - prev->resuscitating_p = 0; - prev->proc = proc; - prev->data = data; - - cd = prev; - } -} - -void -scm_i_add_finalizer (void *obj, scm_t_finalizer_proc proc, void *data) -{ - struct scm_t_chained_finalizer *chained_data; - chained_data = scm_gc_malloc (sizeof (*chained_data), "chained finalizer"); - chained_data->resuscitating_p = 0; - chained_data->proc = proc; - chained_data->data = data; - GC_REGISTER_FINALIZER_NO_ORDER (obj, chained_finalizer, chained_data, - &chained_data->prev, - &chained_data->prev_data); - shuffle_resuscitators_to_front (chained_data); -} - -static void -struct_finalizer_trampoline (void *ptr, void *data) -{ - scm_i_finalize_struct (SCM_I_CURRENT_THREAD, PTR2SCM (ptr)); -} - -static void -smob_finalizer_trampoline (void *ptr, void *data) -{ - scm_i_finalize_smob (SCM_I_CURRENT_THREAD, PTR2SCM (ptr)); -} - -static void -port_finalizer_trampoline (void *ptr, void *data) -{ - scm_i_finalize_port (SCM_I_CURRENT_THREAD, PTR2SCM (ptr)); -} - -static void -pointer_finalizer_trampoline (void *ptr, void *data) -{ - scm_i_finalize_pointer (SCM_I_CURRENT_THREAD, PTR2SCM (ptr), - PTR2SCM (data)); + return add_finalizer (thread, obj, SCM_I_MAKINUM (kind), + FINALIZER_PRIORITY_DEFAULT); } SCM @@ -185,8 +113,7 @@ scm_i_add_struct_finalizer (struct scm_thread *thread, SCM obj) if (!SCM_STRUCTP (obj)) abort (); - scm_i_set_finalizer (SCM2PTR (obj), struct_finalizer_trampoline, NULL); - return SCM_UNSPECIFIED; + return add_builtin_finalizer (thread, obj, FINALIZE_KIND_STRUCT); } SCM @@ -195,8 +122,7 @@ scm_i_add_smob_finalizer (struct scm_thread *thread, SCM obj) if (!SCM_HAS_TYP7 (obj, scm_tc7_smob)) abort (); - scm_i_set_finalizer (SCM2PTR (obj), smob_finalizer_trampoline, NULL); - return SCM_UNSPECIFIED; + return add_builtin_finalizer (thread, obj, FINALIZE_KIND_SMOB); } SCM @@ -205,8 +131,7 @@ scm_i_add_port_finalizer (struct scm_thread *thread, SCM obj) if (!SCM_PORTP (obj)) abort (); - scm_i_set_finalizer (SCM2PTR (obj), port_finalizer_trampoline, NULL); - return SCM_UNSPECIFIED; + return add_builtin_finalizer (thread, obj, FINALIZE_KIND_PORT); } SCM @@ -217,15 +142,98 @@ scm_i_add_pointer_finalizer (struct scm_thread *thread, SCM obj, SCM free) if (!SCM_POINTER_P (free)) abort (); - scm_i_set_finalizer (SCM2PTR (obj), pointer_finalizer_trampoline, - SCM2PTR(free)); - return SCM_UNSPECIFIED; + return add_finalizer (thread, obj, free, FINALIZER_PRIORITY_DEFAULT); } -static void -invoke_finalizer (void *obj, void *data) +SCM +scm_i_add_finalizer (struct scm_thread *thread, SCM obj, SCM proc) { - scm_call_1 (PTR2SCM (data), PTR2SCM (obj)); + if (!scm_is_true (scm_procedure_p (proc))) + abort (); + + return add_finalizer (thread, obj, proc, FINALIZER_PRIORITY_DEFAULT); +} + +SCM +scm_i_add_guardian_finalizer (struct scm_thread *thread, SCM obj, SCM guardian) +{ + if (!scm_is_true (scm_procedure_p (guardian))) + abort (); + + return add_finalizer (thread, obj, guardian, FINALIZER_PRIORITY_GUARDIAN); +} + +/* In future, we can add methods on the finalizer to retrieve the + object, cancel the finalizer, etc. */ + +static void +run_finalizer (struct scm_thread *thread, SCM obj, SCM closure) +{ + if (SCM_I_INUMP (closure)) + { + switch (SCM_I_INUM (closure)) + { + case FINALIZE_KIND_STRUCT: + scm_i_finalize_struct (thread, obj); + break; + case FINALIZE_KIND_SMOB: + scm_i_finalize_smob (thread, obj); + break; + case FINALIZE_KIND_PORT: + scm_i_finalize_port (thread, obj); + break; + default: + abort (); + } + } + else if (SCM_POINTER_P (closure)) + { + if (!SCM_POINTER_P (obj)) + abort (); + void (*free)(void*) = SCM_POINTER_VALUE (closure); + free (SCM_POINTER_VALUE (obj)); + } + else + scm_call_1 (closure, obj); +} + +struct run_finalizers_data { + scm_thread *thread; + SCM error_port; + int count; + int success; +}; + +static void* +run_finalizers (void *raw_data) +{ + struct run_finalizers_data *data = raw_data; + struct scm_thread *thread = data->thread; + struct gc_mutator *mut = thread->mutator; + for (struct gc_finalizer *finalizer = gc_pop_finalizable (mut); + finalizer; + finalizer = gc_pop_finalizable (mut), data->count++) + run_finalizer (thread, + ref_to_scm (gc_finalizer_object (finalizer)), + ref_to_scm (gc_finalizer_closure (finalizer))); + data->success = 1; + return NULL; +} + +int +scm_run_finalizers (void) +{ + struct run_finalizers_data data = { + .thread = SCM_I_CURRENT_THREAD, + .error_port = scm_current_error_port (), + .count = 0, + .success = 0 + }; + do + scm_c_with_continuation_barrier (run_finalizers, &data); + while (!data.success); + finalization_count += data.count; + return data.count; } SCM_DEFINE_STATIC(scm_sys_add_finalizer, "%add-finalizer!", 3, 0, 0, @@ -240,9 +248,7 @@ SCM_DEFINE_STATIC(scm_sys_add_finalizer, "%add-finalizer!", 3, 0, 0, FINALIZER_PRIORITY_GUARDIAN, FINALIZER_PRIORITY_DEFAULT); - (void) c_priority; - scm_i_add_finalizer (SCM2PTR (obj), invoke_finalizer, SCM2PTR (proc)); - return SCM_UNSPECIFIED; + return add_finalizer (SCM_I_CURRENT_THREAD, obj, proc, c_priority); } #undef FUNC_NAME @@ -258,18 +264,12 @@ run_finalizers_async_thunk (void) /* The function queue_finalizer_async is run by the GC when there are * objects to finalize. It will enqueue an asynchronous call to - * GC_invoke_finalizers() at the next SCM_TICK in this thread. + * scm_run_finalizers() at the next SCM_TICK in this thread. */ static void -queue_finalizer_async (void) +queue_finalizer_async (struct gc_heap *heap, size_t count) { scm_thread *t = SCM_I_CURRENT_THREAD; - - /* Could be that the current thread is is NULL when we're allocating - in threads.c:guilify_self_1. In that case, rely on the - GC_invoke_finalizers call there after the thread spins up. */ - if (!t) return; - scm_system_async_mark_for_thread (run_finalizers_subr, scm_thread_handle (t)); } @@ -285,7 +285,7 @@ static pthread_t finalization_thread; static int finalization_thread_is_running = 0; static void -notify_finalizers_to_run (void) +notify_finalizers_to_run (struct gc_heap *heap, size_t count) { char byte = 0; full_write (finalization_pipe[1], &byte, 1); @@ -383,7 +383,7 @@ run_finalization_thread (void *arg) } static void -start_finalization_thread (void) +start_finalization_thread (struct gc_heap *heap) { scm_i_pthread_mutex_lock (&finalization_thread_lock); if (!finalization_thread_is_running) @@ -404,7 +404,7 @@ start_finalization_thread (void) } else { - GC_set_finalizer_notifier (notify_finalizers_to_run); + gc_set_finalizer_callback (heap, notify_finalizers_to_run); finalization_thread_is_running = 1; } } @@ -428,9 +428,9 @@ stop_finalization_thread (void) } static void -spawn_finalizer_thread (void) +spawn_finalizer_thread (struct gc_heap *heap, size_t count) { - start_finalization_thread (); + start_finalization_thread (heap); } #else /* !SCM_USE_PTHREAD_THREADS */ @@ -453,7 +453,7 @@ scm_i_finalizer_pre_fork (void) if (automatic_finalization_p) { stop_finalization_thread (); - GC_set_finalizer_notifier (spawn_finalizer_thread); + gc_set_finalizer_callback (the_gc_heap, spawn_finalizer_thread); } #endif } @@ -478,14 +478,14 @@ scm_set_automatic_finalization_enabled (int enabled_p) if (enabled_p) { #if SCM_USE_PTHREAD_THREADS - GC_set_finalizer_notifier (spawn_finalizer_thread); + gc_set_finalizer_callback (the_gc_heap, spawn_finalizer_thread); #else - GC_set_finalizer_notifier (queue_finalizer_async); + gc_set_finalizer_callback (the_gc_heap, queue_finalizer_async); #endif } else { - GC_set_finalizer_notifier (0); + gc_set_finalizer_callback (the_gc_heap, NULL); #if SCM_USE_PTHREAD_THREADS stop_finalization_thread (); @@ -506,16 +506,6 @@ scm_i_print_finalizer (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED) return 1; } -int -scm_run_finalizers (void) -{ - int finalized = GC_invoke_finalizers (); - - finalization_count += finalized; - - return finalized; -} - @@ -539,7 +529,7 @@ scm_init_finalizers (void) run_finalizers_async_thunk); if (automatic_finalization_p) - GC_set_finalizer_notifier (queue_finalizer_async); + gc_set_finalizer_callback (the_gc_heap, queue_finalizer_async); } static void @@ -555,6 +545,6 @@ scm_init_finalizer_thread (void) { #if SCM_USE_PTHREAD_THREADS if (automatic_finalization_p) - GC_set_finalizer_notifier (spawn_finalizer_thread); + gc_set_finalizer_callback (the_gc_heap, spawn_finalizer_thread); #endif } diff --git a/libguile/finalizers.h b/libguile/finalizers.h index b30036c76..0265eb23d 100644 --- a/libguile/finalizers.h +++ b/libguile/finalizers.h @@ -26,15 +26,6 @@ -typedef void (*scm_t_finalizer_proc) (void *obj, void *data); - -SCM_INTERNAL void scm_i_set_finalizer (void *obj, scm_t_finalizer_proc, - void *data); -SCM_INTERNAL void scm_i_add_finalizer (void *obj, scm_t_finalizer_proc, - void *data); -SCM_INTERNAL void scm_i_add_resuscitator (void *obj, scm_t_finalizer_proc, - void *data); - SCM_INTERNAL SCM scm_i_add_struct_finalizer (struct scm_thread *thread, SCM obj); SCM_INTERNAL SCM scm_i_add_smob_finalizer (struct scm_thread *thread, @@ -43,6 +34,10 @@ SCM_INTERNAL SCM scm_i_add_port_finalizer (struct scm_thread *thread, SCM obj); SCM_INTERNAL SCM scm_i_add_pointer_finalizer (struct scm_thread *thread, SCM obj, SCM free); +SCM_INTERNAL SCM scm_i_add_finalizer (struct scm_thread *thread, SCM obj, + SCM proc); +SCM_INTERNAL SCM scm_i_add_guardian_finalizer (struct scm_thread *thread, + SCM obj, SCM proc); SCM_INTERNAL void scm_i_finalizer_pre_fork (void);