[sgen] Fix locking of the worker distribute gray queue.
[mono.git] / mono / metadata / gc.c
index 1a89248dd0f9b6ba7086b9297fac5c49e67f0d25..c6e01da6f6ef32d68c6ae1474bb227da0ac1b85c 100644 (file)
@@ -24,6 +24,7 @@
 #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/utils/mono-logger-internal.h>
 #include <mono/metadata/gc-internal.h>
@@ -32,6 +33,7 @@
 #include <mono/metadata/console-io.h>
 #include <mono/utils/mono-semaphore.h>
 #include <mono/utils/mono-memory-model.h>
+#include <mono/utils/mono-counters.h>
 
 #ifndef HOST_WIN32
 #include <pthread.h>
@@ -75,6 +77,8 @@ static HANDLE pending_done_event;
 static HANDLE shutdown_event;
 #endif
 
+GCStats gc_stats;
+
 static void
 add_thread_to_finalize (MonoInternalThread *thread)
 {
@@ -225,9 +229,8 @@ mono_gc_run_finalize (void *obj, void *data)
 
        runtime_invoke (o, NULL, &exc, NULL);
 
-       if (exc) {
-               /* fixme: do something useful */
-       }
+       if (exc)
+               mono_internal_thread_unhandled_exception (exc);
 
        mono_domain_set_internal (caller_domain);
 }
@@ -485,6 +488,13 @@ ves_icall_System_GC_WaitForPendingFinalizers (void)
                /* Avoid deadlocks */
                return;
 
+       /*
+       If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
+       be the one responsible for starting it up.
+       */
+       if (gc_thread == NULL)
+               return;
+
        ResetEvent (pending_done_event);
        mono_gc_finalize_notify ();
        /* g_print ("Waiting for pending finalizers....\n"); */
@@ -619,6 +629,16 @@ find_first_unset (guint32 bitmap)
        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)
 {
@@ -628,7 +648,7 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
        if (!handles->size) {
                handles->size = 32;
                if (handles->type > HANDLE_WEAK_TRACK) {
-                       handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, mono_gc_make_root_descr_all_refs (handles->size));
+                       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);
@@ -666,8 +686,8 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
                if (handles->type > HANDLE_WEAK_TRACK) {
                        gpointer *entries;
 
-                       entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, mono_gc_make_root_descr_all_refs (new_size));
-                       memcpy (entries, handles->entries, sizeof (gpointer) * handles->size);
+                       entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
+                       mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
 
                        mono_gc_free_fixed (handles->entries);
                        handles->entries = entries;
@@ -678,8 +698,8 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
                        entries = g_malloc (sizeof (gpointer) * new_size);
                        /* we disable GC because we could lose some disappearing link updates */
                        mono_gc_disable ();
-                       memcpy (entries, handles->entries, sizeof (gpointer) * handles->size);
-                       memset (entries + handles->size, 0, sizeof (gpointer) * handles->size);
+                       mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
+                       mono_gc_bzero (entries + handles->size, sizeof (gpointer) * handles->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]));
@@ -713,7 +733,9 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
                        mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
        }
 
+#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);
@@ -921,7 +943,9 @@ mono_gchandle_free (guint32 gchandle)
        } 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);
@@ -1013,6 +1037,15 @@ finalize_domain_objects (DomainFinalizationReq *req)
 {
        MonoDomain *domain = req->domain;
 
+#if HAVE_SGEN_GC
+#define NUM_FOBJECTS 64
+       MonoObject *to_finalize [NUM_FOBJECTS];
+       int count;
+#endif
+
+       /* Process finalizers which are already in the queue */
+       mono_gc_invoke_finalizers ();
+
 #ifdef HAVE_BOEHM_GC
        while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
                int i;
@@ -1035,9 +1068,6 @@ finalize_domain_objects (DomainFinalizationReq *req)
                g_ptr_array_free (objs, TRUE);
        }
 #elif defined(HAVE_SGEN_GC)
-#define NUM_FOBJECTS 64
-       MonoObject *to_finalize [NUM_FOBJECTS];
-       int count;
        while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
                int i;
                for (i = 0; i < count; ++i) {
@@ -1046,9 +1076,6 @@ finalize_domain_objects (DomainFinalizationReq *req)
        }
 #endif
 
-       /* Process finalizers which are already in the queue */
-       mono_gc_invoke_finalizers ();
-
        /* cleanup the reference queue */
        reference_queue_clear_for_domain (domain);
        
@@ -1111,6 +1138,16 @@ finalizer_thread (gpointer unused)
        return 0;
 }
 
+#ifndef LAZY_GC_THREAD_CREATION
+static
+#endif
+void
+mono_gc_init_finalizer_thread (void)
+{
+       gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
+       ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
+}
+
 void
 mono_gc_init (void)
 {
@@ -1123,6 +1160,11 @@ mono_gc_init (void)
        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_INT, &gc_stats.minor_gc_count);
+       mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
+       mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
+       mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
+
        mono_gc_base_init ();
 
        if (mono_gc_is_disabled ()) {
@@ -1140,8 +1182,9 @@ mono_gc_init (void)
        MONO_SEM_INIT (&finalizer_sem, 0);
 #endif
 
-       gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
-       ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
+#ifndef LAZY_GC_THREAD_CREATION
+       mono_gc_init_finalizer_thread ();
+#endif
 }
 
 void
@@ -1309,9 +1352,19 @@ mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
                return FALSE;
 
        if (is_suffix) {
+               gulong unshifted;
+
+               if (val < 0)    /* negative numbers cannot be suffixed */
+                       return FALSE;
                if (*(endptr + 1)) /* Invalid string. */
                        return FALSE;
+
+               unshifted = (gulong)val;
                val <<= shift;
+               if (val < 0)    /* overflow */
+                       return FALSE;
+               if (((gulong)val >> shift) != unshifted) /* value too large */
+                       return FALSE;
        }
 
        *out = val;