[sgen] Avoid popping the entire finalizer queues if finalizers are suspended
[mono.git] / mono / metadata / gc.c
index 79293d97b9910f8440b5d69e627551a27a031c2a..c3d240c0d77a0a841a75b450af4a153b54e532b7 100644 (file)
@@ -38,6 +38,7 @@
 #include <mono/utils/mono-time.h>
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include <mono/utils/atomic.h>
 #include <mono/utils/mono-coop-semaphore.h>
 #include <mono/utils/hazard-pointer.h>
@@ -57,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)
@@ -104,7 +106,6 @@ add_thread_to_finalize (MonoInternalThread *thread, MonoError *error)
        return is_ok (error);
 }
 
-static 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...
@@ -692,12 +693,6 @@ finalize_domain_objects (DomainFinalizationReq *req)
 {
        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 ();
 
@@ -723,12 +718,8 @@ finalize_domain_objects (DomainFinalizationReq *req)
                g_ptr_array_free (objs, TRUE);
        }
 #elif defined(HAVE_SGEN_GC)
-       while ((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);
+       mono_gc_invoke_finalizers ();
 #endif
 
        /* cleanup the reference queue */
@@ -869,7 +860,6 @@ mono_gc_cleanup (void)
        if (!gc_disabled) {
                finished = TRUE;
                if (mono_thread_internal_current () != gc_thread) {
-                       gboolean timed_out = FALSE;
                        gint64 start_ticks = mono_msec_ticks ();
                        gint64 end_ticks = start_ticks + 2000;
 
@@ -895,33 +885,33 @@ 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_stop (gc_thread);
+                               mono_thread_internal_abort (gc_thread);
 
                                /* Wait for it to stop */
                                ret = guarded_wait (gc_thread->handle, 100, TRUE);
 
                                if (ret == WAIT_TIMEOUT) {
-                                       /* 
-                                        * The finalizer thread refused to die. There is not much we 
-                                        * can do here, since the runtime is shutting down so the 
-                                        * state the finalizer thread depends on will vanish.
+                                       /*
+                                        * The finalizer thread refused to exit. Make it stop.
                                         */
-                                       g_warning ("Shutting down finalizer thread timed out.");
-                                       timed_out = TRUE;
+                                       mono_thread_internal_stop (gc_thread);
+                                       ret = guarded_wait (gc_thread->handle, 100, TRUE);
+                                       g_assert (ret != WAIT_TIMEOUT);
+                                       /* The thread can't set this flag */
+                                       finalizer_thread_exited = TRUE;
                                }
                        }
 
-                       if (!timed_out) {
-                               int ret;
+                       int ret;
 
-                               /* Wait for the thread to actually exit */
-                               ret = guarded_wait (gc_thread->handle, INFINITE, TRUE);
-                               g_assert (ret == WAIT_OBJECT_0);
+                       /* Wait for the thread to actually exit */
+                       ret = guarded_wait (gc_thread->handle, INFINITE, TRUE);
+                       g_assert (ret == WAIT_OBJECT_0);
 
-                               mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
-                       }
+                       mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
                        g_assert (finalizer_thread_exited);
                }
                gc_thread = NULL;