[runtime] Fix a crash on Windows during the cleanup phase caused by using a destroyed...
[mono.git] / mono / metadata / gc.c
index 3078e1c6db5c31fb15c1a122068d20b4b8fe8237..03273531193a1f042d36fb185ca99ead3f019565 100644 (file)
@@ -48,13 +48,6 @@ typedef struct DomainFinalizationReq {
        HANDLE done_event;
 } DomainFinalizationReq;
 
-#ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
-extern void (*__imp_GC_finalizer_notifier)(void);
-#define GC_finalizer_notifier __imp_GC_finalizer_notifier
-extern int __imp_GC_finalize_on_demand;
-#define GC_finalize_on_demand __imp_GC_finalize_on_demand
-#endif
-
 static gboolean gc_disabled = FALSE;
 
 static gboolean finalizing_root_domain = FALSE;
@@ -71,13 +64,8 @@ static GSList *domains_to_finalize= NULL;
 static MonoMList *threads_to_finalize = NULL;
 
 static gboolean finalizer_thread_exited;
-static int num_to_finalize;
-
-/* These use finalizer_mutex */
-/* Used to wait for finalizer_thread_exited to become TRUE */
+/* Uses finalizer_mutex */
 static mono_cond_t exited_cond;
-/* Used to wait for num_to_finalize to become > 0 */
-static mono_cond_t finalizer_cond;
 
 static MonoInternalThread *gc_thread;
 
@@ -211,7 +199,6 @@ mono_gc_run_finalize (void *obj, void *data)
 
        finalizer = mono_class_get_finalizer (o->vtable->klass);
 
-#ifndef DISABLE_COM
        /* If object has a CCW but has no finalizer, it was only
         * registered for finalization in order to free the CCW.
         * Else it needs the regular finalizer run.
@@ -222,7 +209,6 @@ mono_gc_run_finalize (void *obj, void *data)
                mono_domain_set_internal (caller_domain);
                return;
        }
-#endif
 
        /* 
         * To avoid the locking plus the other overhead of mono_runtime_invoke (),
@@ -511,8 +497,6 @@ ves_icall_System_GC_WaitForPendingFinalizers (void)
        if (gc_thread == NULL)
                return;
 
-       /* Can't use cond vars here, since they don't contain the wapi interrupt logic */
-
        ResetEvent (pending_done_event);
        mono_gc_finalize_notify ();
        /* g_print ("Waiting for pending finalizers....\n"); */
@@ -654,12 +638,12 @@ find_first_unset (guint32 bitmap)
        return -1;
 }
 
-static void*
+static MonoGCDescriptor
 make_root_descr_all_refs (int numbits, gboolean pinned)
 {
 #ifdef HAVE_SGEN_GC
        if (pinned)
-               return NULL;
+               return MONO_GC_DESCRIPTOR_NULL;
 #endif
        return mono_gc_make_root_descr_all_refs (numbits);
 }
@@ -1000,6 +984,10 @@ mono_gc_GCHandle_CheckCurrentDomain (guint32 gchandle)
        return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
 }
 
+#ifdef MONO_HAS_SEMAPHORES
+static MonoSemType finalizer_sem;
+#endif
+static HANDLE finalizer_event;
 static volatile gboolean finished=FALSE;
 
 void
@@ -1012,10 +1000,11 @@ mono_gc_finalize_notify (void)
        if (mono_gc_is_null ())
                return;
 
-       mono_mutex_lock (&finalizer_mutex);
-       num_to_finalize ++;
-       mono_cond_signal (&finalizer_cond);
-       mono_mutex_unlock (&finalizer_mutex);
+#ifdef MONO_HAS_SEMAPHORES
+       MONO_SEM_POST (&finalizer_sem);
+#else
+       SetEvent (finalizer_event);
+#endif
 }
 
 #ifdef HAVE_BOEHM_GC
@@ -1091,37 +1080,34 @@ finalize_domain_objects (DomainFinalizationReq *req)
 static guint32
 finalizer_thread (gpointer unused)
 {
+       gboolean wait = TRUE;
+
        while (!finished) {
-               /*
-                * Wait to be notified that there's at least one
+               /* Wait to be notified that there's at least one
                 * finaliser to run
                 */
-               g_assert (mono_domain_get () == mono_get_root_domain ());
 
-               gboolean has_work = FALSE;
-               while (TRUE) {
-                       mono_gc_set_skip_thread (TRUE);
-                       MONO_PREPARE_BLOCKING;
-                       mono_mutex_lock (&finalizer_mutex);
-                       if (!num_to_finalize)
-                               mono_cond_wait (&finalizer_cond, &finalizer_mutex);
-                       else
-                               has_work = TRUE;
-                       mono_mutex_unlock (&finalizer_mutex);
-                       MONO_FINISH_BLOCKING;
-                       mono_gc_set_skip_thread (FALSE);
+               g_assert (mono_domain_get () == mono_get_root_domain ());
+               mono_gc_set_skip_thread (TRUE);
+               MONO_PREPARE_BLOCKING
 
-                       if (has_work || finished)
-                               break;
+               if (wait) {
+               /* An alertable wait is required so this thread can be suspended on windows */
+#ifdef MONO_HAS_SEMAPHORES
+                       MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
+#else
+                       WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
+#endif
                }
+               wait = TRUE;
+               MONO_FINISH_BLOCKING
+               mono_gc_set_skip_thread (FALSE);
 
                mono_threads_perform_thread_dump ();
 
                mono_console_handle_async_ops ();
 
-#ifndef DISABLE_ATTACH
                mono_attach_maybe_start ();
-#endif
 
                if (domains_to_finalize) {
                        mono_finalizer_lock ();
@@ -1145,12 +1131,16 @@ finalizer_thread (gpointer unused)
 
                reference_queue_proccess_all ();
 
+#ifdef MONO_HAS_SEMAPHORES
                /* Avoid posting the pending done event until there are pending finalizers */
-               mono_mutex_lock (&finalizer_mutex);
-               num_to_finalize --;
-               if (num_to_finalize == 0)
+               if (MONO_SEM_TIMEDWAIT (&finalizer_sem, 0) == 0)
+                       /* Don't wait again at the start of the loop */
+                       wait = FALSE;
+               else
                        SetEvent (pending_done_event);
-               mono_mutex_unlock (&finalizer_mutex);
+#else
+                       SetEvent (pending_done_event);
+#endif
        }
 
        mono_finalizer_lock ();
@@ -1195,11 +1185,15 @@ mono_gc_init (void)
                gc_disabled = TRUE;
                return;
        }
-
-       mono_cond_init (&finalizer_cond, 0);
+       
+       finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+       g_assert (finalizer_event);
        pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
        g_assert (pending_done_event);
        mono_cond_init (&exited_cond, 0);
+#ifdef MONO_HAS_SEMAPHORES
+       MONO_SEM_INIT (&finalizer_sem, 0);
+#endif
 
 #ifndef LAZY_GC_THREAD_CREATION
        mono_gc_init_finalizer_thread ();
@@ -1276,19 +1270,27 @@ mono_gc_cleanup (void)
                        }
                }
                gc_thread = NULL;
-#ifdef HAVE_BOEHM_GC
-               GC_finalizer_notifier = NULL;
-#endif
+               mono_gc_base_cleanup ();
        }
 
        mono_reference_queue_cleanup ();
 
-       mono_mutex_destroy (&handle_section);
        mono_mutex_destroy (&allocator_section);
        mono_mutex_destroy (&finalizer_mutex);
        mono_mutex_destroy (&reference_queue_mutex);
 }
 
+/**
+ * mono_gc_mutex_cleanup:
+ *
+ * Destroy the mutexes that may still be used after the main cleanup routine.
+ */
+void
+mono_gc_mutex_cleanup (void)
+{
+       mono_mutex_destroy (&handle_section);
+}
+
 gboolean
 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
 {