Merge pull request #3800 from madewokherd/mingwbuild
[mono.git] / mono / metadata / sgen-mono.c
index 19265f57ef4bf84d41c97a2542253251a0cf2265..6372084d21dfb43b801fd1a0374c5aeb12a463c1 100644 (file)
@@ -16,6 +16,7 @@
 #include "sgen/sgen-client.h"
 #include "sgen/sgen-cardtable.h"
 #include "sgen/sgen-pinning.h"
+#include "sgen/sgen-thread-pool.h"
 #include "metadata/marshal.h"
 #include "metadata/method-builder.h"
 #include "metadata/abi-details.h"
@@ -28,6 +29,7 @@
 #include "utils/mono-logger-internals.h"
 #include "utils/mono-threads-coop.h"
 #include "sgen/sgen-thread-pool.h"
+#include "utils/mono-threads.h"
 
 #ifdef HEAVY_STATISTICS
 static guint64 stat_wbarrier_set_arrayref = 0;
@@ -183,19 +185,31 @@ mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, uns
        sgen_wbarrier_value_copy_bitmap (_dest, _src, size, bitmap);
 }
 
+int
+mono_gc_get_suspend_signal (void)
+{
+       return mono_threads_suspend_get_suspend_signal ();
+}
+
+int
+mono_gc_get_restart_signal (void)
+{
+       return mono_threads_suspend_get_restart_signal ();
+}
+
 static MonoMethod *write_barrier_conc_method;
 static MonoMethod *write_barrier_noconc_method;
 
 gboolean
 sgen_is_critical_method (MonoMethod *method)
 {
-       return (method == write_barrier_conc_method || method == write_barrier_noconc_method || sgen_is_managed_allocator (method));
+       return sgen_is_managed_allocator (method);
 }
 
 gboolean
 sgen_has_critical_method (void)
 {
-       return write_barrier_conc_method || write_barrier_noconc_method || sgen_has_managed_allocator ();
+       return sgen_has_managed_allocator ();
 }
 
 #ifndef DISABLE_JIT
@@ -491,7 +505,7 @@ mono_gc_invoke_finalizers (void)
        return sgen_gc_invoke_finalizers ();
 }
 
-gboolean
+MonoBoolean
 mono_gc_pending_finalizers (void)
 {
        return sgen_have_pending_finalizers ();
@@ -731,18 +745,6 @@ mono_gc_ephemeron_array_add (MonoObject *obj)
  * Appdomain handling
  */
 
-void
-mono_gc_set_current_thread_appdomain (MonoDomain *domain)
-{
-       SgenThreadInfo *info = mono_thread_info_current ();
-
-       /* Could be called from sgen_thread_unregister () with a NULL info */
-       if (domain) {
-               g_assert (info);
-               info->client_info.stopped_domain = domain;
-       }
-}
-
 static gboolean
 need_remove_object_for_domain (GCObject *start, MonoDomain *domain)
 {
@@ -917,20 +919,12 @@ mono_gc_clear_domain (MonoDomain * domain)
  * Allocation
  */
 
-static gboolean alloc_events = FALSE;
-
-void
-mono_gc_enable_alloc_events (void)
-{
-       alloc_events = TRUE;
-}
-
 void*
 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
 {
        MonoObject *obj = sgen_alloc_obj (vtable, size);
 
-       if (G_UNLIKELY (alloc_events)) {
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
                if (obj)
                        mono_profiler_allocation (obj);
        }
@@ -943,7 +937,7 @@ mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
 {
        MonoObject *obj = sgen_alloc_obj_pinned (vtable, size);
 
-       if (G_UNLIKELY (alloc_events)) {
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
                if (obj)
                        mono_profiler_allocation (obj);
        }
@@ -956,7 +950,7 @@ mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
 {
        MonoObject *obj = sgen_alloc_obj_mature (vtable, size);
 
-       if (G_UNLIKELY (alloc_events)) {
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
                if (obj)
                        mono_profiler_allocation (obj);
        }
@@ -968,11 +962,11 @@ void*
 mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
 {
        /* FIXME: do a single allocation */
-       void *res = calloc (1, size);
+       void *res = g_calloc (1, size);
        if (!res)
                return NULL;
        if (!mono_gc_register_root ((char *)res, size, descr, source, msg)) {
-               free (res);
+               g_free (res);
                res = NULL;
        }
        return res;
@@ -982,7 +976,7 @@ void
 mono_gc_free_fixed (void* addr)
 {
        mono_gc_deregister_root ((char *)addr);
-       free (addr);
+       g_free (addr);
 }
 
 /*
@@ -1753,7 +1747,7 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
        UNLOCK_GC;
 
  done:
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&arr->obj);
 
        SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Vector has incorrect size.");
@@ -1801,7 +1795,7 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint
        UNLOCK_GC;
 
  done:
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&arr->obj);
 
        SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Array has incorrect size.");
@@ -1842,7 +1836,7 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
        UNLOCK_GC;
 
  done:
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&str->object);
 
        return str;
@@ -2061,22 +2055,45 @@ sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQu
 static void *moved_objects [MOVED_OBJECTS_NUM];
 static int moved_objects_idx = 0;
 
+static SgenPointerQueue moved_objects_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_MOVED_OBJECT);
+
 void
 mono_sgen_register_moved_object (void *obj, void *destination)
 {
-       g_assert (mono_profiler_events & MONO_PROFILE_GC_MOVES);
+       /*
+        * This function can be called from SGen's worker threads. We want to try
+        * and avoid exposing those threads to the profiler API, so queue up move
+        * events and send them later when the main GC thread calls
+        * mono_sgen_gc_event_moves ().
+        *
+        * TODO: Once SGen has multiple worker threads, we need to switch to a
+        * lock-free data structure for the queue as multiple threads will be
+        * adding to it at the same time.
+        */
+       if (sgen_thread_pool_is_thread_pool_thread (mono_native_thread_id_get ())) {
+               sgen_pointer_queue_add (&moved_objects_queue, obj);
+               sgen_pointer_queue_add (&moved_objects_queue, destination);
+       } else {
+               if (moved_objects_idx == MOVED_OBJECTS_NUM) {
+                       mono_profiler_gc_moves (moved_objects, moved_objects_idx);
+                       moved_objects_idx = 0;
+               }
 
-       if (moved_objects_idx == MOVED_OBJECTS_NUM) {
-               mono_profiler_gc_moves (moved_objects, moved_objects_idx);
-               moved_objects_idx = 0;
+               moved_objects [moved_objects_idx++] = obj;
+               moved_objects [moved_objects_idx++] = destination;
        }
-       moved_objects [moved_objects_idx++] = obj;
-       moved_objects [moved_objects_idx++] = destination;
 }
 
 void
 mono_sgen_gc_event_moves (void)
 {
+       while (!sgen_pointer_queue_is_empty (&moved_objects_queue)) {
+               void *dst = sgen_pointer_queue_pop (&moved_objects_queue);
+               void *src = sgen_pointer_queue_pop (&moved_objects_queue);
+
+               mono_sgen_register_moved_object (src, dst);
+       }
+
        if (moved_objects_idx) {
                mono_profiler_gc_moves (moved_objects, moved_objects_idx);
                moved_objects_idx = 0;
@@ -2198,8 +2215,6 @@ sgen_client_thread_register (SgenThreadInfo* info, void *stack_bottom_fallback)
 #endif
 
        info->client_info.skip = 0;
-       info->client_info.stopped_ip = NULL;
-       info->client_info.stopped_domain = NULL;
 
        info->client_info.stack_start = NULL;
 
@@ -2208,12 +2223,9 @@ sgen_client_thread_register (SgenThreadInfo* info, void *stack_bottom_fallback)
        info->client_info.signal = 0;
 #endif
 
-       /* On win32, stack_start_limit should be 0, since the stack can grow dynamically */
        mono_thread_info_get_stack_bounds (&staddr, &stsize);
        if (staddr) {
-#ifndef HOST_WIN32
                info->client_info.stack_start_limit = staddr;
-#endif
                info->client_info.stack_end = staddr + stsize;
        } else {
                gsize stack_bottom = (gsize)stack_bottom_fallback;
@@ -2301,7 +2313,7 @@ sgen_thread_detach (SgenThreadInfo *p)
         * so we assume that if the domain is still registered, we can detach
         * the thread
         */
-       if (mono_domain_get ())
+       if (mono_thread_internal_current_is_attached ())
                mono_thread_detach_internal (mono_thread_internal_current ());
 }
 
@@ -2515,11 +2527,6 @@ mono_gc_get_generation (MonoObject *obj)
        return 1;
 }
 
-void
-mono_gc_enable_events (void)
-{
-}
-
 const char *
 mono_gc_get_gc_name (void)
 {
@@ -2791,6 +2798,7 @@ sgen_client_description_for_internal_mem_type (int type)
 {
        switch (type) {
        case INTERNAL_MEM_EPHEMERON_LINK: return "ephemeron-link";
+       case INTERNAL_MEM_MOVED_OBJECT: return "moved-object";
        default:
                return NULL;
        }
@@ -2867,13 +2875,6 @@ sgen_client_init (void)
        }
 #endif
 
-       /*
-        * This needs to happen before any internal allocations because
-        * it inits the small id which is required for hazard pointer
-        * operations.
-        */
-       sgen_os_init ();
-
        mono_gc_register_thread (&dummy);
 }
 
@@ -2896,7 +2897,7 @@ sgen_client_handle_gc_param (const char *opt)
        } else if (g_str_has_prefix (opt, "toggleref-test")) {
                /* FIXME: This should probably in MONO_GC_DEBUG */
                sgen_register_test_toggleref_callback ();
-       } else {
+       } else if (!sgen_bridge_handle_gc_param (opt)) {
                return FALSE;
        }
        return TRUE;
@@ -2973,6 +2974,10 @@ mono_gc_base_init (void)
 
        mono_counters_init ();
 
+#ifndef HOST_WIN32
+       mono_w32handle_init ();
+#endif
+
 #ifdef HEAVY_STATISTICS
        mono_counters_register ("los marked cards", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_marked_cards);
        mono_counters_register ("los array cards scanned ", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_array_cards);
@@ -3001,6 +3006,9 @@ void
 mono_gc_base_cleanup (void)
 {
        sgen_thread_pool_shutdown ();
+
+       // We should have consumed any outstanding moves.
+       g_assert (sgen_pointer_queue_is_empty (&moved_objects_queue));
 }
 
 gboolean