For objects that die at the same time, normal finalizers should be run before critical finalizers. When we were unloading a domain we were running finalizers for all objects in that domain without checking whether the finalizer is critical or not. Now we enqueue the objects first in the finalization queues so we can run all the normal finalizers before the critical ones.
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);
-int mono_gc_finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size);
+void mono_gc_finalize_domain (MonoDomain *domain, volatile gboolean *suspend);
void mono_gc_run_finalize (void *obj, void *data);
void mono_gc_clear_domain (MonoDomain * domain);
{
MonoDomain *domain = req->domain;
-#if HAVE_SGEN_GC
-#define NUM_FOBJECTS 64
- MonoObject *to_finalize [NUM_FOBJECTS];
- int count;
-#endif
-
/* Process finalizers which are already in the queue */
mono_gc_invoke_finalizers ();
g_ptr_array_free (objs, TRUE);
}
#elif defined(HAVE_SGEN_GC)
- while (!suspend_finalizers && (count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
- int i;
- for (i = 0; i < count; ++i) {
- mono_gc_run_finalize (to_finalize [i], 0);
- }
- }
+ mono_gc_finalize_domain (domain, &suspend_finalizers);
+ mono_gc_invoke_finalizers ();
#endif
/* cleanup the reference queue */
* @out_array: output array
* @out_size: size of output array
*
- * Store inside @out_array up to @out_size objects that belong to the unloading
- * appdomain @domain. Returns the number of stored items. Can be called repeteadly
- * until it returns 0.
- * The items are removed from the finalizer data structure, so the caller is supposed
- * to finalize them.
- * @out_array should be on the stack to allow the GC to know the objects are still alive.
+ * Enqueue for finalization all objects that belong to the unloading appdomain @domain
+ * @suspend is used for early termination of the enqueuing process.
*/
-int
-mono_gc_finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size)
+void
+mono_gc_finalize_domain (MonoDomain *domain, volatile gboolean *suspend)
{
- return sgen_gather_finalizers_if (object_in_domain_predicate, domain, out_array, out_size);
+ sgen_finalize_if (object_in_domain_predicate, domain, suspend);
}
/*
}
/* LOCKING: requires that the GC lock is held */
-static int
-finalizers_with_predicate (SgenObjectPredicateFunc predicate, void *user_data, GCObject **out_array, int out_size, SgenHashTable *hash_table)
+static void
+finalize_with_predicate (SgenObjectPredicateFunc predicate, void *user_data, volatile gboolean *suspend, SgenHashTable *hash_table)
{
GCObject *object;
gpointer dummy G_GNUC_UNUSED;
- int count;
- if (no_finalize || !out_size || !out_array)
+ if (no_finalize)
return 0;
- count = 0;
SGEN_HASH_TABLE_FOREACH (hash_table, GCObject *, object, gpointer, dummy) {
object = tagged_object_get_object (object);
if (predicate (object, user_data)) {
/* remove and put in out_array */
SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
- out_array [count ++] = object;
- SGEN_LOG (5, "Collecting object for finalization: %p (%s) (%d)", object, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (object)), sgen_hash_table_num_entries (hash_table));
- if (count == out_size)
- return count;
- continue;
+ sgen_queue_finalization_entry (object);
+ 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)
+ break;
} SGEN_HASH_TABLE_FOREACH_END;
- return count;
}
/**
* @out_array me be on the stack, or registered as a root, to allow the GC to know the
* objects are still alive.
*/
-int
-sgen_gather_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, GCObject **out_array, int out_size)
+void
+sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data, volatile gboolean *suspend)
{
- int result;
-
LOCK_GC;
sgen_process_fin_stage_entries ();
- result = finalizers_with_predicate (predicate, user_data, (GCObject**)out_array, out_size, &minor_finalizable_hash);
- if (result < out_size) {
- result += finalizers_with_predicate (predicate, user_data, (GCObject**)out_array + result, out_size - result,
- &major_finalizable_hash);
- }
+ finalize_with_predicate (predicate, user_data, suspend, &minor_finalizable_hash);
+ finalize_with_predicate (predicate, user_data, suspend, &major_finalizable_hash);
UNLOCK_GC;
-
- return result;
}
void
gboolean sgen_have_pending_finalizers (void);
void sgen_object_register_for_finalization (GCObject *obj, void *user_data);
-int sgen_gather_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, GCObject **out_array, int out_size);
+void sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data, volatile gboolean *suspend);
void sgen_remove_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, int generation);
void sgen_register_disappearing_link (GCObject *obj, void **link, gboolean track, gboolean in_gc);