[runtime] Fix a crash on Windows during the cleanup phase caused by using a destroyed...
[mono.git] / mono / metadata / gc.c
index 58aa546c1375f7f094a9690ba07f64931630c3f2..03273531193a1f042d36fb185ca99ead3f019565 100644 (file)
 
 typedef struct DomainFinalizationReq {
        MonoDomain *domain;
-       mono_mutex_t *done_mutex;
-       mono_cond_t *done_cond;
-       gboolean done;
+       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;
@@ -99,21 +90,6 @@ guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
        return result;
 }
 
-static guint32
-guarded_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout)
-{
-       guint32 result;
-
-       MONO_PREPARE_BLOCKING;
-       if (timeout == INFINITE)
-               result = mono_cond_wait (cond, mutex);
-       else
-               result = mono_cond_timedwait_ms (cond, mutex, timeout);
-       MONO_FINISH_BLOCKING
-
-       return result;
-}
-
 static void
 add_thread_to_finalize (MonoInternalThread *thread)
 {
@@ -223,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.
@@ -234,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 (),
@@ -380,8 +354,8 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
 {
        DomainFinalizationReq *req;
        guint32 res;
-       mono_mutex_t done_mutex;
-       mono_cond_t done_cond;
+       HANDLE done_event;
+       MonoInternalThread *thread = mono_thread_internal_current ();
 
 #if defined(__native_client__)
        return FALSE;
@@ -405,14 +379,14 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
 
        mono_gc_collect (mono_gc_max_generation ());
 
-       mono_mutex_init (&done_mutex);
-       mono_cond_init (&done_cond, 0);
+       done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+       if (done_event == NULL) {
+               return FALSE;
+       }
 
        req = g_new0 (DomainFinalizationReq, 1);
        req->domain = domain;
-       req->done_mutex = &done_mutex;
-       req->done_cond = &done_cond;
-       req->done = FALSE;
+       req->done_event = done_event;
 
        if (domain == mono_get_root_domain ())
                finalizing_root_domain = TRUE;
@@ -430,23 +404,21 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
                timeout = INFINITE;
 
        while (TRUE) {
-               res = 0;
-               mono_mutex_lock (&done_mutex);
-               if (!req->done) {
-                       res = guarded_cond_wait (&done_cond, &done_mutex, timeout);
-                       /* printf ("WAIT RES: %d.\n", res); */
-               }
-               mono_mutex_unlock (&done_mutex);
-               if (res)
-                       /* We leak memory here, since the finalizer thread might still be using it */
+               res = guarded_wait (done_event, timeout, TRUE);
+               /* printf ("WAIT RES: %d.\n", res); */
+
+               if (res == WAIT_IO_COMPLETION) {
+                       if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
+                               return FALSE;
+               } else if (res == WAIT_TIMEOUT) {
+                       /* We leak the handle here */
                        return FALSE;
-               if (req->done)
+               } else {
                        break;
+               }
        }
 
-       mono_mutex_destroy (&done_mutex);
-       mono_cond_destroy (&done_cond);
-       g_free (req);
+       CloseHandle (done_event);
 
        if (domain == mono_get_root_domain ()) {
                mono_thread_pool_cleanup ();
@@ -666,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);
 }
@@ -1097,13 +1069,12 @@ finalize_domain_objects (DomainFinalizationReq *req)
 
        /* cleanup the reference queue */
        reference_queue_clear_for_domain (domain);
-
+       
        /* printf ("DONE.\n"); */
+       SetEvent (req->done_event);
 
-       mono_mutex_lock (req->done_mutex);
-       req->done = TRUE;
-       mono_cond_signal (req->done_cond);
-       mono_mutex_unlock (req->done_mutex);
+       /* The event is closed in mono_domain_finalize if we get here */
+       g_free (req);
 }
 
 static guint32
@@ -1136,9 +1107,7 @@ finalizer_thread (gpointer unused)
 
                mono_console_handle_async_ops ();
 
-#ifndef DISABLE_ATTACH
                mono_attach_maybe_start ();
-#endif
 
                if (domains_to_finalize) {
                        mono_finalizer_lock ();
@@ -1301,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)
 {