Re: [Gc] Two-phase finalization?
David Kastrup <dak-mXXj517/[email protected]> Sun, 08 Nov 2015 22:42:03 +0100
| Newsgroups | gmane.comp.programming.garbage-collection.boehmgc |
|---|---|
| Message-ID | <[email protected]> |
Florian Weimer <[email protected]> writes: > * David Kastrup: > >> Now the problem we encounter is that if some structure A points to B and >> some structure B points to A and both A and B are placed into >> finalization, then the finalization of A will delete the associated C++ >> structure. If now a mark pass is allowed through B, it will try to >> access the deleted C++ structure of A. >> >> Topological ordering will not do the trick since cyclical references are >> quite typical (a NoteHead has a reference to the corresponding Stem, a >> Stem has references to all corresponding NoteHeads). > > Have all of them corresponding C++ objects? Do you want the garbage > collector to devise a safe deallocation order, or does deallocation > happen by another mechanism? No, a "safe deallocation order" is unachievable because of cycles. Guile has replaced its own allocator with the Boehm GC. There is a mismatch in semantics for type hooks registered with scm_set_smob_free/scm_set_smob_mark which have the following description: -- C Function: void scm_set_smob_free (scm_t_bits tc, size_t (*free) (SCM obj)) This function sets the smob freeing procedure (sometimes referred to as a "finalizer") for the smob type specified by the tag TC. TC is the tag returned by ‘scm_make_smob_type’. The FREE procedure must deallocate all resources that are directly associated with the smob instance OBJ. It must assume that all ‘SCM’ values that it references have already been freed and are thus invalid. It must also not call any libguile function or macro except ‘scm_gc_free’, ‘SCM_SMOB_FLAGS’, ‘SCM_SMOB_DATA’, ‘SCM_SMOB_DATA_2’, and ‘SCM_SMOB_DATA_3’. The FREE procedure must return 0. Note that defining a freeing procedure is not necessary if the resources associated with OBJ consists only of memory allocated with ‘scm_gc_malloc’ or ‘scm_gc_malloc_pointerless’ because this memory is automatically reclaimed by the garbage collector when it is no longer needed (*note ‘scm_gc_malloc’: Memory Blocks.). -- C Function: void scm_set_smob_mark (scm_t_bits tc, SCM (*mark) (SCM obj)) This function sets the smob marking procedure for the smob type specified by the tag TC. TC is the tag returned by ‘scm_make_smob_type’. Defining a marking procedure may sometimes be unnecessary because large parts of the process’ memory (with the exception of ‘scm_gc_malloc_pointerless’ regions, and ‘malloc’- or ‘scm_malloc’-allocated memory) are scanned for live pointers(1). The MARK procedure must cause ‘scm_gc_mark’ to be called for every ‘SCM’ value that is directly referenced by the smob instance OBJ. One of these ‘SCM’ values can be returned from the procedure and Guile will call ‘scm_gc_mark’ for it. This can be used to avoid deep recursions for smob instances that form a list. It must not call any libguile function or macro except ‘scm_gc_mark’, ‘SCM_SMOB_FLAGS’, ‘SCM_SMOB_DATA’, ‘SCM_SMOB_DATA_2’, and ‘SCM_SMOB_DATA_3’. Note in particular that scm_set_smob_free states: The FREE procedure must deallocate all resources that are directly associated with the smob instance OBJ. It must assume that all ‘SCM’ values that it references have already been freed and are thus invalid. In contrast to that, finalizers in Boehm GC work with fully valid objects. In particular, mark passes are made through the finalized data that expect operative data and consequently call for topologically sorted finalization while scm_set_smob_free may not depend on any valid pointers for doing its work: it really is much more related to destructing objects than to finalizing them. I _think_ that reading gc.h I have found a workable solution: set Java collection semantics with GC_set_java_finalization (1); GC_API GC_ATTR_DEPRECATED int GC_java_finalization; /* Mark objects reachable from finalizable */ /* objects in a separate post-pass. This makes */ /* it a bit safer to use non-topologically- */ /* ordered finalization. Default value is */ /* determined by JAVA_FINALIZATION macro. */ /* Enables register_finalizer_unreachable to */ /* work correctly. */ /* The setter and getter are unsynchronized. */ GC_API void GC_CALL GC_set_java_finalization(int); GC_API int GC_CALL GC_get_java_finalization(void); And then, during finalization, clear out each finalized object's Guile type-id so that no more hooks (in particular no hook set with scm_set_smob_mark) will be called in any separate post-pass and no dependency on the destructed C++ objects or their memory exists at the time of the post-pass (not that I understand the post-pass' utility in the first place but that apparently is what's causing the problems shown in <URL:http://debbugs.gnu.org/cgi/bugreport.cgi?bug=19883>). As far as I understand the code, the Guile-2 code base already does set GC_java_finalization. So all that should remain would be clearing out the type identification for data at finalization time. -- David Kastrup _______________________________________________ bdwgc mailing list [email protected] https://lists.opendylan.org/mailman/listinfo/bdwgc