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;
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.
mono_domain_set_internal (caller_domain);
return;
}
-#endif
/*
* To avoid the locking plus the other overhead of mono_runtime_invoke (),
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"); */
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);
}
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
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
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 ();
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 ();
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 ();
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)
{