2004-05-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mono / metadata / gc.c
index 6815f0027d9f320417a709789f82b66336764b3a..cc1e2902a6970a8e937e589fece408b034506110 100644 (file)
@@ -42,7 +42,7 @@ static CRITICAL_SECTION finalizer_mutex;
 
 static GSList *domains_to_finalize= NULL;
 
-static HANDLE gc_thread;
+static MonoThread *gc_thread;
 
 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
 
@@ -50,6 +50,7 @@ static void object_register_finalizer (MonoObject *obj, void (*callback)(void *,
 static void finalize_notify (void);
 static HANDLE pending_done_event;
 static HANDLE shutdown_event;
+static HANDLE thread_started_event;
 #endif
 
 /* 
@@ -87,6 +88,12 @@ run_finalize (void *obj, void *data)
 
        /* make sure the finalizer is not called again if the object is resurrected */
        object_register_finalizer (obj, NULL);
+
+       if (o->vtable->klass == mono_defaults.thread_class)
+               if (mono_gc_is_finalizer_thread ((MonoThread*)o))
+                       /* Avoid finalizing ourselves */
+                       return;
+
        /* speedup later... and use a timeout */
        /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
 
@@ -190,11 +197,14 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
 
        res = WaitForSingleObject (done_event, timeout);
 
-       //printf ("WAIT RES: %d.\n", res);
-       if (res == WAIT_TIMEOUT)
+       /* printf ("WAIT RES: %d.\n", res); */
+       if (res == WAIT_TIMEOUT) {
+               /* We leak the handle here */
                return FALSE;
-       else
-               return TRUE;
+       }
+
+       CloseHandle (done_event);
+       return TRUE;
 #else
        /* We don't support domain finalization without a GC */
        return FALSE;
@@ -260,7 +270,7 @@ ves_icall_System_GC_WaitForPendingFinalizers (void)
        if (!GC_should_invoke_finalizers ())
                return;
 
-       if (GetCurrentThread () == gc_thread)
+       if (mono_thread_current () == gc_thread)
                /* Avoid deadlocks */
                return;
 
@@ -500,19 +510,19 @@ finalize_domain_objects (DomainFinalizationReq *req)
                g_ptr_array_free (objs, TRUE);
        }
 
-       //printf ("DONE.\n");
+       /* printf ("DONE.\n"); */
        SetEvent (req->done_event);
 
-       /* FIXME: How to delete the event ? */
+       /* The event is closed in mono_domain_finalize if we get here */
        g_free (req);
 }
 
 static guint32 finalizer_thread (gpointer unused)
 {
-       guint32 stack_start;
-       
-       mono_thread_new_init (GetCurrentThreadId (), &stack_start, NULL);
-       
+       gc_thread = mono_thread_current ();
+
+       SetEvent (thread_started_event);
+
        while(!finished) {
                /* Wait to be notified that there's at least one
                 * finaliser to run
@@ -613,21 +623,20 @@ void mono_gc_init (void)
        finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
        pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
        shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
-       if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
+       thread_started_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+       if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL || thread_started_event == NULL) {
                g_assert_not_reached ();
        }
 
        GC_finalize_on_demand = 1;
        GC_finalizer_notifier = finalize_notify;
-       
-       /* Don't use mono_thread_create here, because we don't want
-        * the runtime to wait for this thread to exit when it's
-        * cleaning up.
+
+       mono_thread_create (mono_domain_get (), finalizer_thread, NULL);
+       /*
+        * Wait until the finalizer thread sets gc_thread since its value is needed
+        * by mono_thread_attach ()
         */
-       gc_thread = CreateThread (NULL, mono_threads_get_default_stacksize (), finalizer_thread, NULL, 0, NULL);
-       if (gc_thread == NULL) {
-               g_assert_not_reached ();
-       }
+       WaitForSingleObject (thread_started_event, INFINITE);
 #endif
 }
 
@@ -654,6 +663,26 @@ void mono_gc_cleanup (void)
 #endif
 }
 
+void
+mono_gc_disable (void)
+{
+#ifdef HAVE_GC_ENABLE
+       GC_disable ();
+#else
+       g_assert_not_reached ();
+#endif
+}
+
+void
+mono_gc_enable (void)
+{
+#ifdef HAVE_GC_ENABLE
+       GC_enable ();
+#else
+       g_assert_not_reached ();
+#endif
+}
+
 #else
 
 /* no Boehm GC support. */
@@ -666,5 +695,22 @@ void mono_gc_cleanup (void)
 {
 }
 
+void
+mono_gc_disable (void)
+{
+}
+
+void
+mono_gc_enable (void)
+{
+}
+
 #endif
 
+gboolean
+mono_gc_is_finalizer_thread (MonoThread *thread)
+{
+       return thread == gc_thread;
+}
+
+