+#ifdef THREADS
+ /* Defined in pthread_support.c or win32_threads.c. Called with the */
+ /* allocation lock held. */
+ GC_INNER void GC_reset_finalizer_nested(void);
+ GC_INNER unsigned *GC_check_finalizer_nested(void);
+#else
+ /* Global variables to minimize the level of recursion when a client */
+ /* finalizer allocates memory. */
+ STATIC unsigned GC_finalizer_nested = 0;
+ STATIC unsigned GC_finalizer_skipped = 0;
+
+ /* Checks and updates the level of finalizers recursion. */
+ /* Returns NULL if GC_invoke_finalizers() should not be called by the */
+ /* collector (to minimize the risk of a deep finalizers recursion), */
+ /* otherwise returns a pointer to GC_finalizer_nested. */
+ STATIC unsigned *GC_check_finalizer_nested(void)
+ {
+ unsigned nesting_level = GC_finalizer_nested;
+ if (nesting_level) {
+ /* We are inside another GC_invoke_finalizers(). */
+ /* Skip some implicitly-called GC_invoke_finalizers() */
+ /* depending on the nesting (recursion) level. */
+ if (++GC_finalizer_skipped < (1U << nesting_level)) return NULL;
+ GC_finalizer_skipped = 0;
+ }
+ GC_finalizer_nested = nesting_level + 1;
+ return &GC_finalizer_nested;
+ }
+#endif /* THREADS */
+
+/* Called with held lock (but the world is running). */
+/* Cause disappearing links to disappear and unreachable objects to be */
+/* enqueued for finalization. */
+GC_INNER void GC_finalize(void)