Merge pull request #3142 from henricm/fix-for-win-mono_string_to_utf8
[mono.git] / mono / metadata / gc.c
index bf02f2892b2e8ff3f8c0f544e2c3a08cf4dfa2b5..e44f07f6d8329cb3e3811eb9387baeb4aa6654a0 100644 (file)
@@ -38,6 +38,7 @@
 #include <mono/utils/mono-time.h>
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include <mono/utils/atomic.h>
 #include <mono/utils/mono-coop-semaphore.h>
 #include <mono/utils/hazard-pointer.h>
@@ -73,7 +74,7 @@ static MonoCoopCond exited_cond;
 
 static MonoInternalThread *gc_thread;
 
-static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*), MonoError *error);
+static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
 
 static void reference_queue_proccess_all (void);
 static void mono_reference_queue_cleanup (void);
@@ -85,21 +86,23 @@ guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
 {
        guint32 result;
 
-       MONO_PREPARE_BLOCKING;
+       MONO_ENTER_GC_SAFE;
        result = WaitForSingleObjectEx (handle, timeout, alertable);
-       MONO_FINISH_BLOCKING;
+       MONO_EXIT_GC_SAFE;
 
        return result;
 }
 
-static void
-add_thread_to_finalize (MonoInternalThread *thread)
+static gboolean
+add_thread_to_finalize (MonoInternalThread *thread, MonoError *error)
 {
+       mono_error_init (error);
        mono_finalizer_lock ();
        if (!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);
+       threads_to_finalize = mono_mlist_append_checked (threads_to_finalize, (MonoObject*)thread, error);
        mono_finalizer_unlock ();
+       return is_ok (error);
 }
 
 static gboolean suspend_finalizers = FALSE;
@@ -164,8 +167,7 @@ mono_gc_run_finalize (void *obj, void *data)
 #endif
 
        /* make sure the finalizer is not called again if the object is resurrected */
-       object_register_finalizer ((MonoObject *)obj, NULL, &error);
-       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+       object_register_finalizer ((MonoObject *)obj, NULL);
 
        if (log_finalizers)
                g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Registered finalizer as processed.", o->vtable->klass->name, o);
@@ -181,7 +183,8 @@ mono_gc_run_finalize (void *obj, void *data)
                        /* Don't finalize threadpool threads when
                           shutting down - they're finalized when the
                           threadpool shuts down. */
-                       add_thread_to_finalize (t);
+                       if (!add_thread_to_finalize (t, &error))
+                               goto unhandled_error;
                        return;
                }
        }
@@ -242,13 +245,15 @@ mono_gc_run_finalize (void *obj, void *data)
        if (!domain->finalize_runtime_invoke) {
                MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
 
-               domain->finalize_runtime_invoke = mono_compile_method (invoke);
+               domain->finalize_runtime_invoke = mono_compile_method_checked (invoke, &error);
+               mono_error_assert_ok (&error); /* expect this not to fail */
        }
 
        runtime_invoke = (RuntimeInvokeFunction)domain->finalize_runtime_invoke;
 
        mono_runtime_class_init_full (o->vtable, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       if (!is_ok (&error))
+               goto unhandled_error;
 
        if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
                MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
@@ -263,6 +268,9 @@ mono_gc_run_finalize (void *obj, void *data)
        if (log_finalizers)
                g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o);
 
+unhandled_error:
+       if (!is_ok (&error))
+               exc = (MonoObject*)mono_error_convert_to_exception (&error);
        if (exc)
                mono_thread_internal_unhandled_exception (exc);
 
@@ -272,14 +280,12 @@ mono_gc_run_finalize (void *obj, void *data)
 void
 mono_gc_finalize_threadpool_threads (void)
 {
-       MonoError error;
        while (threads_to_finalize) {
                MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
 
                /* Force finalization of the thread. */
                thread->threadpool_thread = FALSE;
-               mono_object_register_finalizer ((MonoObject*)thread, &error);
-               mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+               mono_object_register_finalizer ((MonoObject*)thread);
 
                mono_gc_run_finalize (thread, NULL);
 
@@ -309,16 +315,11 @@ mono_gc_out_of_memory (size_t size)
  * since that, too, can cause the underlying pointer to be offset.
  */
 static void
-object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*), MonoError *error)
+object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
 {
        MonoDomain *domain;
 
-       mono_error_init (error);
-
-       if (obj == NULL) {
-               mono_error_set_argument_null (error, "obj", "");
-               return;
-       }
+       g_assert (obj != NULL);
 
        domain = obj->vtable->domain;
 
@@ -360,10 +361,10 @@ object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*), Mon
  * 
  */
 void
-mono_object_register_finalizer (MonoObject *obj, MonoError *error)
+mono_object_register_finalizer (MonoObject *obj)
 {
        /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
-       object_register_finalizer (obj, mono_gc_run_finalize, error);
+       object_register_finalizer (obj, mono_gc_run_finalize);
 }
 
 /**
@@ -453,6 +454,8 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
                mono_gc_finalize_threadpool_threads ();
        }
 
+       mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
+
        return TRUE;
 }
 
@@ -481,19 +484,14 @@ ves_icall_System_GC_KeepAlive (MonoObject *obj)
 void
 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
 {
-       MonoError error;
-
        MONO_CHECK_ARG_NULL (obj,);
 
-       object_register_finalizer (obj, mono_gc_run_finalize, &error);
-       mono_error_set_pending_exception (&error);
+       object_register_finalizer (obj, mono_gc_run_finalize);
 }
 
 void
 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
 {
-       MonoError error;
-
        MONO_CHECK_ARG_NULL (obj,);
 
        /* delegates have no finalizers, but we register them to deal with the
@@ -507,8 +505,7 @@ ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
         * generated for it that needs cleaned up, but user wants to suppress
         * their derived object finalizer. */
 
-       object_register_finalizer (obj, NULL, &error);
-       mono_error_set_pending_exception (&error);
+       object_register_finalizer (obj, NULL);
 }
 
 void
@@ -826,7 +823,9 @@ static
 void
 mono_gc_init_finalizer_thread (void)
 {
-       gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
+       MonoError error;
+       gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0, &error);
+       mono_error_assert_ok (&error);
 }
 
 void
@@ -872,14 +871,14 @@ mono_gc_cleanup (void)
                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;
+                       gint64 start_ticks = mono_msec_ticks ();
+                       gint64 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 */
                        while (!finalizer_thread_exited) {
-                               guint32 current_ticks = mono_msec_ticks ();
+                               gint64 current_ticks = mono_msec_ticks ();
                                guint32 timeout;
 
                                if (current_ticks >= end_ticks)
@@ -1115,18 +1114,18 @@ mono_gc_reference_queue_new (mono_reference_queue_callback callback)
 gboolean
 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
 {
-       MonoError error;
        RefQueueEntry *entry;
        if (queue->should_be_deleted)
                return FALSE;
 
+       g_assert (obj != NULL);
+
        entry = g_new0 (RefQueueEntry, 1);
        entry->user_data = user_data;
        entry->domain = mono_object_domain (obj);
 
        entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
-       mono_object_register_finalizer (obj, &error);
-       mono_error_assert_ok (&error);
+       mono_object_register_finalizer (obj);
 
        ref_list_push (&queue->queue, entry);
        return TRUE;