When we shutdown we set suspend_finalizers flag in metadata so we no longer run any finalizers. After recent changes, we avoid traversing gc hashes for finalizer enqueuing when this flag is set. The counterpart, popping the queues empty (even without running the finalizers) can still take some time, especially since we lock for each entry. Exit early from this loop if we no longer need to run finalizers.
Achieve this by setting a new flag inside sgen, instead of passing the address of suspend_finalizers all the time to the sgen api.
{
}
+void
+mono_gc_suspend_finalizers (void)
+{
+}
+
int
mono_gc_get_suspend_signal (void)
{
void mono_gc_add_memory_pressure (gint64 value);
MONO_API int mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg);
void mono_gc_deregister_root (char* addr);
-void mono_gc_finalize_domain (MonoDomain *domain, volatile gboolean *suspend);
+void mono_gc_finalize_domain (MonoDomain *domain);
void mono_gc_run_finalize (void *obj, void *data);
void mono_gc_clear_domain (MonoDomain * domain);
+/* Signal early termination of finalizer processing inside the gc */
+void mono_gc_suspend_finalizers (void);
/*
gboolean log_finalizers = FALSE;
gboolean mono_do_not_finalize = FALSE;
+volatile gboolean suspend_finalizers = FALSE;
gchar **mono_do_not_finalize_class_names = NULL;
#define mono_finalizer_lock() mono_coop_mutex_lock (&finalizer_mutex)
return is_ok (error);
}
-static volatile gboolean suspend_finalizers = FALSE;
/*
* actually, we might want to queue the finalize requests in a separate thread,
* but we need to be careful about the execution domain of the thread...
g_ptr_array_free (objs, TRUE);
}
#elif defined(HAVE_SGEN_GC)
- mono_gc_finalize_domain (domain, &suspend_finalizers);
+ mono_gc_finalize_domain (domain);
mono_gc_invoke_finalizers ();
#endif
/* Set a flag which the finalizer thread can check */
suspend_finalizers = TRUE;
+ mono_gc_suspend_finalizers ();
/* Try to abort the thread, in the hope that it is running managed code */
mono_thread_internal_abort (gc_thread);
{
}
+void
+mono_gc_suspend_finalizers (void)
+{
+}
+
int
mono_gc_get_suspend_signal (void)
{
* @suspend is used for early termination of the enqueuing process.
*/
void
-mono_gc_finalize_domain (MonoDomain *domain, volatile gboolean *suspend)
+mono_gc_finalize_domain (MonoDomain *domain)
{
- sgen_finalize_if (object_in_domain_predicate, domain, suspend);
+ sgen_finalize_if (object_in_domain_predicate, domain);
+}
+
+void
+mono_gc_suspend_finalizers (void)
+{
+ sgen_set_suspend_finalizers ();
}
/*
/* LOCKING: requires that the GC lock is held */
static void
-finalize_with_predicate (SgenObjectPredicateFunc predicate, void *user_data, volatile gboolean *suspend, SgenHashTable *hash_table)
+finalize_with_predicate (SgenObjectPredicateFunc predicate, void *user_data, SgenHashTable *hash_table)
{
GCObject *object;
gpointer dummy G_GNUC_UNUSED;
SGEN_LOG (5, "Enqueuing object for finalization: %p (%s) (%d)", object, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (object)), sgen_hash_table_num_entries (hash_table));
}
- if (*suspend)
+ if (sgen_suspend_finalizers)
break;
} SGEN_HASH_TABLE_FOREACH_END;
}
* objects are still alive.
*/
void
-sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data, volatile gboolean *suspend)
+sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data)
{
LOCK_GC;
sgen_process_fin_stage_entries ();
- finalize_with_predicate (predicate, user_data, suspend, &minor_finalizable_hash);
- finalize_with_predicate (predicate, user_data, suspend, &major_finalizable_hash);
+ finalize_with_predicate (predicate, user_data, &minor_finalizable_hash);
+ finalize_with_predicate (predicate, user_data, &major_finalizable_hash);
UNLOCK_GC;
}
*/
static volatile gboolean pending_unqueued_finalizer = FALSE;
+volatile gboolean sgen_suspend_finalizers = FALSE;
+
+void
+sgen_set_suspend_finalizers (void)
+{
+ sgen_suspend_finalizers = TRUE;
+}
int
sgen_gc_invoke_finalizers (void)
gboolean
sgen_have_pending_finalizers (void)
{
+ if (sgen_suspend_finalizers)
+ return FALSE;
return pending_unqueued_finalizer || !sgen_pointer_queue_is_empty (&fin_ready_queue) || !sgen_pointer_queue_is_empty (&critical_fin_queue);
}
gboolean sgen_have_pending_finalizers (void);
void sgen_object_register_for_finalization (GCObject *obj, void *user_data);
-void sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data, volatile gboolean *suspend);
+void sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data);
void sgen_remove_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, int generation);
+void sgen_set_suspend_finalizers (void);
void sgen_register_disappearing_link (GCObject *obj, void **link, gboolean track, gboolean in_gc);
extern gboolean sgen_try_free_some_memory;
extern mword total_promoted_size;
extern mword total_allocated_major;
-
+extern volatile gboolean sgen_suspend_finalizers;
extern MonoCoopMutex gc_mutex;
/* Nursery helpers. */