void GC_notify_or_invoke_finalizers(void) { /* This is a convenient place to generate backtraces if appropriate, */ /* since that code is not callable with the allocation lock. */ # if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) static word last_back_trace_gc_no = 1; /* Skip first one. */ if (GC_gc_no > last_back_trace_gc_no) { word i; # ifdef KEEP_BACK_PTRS LOCK(); /* Stops when GC_gc_no wraps; that's OK. */ last_back_trace_gc_no = (word)(-1); /* disable others. */ for (i = 0; i < GC_backtraces; ++i) { /* FIXME: This tolerates concurrent heap mutation, */ /* which may cause occasional mysterious results. */ /* We need to release the GC lock, since GC_print_callers */ /* acquires it. It probably shouldn't. */ UNLOCK(); GC_generate_random_backtrace_no_gc(); LOCK(); } last_back_trace_gc_no = GC_gc_no; UNLOCK(); # endif # ifdef MAKE_BACK_GRAPH if (GC_print_back_height) GC_print_back_graph_stats(); # endif } # endif if (GC_finalize_now == 0) return; if (!GC_finalize_on_demand) { (void) GC_invoke_finalizers(); # ifndef THREADS GC_ASSERT(GC_finalize_now == 0); # endif /* Otherwise GC can run concurrently and add more */ return; } if (GC_finalizer_notifier != (void (*) (void))0 && last_finalizer_notification != GC_gc_no) { last_finalizer_notification = GC_gc_no; GC_finalizer_notifier(); } }
GC_INNER void GC_notify_or_invoke_finalizers(void) { GC_finalizer_notifier_proc notifier_fn = 0; # if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) static word last_back_trace_gc_no = 1; /* Skip first one. */ # endif DCL_LOCK_STATE; # if defined(THREADS) && !defined(KEEP_BACK_PTRS) \ && !defined(MAKE_BACK_GRAPH) /* Quick check (while unlocked) for an empty finalization queue. */ if (NULL == GC_fnlz_roots.finalize_now) return; # endif LOCK(); /* This is a convenient place to generate backtraces if appropriate, */ /* since that code is not callable with the allocation lock. */ # if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) if (GC_gc_no > last_back_trace_gc_no) { # ifdef KEEP_BACK_PTRS long i; /* Stops when GC_gc_no wraps; that's OK. */ last_back_trace_gc_no = (word)(-1); /* disable others. */ for (i = 0; i < GC_backtraces; ++i) { /* FIXME: This tolerates concurrent heap mutation, */ /* which may cause occasional mysterious results. */ /* We need to release the GC lock, since GC_print_callers */ /* acquires it. It probably shouldn't. */ UNLOCK(); GC_generate_random_backtrace_no_gc(); LOCK(); } last_back_trace_gc_no = GC_gc_no; # endif # ifdef MAKE_BACK_GRAPH if (GC_print_back_height) { UNLOCK(); GC_print_back_graph_stats(); LOCK(); } # endif } # endif if (NULL == GC_fnlz_roots.finalize_now) { UNLOCK(); return; } if (!GC_finalize_on_demand) { unsigned char *pnested = GC_check_finalizer_nested(); UNLOCK(); /* Skip GC_invoke_finalizers() if nested */ if (pnested != NULL) { (void) GC_invoke_finalizers(); *pnested = 0; /* Reset since no more finalizers. */ # ifndef THREADS GC_ASSERT(NULL == GC_fnlz_roots.finalize_now); # endif /* Otherwise GC can run concurrently and add more */ } return; } /* These variables require synchronization to avoid data races. */ if (last_finalizer_notification != GC_gc_no) { last_finalizer_notification = GC_gc_no; notifier_fn = GC_finalizer_notifier; } UNLOCK(); if (notifier_fn != 0) (*notifier_fn)(); /* Invoke the notifier */ }