[sgen] Use old GC handle implementation with Boehm.
[mono.git] / mono / metadata / gc.c
index 621ce3f825fcc635e463a84c0af12024ebfd64e4..bc34095900d92a7fb98dcbc8de82fbbfc9f78937 100644 (file)
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/mono-mlist.h>
-#include <mono/metadata/threadpool.h>
-#include <mono/metadata/threadpool-internals.h>
 #include <mono/metadata/threads-types.h>
+#include <mono/metadata/threadpool-ms.h>
 #include <mono/sgen/sgen-conf.h>
+#include <mono/sgen/sgen-gc.h>
 #include <mono/utils/mono-logger-internal.h>
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
@@ -34,6 +34,7 @@
 #include <mono/utils/mono-semaphore.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-time.h>
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/atomic.h>
@@ -47,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;
@@ -69,28 +63,27 @@ static mono_mutex_t reference_queue_mutex;
 static GSList *domains_to_finalize= NULL;
 static MonoMList *threads_to_finalize = NULL;
 
+static gboolean finalizer_thread_exited;
+/* Uses finalizer_mutex */
+static mono_cond_t exited_cond;
+
 static MonoInternalThread *gc_thread;
 
 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
 
-static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
-
 static void reference_queue_proccess_all (void);
 static void mono_reference_queue_cleanup (void);
 static void reference_queue_clear_for_domain (MonoDomain *domain);
-#ifndef HAVE_NULL_GC
 static HANDLE pending_done_event;
-static HANDLE shutdown_event;
-#endif
 
 static guint32
 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
 {
        guint32 result;
 
-       MONO_PREPARE_BLOCKING
+       MONO_PREPARE_BLOCKING;
        result = WaitForSingleObjectEx (handle, timeout, alertable);
-       MONO_FINISH_BLOCKING
+       MONO_FINISH_BLOCKING;
 
        return result;
 }
@@ -100,7 +93,7 @@ add_thread_to_finalize (MonoInternalThread *thread)
 {
        mono_finalizer_lock ();
        if (!threads_to_finalize)
-               MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
+               MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize, MONO_ROOT_SOURCE_FINALIZER_QUEUE, "finalizable threads list");
        threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
        mono_finalizer_unlock ();
 }
@@ -126,6 +119,9 @@ mono_gc_run_finalize (void *obj, void *data)
        MonoDomain *domain;
        RuntimeInvokeFunction runtime_invoke;
 
+       // This function is called from the innards of the GC, so our best alternative for now is to do polling here
+       MONO_SUSPEND_CHECK ();
+
        o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
 
        if (log_finalizers)
@@ -204,7 +200,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.
@@ -215,7 +210,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 (),
@@ -249,7 +243,7 @@ mono_gc_run_finalize (void *obj, void *data)
                g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o);
 
        if (exc)
-               mono_internal_thread_unhandled_exception (exc);
+               mono_thread_internal_unhandled_exception (exc);
 
        mono_domain_set_internal (caller_domain);
 }
@@ -325,8 +319,11 @@ object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
         * end up running them while or after the domain is being cleared, so
         * the objects will not be valid anymore.
         */
-       if (!mono_domain_is_unloading (domain))
+       if (!mono_domain_is_unloading (domain)) {
+               MONO_TRY_BLOCKING;
                mono_gc_register_for_finalization (obj, callback);
+               MONO_FINISH_TRY_BLOCKING;
+       }
 #endif
 }
 
@@ -377,10 +374,13 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
         * is still working and will take care of running the finalizers
         */ 
        
-#ifndef HAVE_NULL_GC
        if (gc_disabled)
                return TRUE;
 
+       /* We don't support domain finalization without a GC */
+       if (mono_gc_is_null ())
+               return FALSE;
+
        mono_gc_collect (mono_gc_max_generation ());
 
        done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
@@ -425,15 +425,11 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
        CloseHandle (done_event);
 
        if (domain == mono_get_root_domain ()) {
-               mono_thread_pool_cleanup ();
+               mono_threadpool_ms_cleanup ();
                mono_gc_finalize_threadpool_threads ();
        }
 
        return TRUE;
-#else
-       /* We don't support domain finalization without a GC */
-       return FALSE;
-#endif
 }
 
 void
@@ -488,7 +484,9 @@ ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
 void
 ves_icall_System_GC_WaitForPendingFinalizers (void)
 {
-#ifndef HAVE_NULL_GC
+       if (mono_gc_is_null ())
+               return;
+
        if (!mono_gc_pending_finalizers ())
                return;
 
@@ -508,7 +506,6 @@ ves_icall_System_GC_WaitForPendingFinalizers (void)
        /* g_print ("Waiting for pending finalizers....\n"); */
        guarded_wait (pending_done_event, INFINITE, TRUE);
        /* g_print ("Done pending....\n"); */
-#endif
 }
 
 void
@@ -531,16 +528,6 @@ ves_icall_System_GC_get_ephemeron_tombstone (void)
 #define mono_allocator_lock() mono_mutex_lock (&allocator_section)
 #define mono_allocator_unlock() mono_mutex_unlock (&allocator_section)
 static mono_mutex_t allocator_section;
-static mono_mutex_t handle_section;
-
-typedef enum {
-       HANDLE_WEAK,
-       HANDLE_WEAK_TRACK,
-       HANDLE_NORMAL,
-       HANDLE_PINNED
-} HandleType;
-
-static HandleType mono_gchandle_get_type (guint32 gchandle);
 
 MonoObject *
 ves_icall_System_GCHandle_GetTarget (guint32 handle)
@@ -585,7 +572,7 @@ ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
 {
        MonoObject *obj;
 
-       if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
+       if (MONO_GC_HANDLE_TYPE (handle) != HANDLE_PINNED)
                return (gpointer)-2;
        obj = mono_gchandle_get_target (handle);
        if (obj) {
@@ -611,388 +598,12 @@ ves_icall_Mono_Runtime_SetGCAllowSynchronousMajor (MonoBoolean flag)
        return mono_gc_set_allow_synchronous_major (flag);
 }
 
-typedef struct {
-       guint32  *bitmap;
-       gpointer *entries;
-       guint32   size;
-       guint8    type;
-       guint     slot_hint : 24; /* starting slot for search */
-       /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
-       /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
-       guint16  *domain_ids;
-} HandleData;
-
-/* weak and weak-track arrays will be allocated in malloc memory 
- */
-static HandleData gc_handles [] = {
-       {NULL, NULL, 0, HANDLE_WEAK, 0},
-       {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
-       {NULL, NULL, 0, HANDLE_NORMAL, 0},
-       {NULL, NULL, 0, HANDLE_PINNED, 0}
-};
-
-#define lock_handles(handles) mono_mutex_lock (&handle_section)
-#define unlock_handles(handles) mono_mutex_unlock (&handle_section)
-
-static int
-find_first_unset (guint32 bitmap)
-{
-       int i;
-       for (i = 0; i < 32; ++i) {
-               if (!(bitmap & (1 << i)))
-                       return i;
-       }
-       return -1;
-}
-
-static void*
-make_root_descr_all_refs (int numbits, gboolean pinned)
-{
-#ifdef HAVE_SGEN_GC
-       if (pinned)
-               return NULL;
-#endif
-       return mono_gc_make_root_descr_all_refs (numbits);
-}
-
-static guint32
-alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
-{
-       gint slot, i;
-       guint32 res;
-       lock_handles (handles);
-       if (!handles->size) {
-               handles->size = 32;
-               if (handles->type > HANDLE_WEAK_TRACK) {
-                       handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
-               } else {
-                       handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
-                       handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
-               }
-               handles->bitmap = g_malloc0 (handles->size / 8);
-       }
-       i = -1;
-       for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
-               if (handles->bitmap [slot] != 0xffffffff) {
-                       i = find_first_unset (handles->bitmap [slot]);
-                       handles->slot_hint = slot;
-                       break;
-               }
-       }
-       if (i == -1 && handles->slot_hint != 0) {
-               for (slot = 0; slot < handles->slot_hint; ++slot) {
-                       if (handles->bitmap [slot] != 0xffffffff) {
-                               i = find_first_unset (handles->bitmap [slot]);
-                               handles->slot_hint = slot;
-                               break;
-                       }
-               }
-       }
-       if (i == -1) {
-               guint32 *new_bitmap;
-               guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
-
-               /* resize and copy the bitmap */
-               new_bitmap = g_malloc0 (new_size / 8);
-               memcpy (new_bitmap, handles->bitmap, handles->size / 8);
-               g_free (handles->bitmap);
-               handles->bitmap = new_bitmap;
-
-               /* resize and copy the entries */
-               if (handles->type > HANDLE_WEAK_TRACK) {
-                       gpointer *entries;
-
-                       entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
-                       mono_gc_memmove_aligned (entries, handles->entries, sizeof (gpointer) * handles->size);
-
-                       mono_gc_free_fixed (handles->entries);
-                       handles->entries = entries;
-               } else {
-                       gpointer *entries;
-                       guint16 *domain_ids;
-                       domain_ids = g_malloc0 (sizeof (guint16) * new_size);
-                       entries = g_malloc0 (sizeof (gpointer) * new_size);
-                       memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
-                       for (i = 0; i < handles->size; ++i) {
-                               MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
-                               if (obj) {
-                                       mono_gc_weak_link_add (&(entries [i]), obj, track);
-                                       mono_gc_weak_link_remove (&(handles->entries [i]), track);
-                               } else {
-                                       g_assert (!handles->entries [i]);
-                               }
-                       }
-                       g_free (handles->entries);
-                       g_free (handles->domain_ids);
-                       handles->entries = entries;
-                       handles->domain_ids = domain_ids;
-               }
-
-               /* set i and slot to the next free position */
-               i = 0;
-               slot = (handles->size + 1) / 32;
-               handles->slot_hint = handles->size + 1;
-               handles->size = new_size;
-       }
-       handles->bitmap [slot] |= 1 << i;
-       slot = slot * 32 + i;
-       handles->entries [slot] = NULL;
-       if (handles->type <= HANDLE_WEAK_TRACK) {
-               /*FIXME, what to use when obj == null?*/
-               handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
-               if (obj)
-                       mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
-       } else {
-               handles->entries [slot] = obj;
-       }
-
-#ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->gc_num_handles++;
-#endif
-       unlock_handles (handles);
-       /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
-       res = (slot << 3) | (handles->type + 1);
-       mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
-       return res;
-}
-
-/**
- * mono_gchandle_new:
- * @obj: managed object to get a handle for
- * @pinned: whether the object should be pinned
- *
- * This returns a handle that wraps the object, this is used to keep a
- * reference to a managed object from the unmanaged world and preventing the
- * object from being disposed.
- * 
- * If @pinned is false the address of the object can not be obtained, if it is
- * true the address of the object can be obtained.  This will also pin the
- * object so it will not be possible by a moving garbage collector to move the
- * object. 
- * 
- * Returns: a handle that can be used to access the object from
- * unmanaged code.
- */
-guint32
-mono_gchandle_new (MonoObject *obj, gboolean pinned)
-{
-       return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
-}
-
-/**
- * mono_gchandle_new_weakref:
- * @obj: managed object to get a handle for
- * @pinned: whether the object should be pinned
- *
- * This returns a weak handle that wraps the object, this is used to
- * keep a reference to a managed object from the unmanaged world.
- * Unlike the mono_gchandle_new the object can be reclaimed by the
- * garbage collector.  In this case the value of the GCHandle will be
- * set to zero.
- * 
- * If @pinned is false the address of the object can not be obtained, if it is
- * true the address of the object can be obtained.  This will also pin the
- * object so it will not be possible by a moving garbage collector to move the
- * object. 
- * 
- * Returns: a handle that can be used to access the object from
- * unmanaged code.
- */
-guint32
-mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
-{
-       guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
-
-       return handle;
-}
-
-static HandleType
-mono_gchandle_get_type (guint32 gchandle)
-{
-       guint type = (gchandle & 7) - 1;
-
-       return type;
-}
-
-/**
- * mono_gchandle_get_target:
- * @gchandle: a GCHandle's handle.
- *
- * The handle was previously created by calling mono_gchandle_new or
- * mono_gchandle_new_weakref. 
- *
- * Returns a pointer to the MonoObject represented by the handle or
- * NULL for a collected object if using a weakref handle.
- */
-MonoObject*
-mono_gchandle_get_target (guint32 gchandle)
-{
-       guint slot = gchandle >> 3;
-       guint type = (gchandle & 7) - 1;
-       HandleData *handles = &gc_handles [type];
-       MonoObject *obj = NULL;
-       if (type > 3)
-               return NULL;
-       lock_handles (handles);
-       if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
-               if (handles->type <= HANDLE_WEAK_TRACK) {
-                       obj = mono_gc_weak_link_get (&handles->entries [slot]);
-               } else {
-                       obj = handles->entries [slot];
-               }
-       } else {
-               /* print a warning? */
-       }
-       unlock_handles (handles);
-       /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
-       return obj;
-}
-
-static void
-mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
-{
-       guint slot = gchandle >> 3;
-       guint type = (gchandle & 7) - 1;
-       HandleData *handles = &gc_handles [type];
-
-       if (type > 3)
-               return;
-       lock_handles (handles);
-       if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
-               if (handles->type <= HANDLE_WEAK_TRACK) {
-                       if (handles->entries [slot])
-                               mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
-                       if (obj)
-                               mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
-                       /*FIXME, what to use when obj == null?*/
-                       handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
-               } else {
-                       handles->entries [slot] = obj;
-               }
-       } else {
-               /* print a warning? */
-       }
-       /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
-       unlock_handles (handles);
-}
-
-/**
- * mono_gchandle_is_in_domain:
- * @gchandle: a GCHandle's handle.
- * @domain: An application domain.
- *
- * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
- */
-gboolean
-mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
-{
-       guint slot = gchandle >> 3;
-       guint type = (gchandle & 7) - 1;
-       HandleData *handles = &gc_handles [type];
-       gboolean result = FALSE;
-       if (type > 3)
-               return FALSE;
-       lock_handles (handles);
-       if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
-               if (handles->type <= HANDLE_WEAK_TRACK) {
-                       result = domain->domain_id == handles->domain_ids [slot];
-               } else {
-                       MonoObject *obj;
-                       obj = handles->entries [slot];
-                       if (obj == NULL)
-                               result = TRUE;
-                       else
-                               result = domain == mono_object_domain (obj);
-               }
-       } else {
-               /* print a warning? */
-       }
-       unlock_handles (handles);
-       return result;
-}
-
-/**
- * mono_gchandle_free:
- * @gchandle: a GCHandle's handle.
- *
- * Frees the @gchandle handle.  If there are no outstanding
- * references, the garbage collector can reclaim the memory of the
- * object wrapped. 
- */
-void
-mono_gchandle_free (guint32 gchandle)
-{
-       guint slot = gchandle >> 3;
-       guint type = (gchandle & 7) - 1;
-       HandleData *handles = &gc_handles [type];
-       if (type > 3)
-               return;
-
-       lock_handles (handles);
-       if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
-               if (handles->type <= HANDLE_WEAK_TRACK) {
-                       if (handles->entries [slot])
-                               mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
-               } else {
-                       handles->entries [slot] = NULL;
-               }
-               handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
-       } else {
-               /* print a warning? */
-       }
-#ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->gc_num_handles--;
-#endif
-       /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
-       unlock_handles (handles);
-       mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
-}
-
-/**
- * mono_gchandle_free_domain:
- * @domain: domain that is unloading
- *
- * Function used internally to cleanup any GC handle for objects belonging
- * to the specified domain during appdomain unload.
- */
-void
-mono_gchandle_free_domain (MonoDomain *domain)
-{
-       guint type;
-
-       for (type = 0; type < 3; ++type) {
-               guint slot;
-               HandleData *handles = &gc_handles [type];
-               lock_handles (handles);
-               for (slot = 0; slot < handles->size; ++slot) {
-                       if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
-                               continue;
-                       if (type <= HANDLE_WEAK_TRACK) {
-                               if (domain->domain_id == handles->domain_ids [slot]) {
-                                       handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
-                                       if (handles->entries [slot])
-                                               mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
-                               }
-                       } else {
-                               if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
-                                       handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
-                                       handles->entries [slot] = NULL;
-                               }
-                       }
-               }
-               unlock_handles (handles);
-       }
-
-}
-
 MonoBoolean
 mono_gc_GCHandle_CheckCurrentDomain (guint32 gchandle)
 {
        return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
 }
 
-#ifndef HAVE_NULL_GC
-
 #ifdef MONO_HAS_SEMAPHORES
 static MonoSemType finalizer_sem;
 #endif
@@ -1006,6 +617,9 @@ mono_gc_finalize_notify (void)
        g_message ( "%s: prodding finalizer", __func__);
 #endif
 
+       if (mono_gc_is_null ())
+               return;
+
 #ifdef MONO_HAS_SEMAPHORES
        MONO_SEM_POST (&finalizer_sem);
 #else
@@ -1095,7 +709,7 @@ finalizer_thread (gpointer unused)
 
                g_assert (mono_domain_get () == mono_get_root_domain ());
                mono_gc_set_skip_thread (TRUE);
-               MONO_PREPARE_BLOCKING
+               MONO_PREPARE_BLOCKING;
 
                if (wait) {
                /* An alertable wait is required so this thread can be suspended on windows */
@@ -1106,16 +720,14 @@ finalizer_thread (gpointer unused)
 #endif
                }
                wait = TRUE;
-               MONO_FINISH_BLOCKING
+               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 ();
@@ -1151,7 +763,11 @@ finalizer_thread (gpointer unused)
 #endif
        }
 
-       SetEvent (shutdown_event);
+       mono_finalizer_lock ();
+       finalizer_thread_exited = TRUE;
+       mono_cond_signal (&exited_cond);
+       mono_finalizer_unlock ();
+
        return 0;
 }
 
@@ -1168,15 +784,11 @@ mono_gc_init_finalizer_thread (void)
 void
 mono_gc_init (void)
 {
-       mono_mutex_init_recursive (&handle_section);
        mono_mutex_init_recursive (&allocator_section);
 
        mono_mutex_init_recursive (&finalizer_mutex);
        mono_mutex_init_recursive (&reference_queue_mutex);
 
-       MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
-       MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
-
        mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.minor_gc_count);
        mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.major_gc_count);
        mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time);
@@ -1191,11 +803,10 @@ mono_gc_init (void)
        }
        
        finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+       g_assert (finalizer_event);
        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) {
-               g_assert_not_reached ();
-       }
+       g_assert (pending_done_event);
+       mono_cond_init (&exited_cond, 0);
 #ifdef MONO_HAS_SEMAPHORES
        MONO_SEM_INIT (&finalizer_sem, 0);
 #endif
@@ -1212,16 +823,36 @@ mono_gc_cleanup (void)
        g_message ("%s: cleaning up finalizer", __func__);
 #endif
 
+       if (mono_gc_is_null ())
+               return;
+
        if (!gc_disabled) {
-               ResetEvent (shutdown_event);
                finished = TRUE;
                if (mono_thread_internal_current () != gc_thread) {
                        gboolean timed_out = FALSE;
+                       guint32 start_ticks = mono_msec_ticks ();
+                       guint32 end_ticks = start_ticks + 2000;
 
                        mono_gc_finalize_notify ();
                        /* Finishing the finalizer thread, so wait a little bit... */
                        /* MS seems to wait for about 2 seconds */
-                       if (guarded_wait (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
+                       while (!finalizer_thread_exited) {
+                               guint32 current_ticks = mono_msec_ticks ();
+                               guint32 timeout;
+
+                               if (current_ticks >= end_ticks)
+                                       break;
+                               else
+                                       timeout = end_ticks - current_ticks;
+                               MONO_PREPARE_BLOCKING;
+                               mono_finalizer_lock ();
+                               if (!finalizer_thread_exited)
+                                       mono_cond_timedwait_ms (&exited_cond, &finalizer_mutex, timeout);
+                               mono_finalizer_unlock ();
+                               MONO_FINISH_BLOCKING;
+                       }
+
+                       if (!finalizer_thread_exited) {
                                int ret;
 
                                /* Set a flag which the finalizer thread can check */
@@ -1255,38 +886,16 @@ 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);
 }
 
-#else
-
-/* Null GC dummy functions */
-void
-mono_gc_finalize_notify (void)
-{
-}
-
-void mono_gc_init (void)
-{
-       mono_mutex_init_recursive (&handle_section);
-}
-
-void mono_gc_cleanup (void)
-{
-}
-
-#endif
-
 gboolean
 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
 {
@@ -1363,13 +972,8 @@ reference_queue_proccess (MonoReferenceQueue *queue)
        RefQueueEntry **iter = &queue->queue;
        RefQueueEntry *entry;
        while ((entry = *iter)) {
-#ifdef HAVE_SGEN_GC
-               if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
-                       mono_gc_weak_link_remove (&entry->dis_link, TRUE);
-#else
                if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
                        mono_gchandle_free ((guint32)entry->gchandle);
-#endif
                        ref_list_remove_element (iter, entry);
                        queue->callback (entry->user_data);
                        g_free (entry);
@@ -1424,11 +1028,7 @@ reference_queue_clear_for_domain (MonoDomain *domain)
                RefQueueEntry *entry;
                while ((entry = *iter)) {
                        if (entry->domain == domain) {
-#ifdef HAVE_SGEN_GC
-                               mono_gc_weak_link_remove (&entry->dis_link, TRUE);
-#else
                                mono_gchandle_free ((guint32)entry->gchandle);
-#endif
                                ref_list_remove_element (iter, entry);
                                queue->callback (entry->user_data);
                                g_free (entry);
@@ -1492,12 +1092,8 @@ mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *u
        entry->user_data = user_data;
        entry->domain = mono_object_domain (obj);
 
-#ifdef HAVE_SGEN_GC
-       mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
-#else
        entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
        mono_object_register_finalizer (obj);
-#endif
 
        ref_list_push (&queue->queue, entry);
        return TRUE;