[sgen] Avoid popping the entire finalizer queues if finalizers are suspended
authorVlad Brezae <brezaevlad@gmail.com>
Mon, 25 Jul 2016 17:40:59 +0000 (20:40 +0300)
committerVlad Brezae <brezaevlad@gmail.com>
Wed, 27 Jul 2016 00:09:53 +0000 (03:09 +0300)
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.

mono/metadata/boehm-gc.c
mono/metadata/gc-internals.h
mono/metadata/gc.c
mono/metadata/null-gc.c
mono/metadata/sgen-mono.c
mono/sgen/sgen-fin-weak-hash.c
mono/sgen/sgen-gc.c
mono/sgen/sgen-gc.h

index e76a3a3bfb7b6f581f9bceb8aa2eb711e4b01c38..41510b486e88139695f0f0109332effe0b59557f 100644 (file)
@@ -829,6 +829,11 @@ mono_gc_clear_domain (MonoDomain *domain)
 {
 }
 
+void
+mono_gc_suspend_finalizers (void)
+{
+}
+
 int
 mono_gc_get_suspend_signal (void)
 {
index 2fa32269a80ee85433a4f042d50d5e454bdcbaa5..b5a19af282f4aa6e588dc7f1f28aef511acd9a7e 100644 (file)
@@ -161,9 +161,11 @@ void  mono_gc_register_for_finalization (MonoObject *obj, void *user_data);
 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);
 
 
 /* 
index f077719380c8e178c8dbfeb36f33d8b686c07219..c3d240c0d77a0a841a75b450af4a153b54e532b7 100644 (file)
@@ -58,6 +58,7 @@ static gboolean finalizing_root_domain = FALSE;
 
 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)
@@ -105,7 +106,6 @@ add_thread_to_finalize (MonoInternalThread *thread, MonoError *error)
        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...
@@ -718,7 +718,7 @@ finalize_domain_objects (DomainFinalizationReq *req)
                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
 
@@ -885,6 +885,7 @@ mono_gc_cleanup (void)
 
                                /* 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);
index f987e6c34837248b7368e0e19dda783615a0a3bd..c1a531c0dc87eac782c46785a481b82df532abc6 100644 (file)
@@ -364,6 +364,11 @@ mono_gc_clear_domain (MonoDomain *domain)
 {
 }
 
+void
+mono_gc_suspend_finalizers (void)
+{
+}
+
 int
 mono_gc_get_suspend_signal (void)
 {
index 247818656b5d2d502fc0e88f08ab0ed867b17435..a71dcb843d4b8851cb96109495253ca8bff7716c 100644 (file)
@@ -529,9 +529,15 @@ object_in_domain_predicate (MonoObject *obj, void *user_data)
  * @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 ();
 }
 
 /*
index f6cab27ec4fe5a2909833626145752e954be043d..bef8bcded6fdb1ea3440012debe30e9a21ac7996 100644 (file)
@@ -558,7 +558,7 @@ sgen_object_register_for_finalization (GCObject *obj, void *user_data)
 
 /* 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;
@@ -575,7 +575,7 @@ finalize_with_predicate (SgenObjectPredicateFunc predicate, void *user_data, vol
                        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;
 }
@@ -597,12 +597,12 @@ finalize_with_predicate (SgenObjectPredicateFunc predicate, void *user_data, vol
  * 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;
 }
 
index 3dac1df3d8dfb82cc4c835eba8d0b59c4c5ad603..bfad162f901acdffe888fffad7c6876b09203562 100644 (file)
@@ -2408,6 +2408,13 @@ sgen_object_is_live (GCObject *obj)
  */
 
 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)
@@ -2463,6 +2470,8 @@ 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);
 }
 
index c08502dc55e2e0517bbf59df732619f56ae42748..7df0515d8d8706d9a4b534d0638a04a1fd668377 100644 (file)
@@ -813,8 +813,9 @@ void sgen_process_fin_stage_entries (void);
 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);
 
@@ -977,7 +978,7 @@ extern NurseryClearPolicy nursery_clear_policy;
 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. */