2004-05-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mono / metadata / gc.c
index 70e1f4d3752c64d993094b8c94b4f18b58cee3a1..cc1e2902a6970a8e937e589fece408b034506110 100644 (file)
@@ -42,12 +42,15 @@ static CRITICAL_SECTION finalizer_mutex;
 
 static GSList *domains_to_finalize= NULL;
 
+static MonoThread *gc_thread;
+
 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
 
 #if HAVE_BOEHM_GC
 static void finalize_notify (void);
 static HANDLE pending_done_event;
 static HANDLE shutdown_event;
+static HANDLE thread_started_event;
 #endif
 
 /* 
@@ -85,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); */
 
@@ -166,8 +175,10 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
         */ 
        
 #if HAVE_BOEHM_GC
+       if (gc_disabled)
+               return TRUE;
+
        GC_gcollect ();
-#endif
 
        done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
 
@@ -186,11 +197,18 @@ 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;
+#endif
 }
 
 void
@@ -252,6 +270,10 @@ ves_icall_System_GC_WaitForPendingFinalizers (void)
        if (!GC_should_invoke_finalizers ())
                return;
 
+       if (mono_thread_current () == gc_thread)
+               /* Avoid deadlocks */
+               return;
+
        ResetEvent (pending_done_event);
        finalize_notify ();
        /* g_print ("Waiting for pending finalizers....\n"); */
@@ -403,6 +425,7 @@ ves_icall_System_GCHandle_FreeHandle (guint32 handle)
                        GC_unregister_disappearing_link (&(gc_handles [idx]));
        }
 #else
+       LeaveCriticalSection (&handle_section);
        mono_raise_exception (mono_get_exception_execution_engine ("No GCHandle support"));
 #endif
 
@@ -487,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
@@ -581,8 +604,6 @@ static GCThreadFunctions mono_gc_thread_vtable = {
 
 void mono_gc_init (void)
 {
-       HANDLE gc_thread;
-
        InitializeCriticalSection (&handle_section);
        InitializeCriticalSection (&allocator_section);
 
@@ -602,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
 }
 
@@ -627,9 +647,9 @@ void mono_gc_cleanup (void)
 #endif
 
 #ifdef ENABLE_FINALIZER_THREAD
-       ResetEvent (shutdown_event);
-       finished = TRUE;
        if (!gc_disabled) {
+               ResetEvent (shutdown_event);
+               finished = TRUE;
                finalize_notify ();
                /* Finishing the finalizer thread, so wait a little bit... */
                /* MS seems to wait for about 2 seconds */
@@ -643,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. */
@@ -655,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;
+}
+
+