diff options
Diffstat (limited to 'libguile/whippet/api/gc-finalizer.h')
-rw-r--r-- | libguile/whippet/api/gc-finalizer.h | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/libguile/whippet/api/gc-finalizer.h b/libguile/whippet/api/gc-finalizer.h new file mode 100644 index 000000000..1dcb0fb2f --- /dev/null +++ b/libguile/whippet/api/gc-finalizer.h @@ -0,0 +1,81 @@ +#ifndef GC_FINALIZER_H_ +#define GC_FINALIZER_H_ + +#include "gc-edge.h" +#include "gc-ref.h" +#include "gc-visibility.h" + +// A finalizer allows the embedder to be notified when an object becomes +// unreachable. +// +// A finalizer has a priority. When the heap is created, the embedder +// should declare how many priorities there are. Lower-numbered +// priorities take precedence; if an object has a priority-0 finalizer +// outstanding, that will prevent any finalizer at level 1 (or 2, ...) +// from firing until no priority-0 finalizer remains. +// +// Call gc_attach_finalizer to attach a finalizer to an object. +// +// A finalizer also references an associated GC-managed closure object. +// A finalizer's reference to the closure object is strong: if a +// finalizer's closure closure references its finalizable object, +// directly or indirectly, the finalizer will never fire. +// +// When an object with a finalizer becomes unreachable, it is added to a +// queue. The embedder can call gc_pop_finalizable to get the next +// finalizable object and its associated closure. At that point the +// embedder can do anything with the object, including keeping it alive. +// Ephemeron associations will still be present while the finalizable +// object is live. Note however that any objects referenced by the +// finalizable object may themselves be already finalized; finalizers +// are enqueued for objects when they become unreachable, which can +// concern whole subgraphs of objects at once. +// +// The usual way for an embedder to know when the queue of finalizable +// object is non-empty is to call gc_set_finalizer_callback to +// provide a function that will be invoked when there are pending +// finalizers. +// +// Arranging to call gc_pop_finalizable and doing something with the +// finalizable object and closure is the responsibility of the embedder. +// The embedder's finalization action can end up invoking arbitrary +// code, so unless the embedder imposes some kind of restriction on what +// finalizers can do, generally speaking finalizers should be run in a +// dedicated thread instead of recursively from within whatever mutator +// thread caused GC. Setting up such a thread is the responsibility of +// the mutator. gc_pop_finalizable is thread-safe, allowing multiple +// finalization threads if that is appropriate. +// +// gc_allocate_finalizer returns a finalizer, which is a fresh +// GC-managed heap object. The mutator should then directly attach it +// to an object using gc_finalizer_attach. When the finalizer is fired, +// it becomes available to the mutator via gc_pop_finalizable. + +struct gc_heap; +struct gc_mutator; +struct gc_finalizer; + +GC_API_ size_t gc_finalizer_size(void); +GC_API_ struct gc_finalizer* gc_allocate_finalizer(struct gc_mutator *mut); +GC_API_ void gc_finalizer_attach(struct gc_mutator *mut, + struct gc_finalizer *finalizer, + unsigned priority, + struct gc_ref object, struct gc_ref closure); + +GC_API_ struct gc_ref gc_finalizer_object(struct gc_finalizer *finalizer); +GC_API_ struct gc_ref gc_finalizer_closure(struct gc_finalizer *finalizer); + +GC_API_ struct gc_finalizer* gc_pop_finalizable(struct gc_mutator *mut); + +typedef void (*gc_finalizer_callback)(struct gc_heap *heap, size_t count); +GC_API_ void gc_set_finalizer_callback(struct gc_heap *heap, + gc_finalizer_callback callback); + +GC_API_ void gc_trace_finalizer(struct gc_finalizer *finalizer, + void (*visit)(struct gc_edge edge, + struct gc_heap *heap, + void *visit_data), + struct gc_heap *heap, + void *trace_data); + +#endif // GC_FINALIZER_H_ |