Merge pull request #817 from desdesdes/master
[mono.git] / mono / metadata / sgen-gc.c
index da89a5f74f50175b016ef0fc6c731bb587ba7b1c..95f263c1c59c6313d50f4ac8aa3a47c4b8b2f1ab 100644 (file)
@@ -401,6 +401,7 @@ sgen_safe_name (void* obj)
  * ######################################################################
  */
 LOCK_DECLARE (gc_mutex);
+gboolean sgen_try_free_some_memory;
 
 #define SCAN_START_SIZE        SGEN_SCAN_START_SIZE
 
@@ -3105,6 +3106,13 @@ major_start_collection (gboolean concurrent, int *old_next_pin_slot)
 
 static void
 wait_for_workers_to_finish (void)
+{
+       while (!sgen_workers_all_done ())
+               g_usleep (200);
+}
+
+static void
+join_workers (void)
 {
        if (concurrent_collection_in_progress || major_collector.is_parallel) {
                gray_queue_redirect (&gray_queue);
@@ -3128,13 +3136,13 @@ major_finish_collection (const char *reason, int old_next_pin_slot, gboolean sca
        TV_GETTIME (btv);
 
        if (concurrent_collection_in_progress || major_collector.is_parallel)
-               wait_for_workers_to_finish ();
+               join_workers ();
 
        if (concurrent_collection_in_progress) {
                current_object_ops = major_collector.major_concurrent_ops;
 
                major_copy_or_mark_from_roots (NULL, TRUE, scan_mod_union);
-               wait_for_workers_to_finish ();
+               join_workers ();
 
                g_assert (sgen_gray_object_queue_is_empty (&gray_queue));
 
@@ -3341,19 +3349,30 @@ major_update_or_finish_concurrent_collection (gboolean force_finish)
 
        g_assert (sgen_gray_object_queue_is_empty (&gray_queue));
 
-       major_collector.update_cardtable_mod_union ();
-       sgen_los_update_cardtable_mod_union ();
-
        if (!force_finish && !sgen_workers_all_done ()) {
+               major_collector.update_cardtable_mod_union ();
+               sgen_los_update_cardtable_mod_union ();
+
                MONO_GC_CONCURRENT_UPDATE_END (GENERATION_OLD, major_collector.get_and_reset_num_major_objects_marked ());
                return FALSE;
        }
 
-       if (mod_union_consistency_check)
-               sgen_check_mod_union_consistency ();
+       /*
+        * The major collector can add global remsets which are processed in the finishing
+        * nursery collection, below.  That implies that the workers must have finished
+        * marking before the nursery collection is allowed to run, otherwise we might miss
+        * some remsets.
+        */
+       wait_for_workers_to_finish ();
+
+       major_collector.update_cardtable_mod_union ();
+       sgen_los_update_cardtable_mod_union ();
 
        collect_nursery (&unpin_queue, TRUE);
 
+       if (mod_union_consistency_check)
+               sgen_check_mod_union_consistency ();
+
        current_collection_generation = GENERATION_OLD;
        major_finish_collection ("finishing", -1, TRUE);
 
@@ -4091,6 +4110,7 @@ sgen_thread_register (SgenThreadInfo* info, void *addr)
 
        binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info));
 
+       // FIXME: Unift with mono_thread_get_stack_bounds ()
        /* try to get it with attributes first */
 #if (defined(HAVE_PTHREAD_GETATTR_NP) || defined(HAVE_PTHREAD_ATTR_GET_NP)) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
   {
@@ -4115,8 +4135,14 @@ sgen_thread_register (SgenThreadInfo* info, void *addr)
      pthread_attr_destroy (&attr);
   }
 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
-                info->stack_end = (char*)pthread_get_stackaddr_np (pthread_self ());
-                info->stack_start_limit = (char*)info->stack_end - pthread_get_stacksize_np (pthread_self ());
+       {
+               size_t stsize = 0;
+               guint8 *staddr = NULL;
+
+               mono_thread_get_stack_bounds (&staddr, &stsize);
+               info->stack_start_limit = staddr;
+               info->stack_end = staddr + stsize;
+       }
 #else
        {
                /* FIXME: we assume the stack grows down */
@@ -4139,7 +4165,7 @@ sgen_thread_register (SgenThreadInfo* info, void *addr)
 }
 
 static void
-sgen_thread_unregister (SgenThreadInfo *p)
+sgen_thread_detach (SgenThreadInfo *p)
 {
        /* If a delegate is passed to native code and invoked on a thread we dont
         * know about, the jit will register it with mono_jit_thread_attach, but
@@ -4149,7 +4175,11 @@ sgen_thread_unregister (SgenThreadInfo *p)
         */
        if (mono_domain_get ())
                mono_thread_detach (mono_thread_current ());
+}
 
+static void
+sgen_thread_unregister (SgenThreadInfo *p)
+{
        binary_protocol_thread_unregister ((gpointer)mono_thread_info_get_tid (p));
        SGEN_LOG (3, "unregister thread %p (%p)", p, (gpointer)mono_thread_info_get_tid (p));
 
@@ -4400,7 +4430,7 @@ mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
 
        SGEN_LOG (8, "Wbarrier atomic store at %p to %p (%s)", ptr, value, value ? safe_name (value) : "null");
 
-       mono_atomic_store_release ((volatile MonoObject **) ptr, value);
+       InterlockedWritePointer (ptr, value);
 
        if (ptr_in_nursery (value))
                mono_gc_wbarrier_generic_nostore (ptr);
@@ -4840,6 +4870,7 @@ mono_gc_base_init (void)
        gc_debug_file = stderr;
 
        cb.thread_register = sgen_thread_register;
+       cb.thread_detach = sgen_thread_detach;
        cb.thread_unregister = sgen_thread_unregister;
        cb.thread_attach = sgen_thread_attach;
        cb.mono_method_is_critical = (gpointer)is_critical_method;
@@ -5481,7 +5512,7 @@ mono_gc_get_write_barrier (void)
        res = mono_mb_create_method (mb, sig, 16);
        mono_mb_free (mb);
 
-       mono_loader_lock ();
+       LOCK_GC;
        if (write_barrier_method) {
                /* Already created */
                mono_free_method (res);
@@ -5490,7 +5521,7 @@ mono_gc_get_write_barrier (void)
                mono_memory_barrier ();
                write_barrier_method = res;
        }
-       mono_loader_unlock ();
+       UNLOCK_GC;
 
        return write_barrier_method;
 }
@@ -5567,7 +5598,12 @@ sgen_gc_lock (void)
 void
 sgen_gc_unlock (void)
 {
-       UNLOCK_GC;
+       gboolean try_free = sgen_try_free_some_memory;
+       sgen_try_free_some_memory = FALSE;
+       mono_mutex_unlock (&gc_mutex);
+       MONO_GC_UNLOCKED ();
+       if (try_free)
+               mono_thread_hazardous_try_free_some ();
 }
 
 void