Merge pull request #956 from ermshiperete/bug-xamarin-14987
[mono.git] / mono / metadata / sgen-stw.c
index f2c19a2c4cffba8493982aa418c7a0f490bb6c5d..b6fe446cc36d28b5e8d4ca3341b342b5158007a2 100755 (executable)
@@ -147,11 +147,7 @@ restart_threads_until_none_in_managed_allocator (void)
                sgen_wait_for_suspend_ack (restart_count);
 
                if (sleep_duration < 0) {
-#ifdef HOST_WIN32
-                       SwitchToThread ();
-#else
-                       sched_yield ();
-#endif
+                       mono_thread_info_yield ();
                        sleep_duration = 0;
                } else {
                        g_usleep (sleep_duration);
@@ -195,18 +191,6 @@ release_gc_locks (void)
        UNLOCK_INTERRUPTION;
 }
 
-static void
-stw_bridge_process (void)
-{
-       sgen_bridge_processing_stw_step ();
-}
-
-static void
-bridge_process (int generation)
-{
-       sgen_bridge_processing_finish (generation);
-}
-
 static TV_DECLARE (stop_world_time);
 static unsigned long max_pause_usec = 0;
 
@@ -216,13 +200,13 @@ sgen_stop_world (int generation)
 {
        int count, dead;
 
-       /*XXX this is the right stop, thought might not be the nicest place to put it*/
-       sgen_process_togglerefs ();
-
        mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD, generation);
        MONO_GC_WORLD_STOP_BEGIN ();
        acquire_gc_locks ();
 
+       /* We start to scan after locks are taking, this ensures we won't be interrupted. */
+       sgen_process_togglerefs ();
+
        update_current_thread_stack (&count);
 
        sgen_global_stop_count++;
@@ -269,9 +253,6 @@ sgen_restart_world (int generation, GGTimingInfo *timing)
 #endif
        } END_FOREACH_THREAD
 
-       stw_bridge_process ();
-       release_gc_locks ();
-
        count = sgen_thread_handshake (FALSE);
        TV_GETTIME (end_sw);
        usec = TV_ELAPSED (stop_world_time, end_sw);
@@ -280,9 +261,21 @@ sgen_restart_world (int generation, GGTimingInfo *timing)
        mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD, generation);
        MONO_GC_WORLD_RESTART_END (generation);
 
-       mono_thread_hazardous_try_free_some ();
+       /*
+        * We must release the thread info suspend lock after doing
+        * the thread handshake.  Otherwise, if the GC stops the world
+        * and a thread is in the process of starting up, but has not
+        * yet registered (it's not in the thread_list), it is
+        * possible that the thread does register while the world is
+        * stopped.  When restarting the GC will then try to restart
+        * said thread, but since it never got the suspend signal, it
+        * cannot answer the restart signal, so a deadlock results.
+        */
+       release_gc_locks ();
 
-       bridge_process (generation);
+       sgen_try_free_some_memory = TRUE;
+
+       sgen_bridge_processing_finish (generation);
 
        TV_GETTIME (end_bridge);
        bridge_usec = TV_ELAPSED (end_sw, end_bridge);