[local gc] refactor apis for threading and suspension to avoid redundant calls in...
authorDavid Mason <davmason@microsoft.com>
Tue, 13 Mar 2018 08:24:20 +0000 (01:24 -0700)
committerGitHub <noreply@github.com>
Tue, 13 Mar 2018 08:24:20 +0000 (01:24 -0700)
* [Local GC] Refactor calls involving thread modes, suspension, and alloc contexts to always operate on current thread

* BOOL -> bool for enable/disable preemptive routines, also remove an unused call to GetThread

* avoid one indirection by having GCToEEInterface::EnablePreemptiveGC return a bool indicating whether the mode was changed

* Callback on IGCHeap for the runtime to notify the GC when it is trapping threads

* use g_fSuspensionPending instead of GCToEEInterface::CatchAtSafePoint for allow_fgc

* Remove CatchAtSafePoint

* Remove GetThread from WaitLongerNoInstru

* code review feedback

* code review feedback

* change BOOL to bool

15 files changed:
src/gc/env/gcenv.ee.h
src/gc/gc.cpp
src/gc/gc.h
src/gc/gccommon.cpp
src/gc/gcee.cpp
src/gc/gcenv.ee.standalone.inl
src/gc/gcimpl.h
src/gc/gcinterface.ee.h
src/gc/gcinterface.h
src/gc/gcpriv.h
src/gc/sample/gcenv.ee.cpp
src/gc/sample/gcenv.h
src/vm/gcenv.ee.cpp
src/vm/gcenv.ee.h
src/vm/threadsuspend.cpp

index 4ef1b93..db96631 100644 (file)
@@ -47,14 +47,12 @@ public:
     static uint32_t GetActiveSyncBlockCount();
 
     // Thread functions
-    static bool IsPreemptiveGCDisabled(Thread * pThread);
-    static void EnablePreemptiveGC(Thread * pThread);
-    static void DisablePreemptiveGC(Thread * pThread);
-    static bool TrapReturningThreads();
+    static bool IsPreemptiveGCDisabled();
+    static bool EnablePreemptiveGC();
+    static void DisablePreemptiveGC();
     static Thread* GetThread();
 
-    static gc_alloc_context * GetAllocContext(Thread * pThread);
-    static bool CatchAtSafePoint(Thread * pThread);
+    static gc_alloc_context * GetAllocContext();
 
     static void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param);
     // Diagnostics methods.
index fe0b36b..3bc2809 100644 (file)
@@ -1370,9 +1370,7 @@ void recursive_gc_sync::begin_foreground()
 {
     dprintf (2, ("begin_foreground"));
 
-    BOOL cooperative_mode = FALSE;
-    Thread* current_thread = 0;
-
+    bool cooperative_mode = false;
     if (gc_background_running)
     {
         gc_heap::fire_alloc_wait_event_begin (awr_fgc_wait_for_bgc);
@@ -1387,14 +1385,13 @@ try_again_no_inc:
         assert (foreground_allowed.IsValid());
         assert (foreground_complete.IsValid());
 
-        current_thread = GCToEEInterface::GetThread();
-        cooperative_mode = gc_heap::enable_preemptive (current_thread);
+        cooperative_mode = gc_heap::enable_preemptive ();
 
         foreground_allowed.Wait(INFINITE, FALSE);
 
         dprintf(2, ("Waiting sync gc point is done"));
 
-        gc_heap::disable_preemptive (current_thread, cooperative_mode);
+        gc_heap::disable_preemptive (cooperative_mode);
 
         if (foreground_gate)
         {
@@ -1590,17 +1587,10 @@ inline bool can_use_write_watch_for_card_table()
 void WaitLongerNoInstru (int i)
 {
     // every 8th attempt:
-    Thread *pCurThread = GCToEEInterface::GetThread();
-    bool bToggleGC = false;
-    if (pCurThread)
-    {
-        bToggleGC = GCToEEInterface::IsPreemptiveGCDisabled(pCurThread);
-        if (bToggleGC)
-            GCToEEInterface::EnablePreemptiveGC(pCurThread);
-    }
+    bool bToggleGC = GCToEEInterface::EnablePreemptiveGC();
 
     // if we're waiting for gc to finish, we should block immediately
-    if (!GCToEEInterface::TrapReturningThreads())
+    if (g_fSuspensionPending == 0)
     {
         if  (g_num_processors > 1)
         {
@@ -1618,30 +1608,23 @@ void WaitLongerNoInstru (int i)
     // or it has no Thread object, in order to force a task to yield, or to triger a GC.
     // It is important that the thread is going to wait for GC.  Otherwise the thread
     // is in a tight loop.  If the thread has high priority, the perf is going to be very BAD.
-    if (pCurThread)
+    if (bToggleGC)
     {
-        if (bToggleGC || GCToEEInterface::TrapReturningThreads())
-        {
 #ifdef _DEBUG
-            // In debug builds, all enter_spin_lock operations go through this code.  If a GC has
-            // started, it is important to block until the GC thread calls set_gc_done (since it is
-            // guaranteed to have cleared g_TrapReturningThreads by this point).  This avoids livelock
-            // conditions which can otherwise occur if threads are allowed to spin in this function
-            // (and therefore starve the GC thread) between the point when the GC thread sets the
-            // WaitForGC event and the point when the GC thread clears g_TrapReturningThreads.
-            if (gc_heap::gc_started)
-            {
-                gc_heap::wait_for_gc_done();
-            }
-#endif // _DEBUG
-            GCToEEInterface::DisablePreemptiveGC(pCurThread);
-            if (!bToggleGC)
-            {
-                GCToEEInterface::EnablePreemptiveGC(pCurThread);
-            }
+        // In debug builds, all enter_spin_lock operations go through this code.  If a GC has
+        // started, it is important to block until the GC thread calls set_gc_done (since it is
+        // guaranteed to have cleared g_TrapReturningThreads by this point).  This avoids livelock
+        // conditions which can otherwise occur if threads are allowed to spin in this function
+        // (and therefore starve the GC thread) between the point when the GC thread sets the
+        // WaitForGC event and the point when the GC thread clears g_TrapReturningThreads.
+        if (gc_heap::gc_started)
+        {
+            gc_heap::wait_for_gc_done();
         }
+#endif // _DEBUG
+        GCToEEInterface::DisablePreemptiveGC();
     }
-    else if (GCToEEInterface::TrapReturningThreads())
+    else if (g_fSuspensionPending > 0)
     {
         g_theGCHeap->WaitUntilGCComplete();
     }
@@ -1650,12 +1633,11 @@ void WaitLongerNoInstru (int i)
 inline
 static void safe_switch_to_thread()
 {
-    Thread* current_thread = GCToEEInterface::GetThread();
-    BOOL cooperative_mode = gc_heap::enable_preemptive(current_thread);
+    bool cooperative_mode = gc_heap::enable_preemptive();
 
     GCToOSInterface::YieldThread(0);
 
-    gc_heap::disable_preemptive(current_thread, cooperative_mode);
+    gc_heap::disable_preemptive(cooperative_mode);
 }
 
 //
@@ -1769,20 +1751,8 @@ void WaitLonger (int i
 #endif //SYNCHRONIZATION_STATS
 
     // every 8th attempt:
-    Thread *pCurThread = GCToEEInterface::GetThread();
-    bool bToggleGC = false;
-    if (pCurThread)
-    {
-        bToggleGC = GCToEEInterface::IsPreemptiveGCDisabled(pCurThread);
-        if (bToggleGC)
-        {
-            GCToEEInterface::EnablePreemptiveGC(pCurThread);
-        }
-        else
-        {
-            assert (!"bToggleGC == TRUE");
-        }
-    }
+    bool bToggleGC = GCToEEInterface::EnablePreemptiveGC();
+    assert (bToggleGC);
 
     // if we're waiting for gc to finish, we should block immediately
     if (!gc_heap::gc_started)
@@ -1805,21 +1775,18 @@ void WaitLonger (int i
     // If CLR is hosted, a thread may reach here while it is in preemptive GC mode,
     // or it has no Thread object, in order to force a task to yield, or to triger a GC.
     // It is important that the thread is going to wait for GC.  Otherwise the thread
-    // is in a tight loop.  If the thread has high priority, the perf is going to be very BAD.
-    if (pCurThread)
+    // is in a tight loop.  If the thread has high priority, the perf is going to be very BAD. 
+    if (gc_heap::gc_started)
     {
-        if (bToggleGC || gc_heap::gc_started)
-        {
-            if (gc_heap::gc_started)
-            {
-                gc_heap::wait_for_gc_done();
-            }
+        gc_heap::wait_for_gc_done();
+    }
 
+    if (bToggleGC)
+    {
 #ifdef SYNCHRONIZATION_STATS
-            (spin_lock->num_disable_preemptive_w)++;
+        (spin_lock->num_disable_preemptive_w)++;
 #endif //SYNCHRONIZATION_STATS
-            GCToEEInterface::DisablePreemptiveGC(pCurThread);
-        }
+        GCToEEInterface::DisablePreemptiveGC();
     }
 }
 
@@ -1853,12 +1820,11 @@ retry:
 #ifdef SYNCHRONIZATION_STATS
                         (spin_lock->num_switch_thread)++;
 #endif //SYNCHRONIZATION_STATS
-                        Thread* current_thread = GCToEEInterface::GetThread();
-                        BOOL cooperative_mode = gc_heap::enable_preemptive (current_thread);
+                        BOOL cooperative_mode = gc_heap::enable_preemptive ();
 
                         GCToOSInterface::YieldThread(0);
 
-                        gc_heap::disable_preemptive (current_thread, cooperative_mode);
+                        gc_heap::disable_preemptive (cooperative_mode);
                     }
                 }
                 else
@@ -1892,29 +1858,16 @@ static void leave_spin_lock (GCSpinLock * spin_lock)
 
 #endif //_DEBUG
 
-BOOL gc_heap::enable_preemptive (Thread* current_thread)
+bool gc_heap::enable_preemptive ()
 {
-    bool cooperative_mode = false;
-    if (current_thread)
-    {
-        cooperative_mode = GCToEEInterface::IsPreemptiveGCDisabled(current_thread);
-        if (cooperative_mode)
-        {
-            GCToEEInterface::EnablePreemptiveGC(current_thread);
-        }
-    }
-
-    return cooperative_mode;
+    return GCToEEInterface::EnablePreemptiveGC();
 }
 
-void gc_heap::disable_preemptive (Thread* current_thread, BOOL restore_cooperative)
+void gc_heap::disable_preemptive (bool restore_cooperative)
 {
-    if (current_thread)
+    if (restore_cooperative)
     {
-        if (restore_cooperative)
-        {
-            GCToEEInterface::DisablePreemptiveGC(current_thread);
-        }
+        GCToEEInterface::DisablePreemptiveGC();
     }
 }
 
@@ -9624,10 +9577,9 @@ const size_t ww_reset_quantum = 128*1024*1024;
 inline
 void gc_heap::switch_one_quantum()
 {
-    Thread* current_thread = GCToEEInterface::GetThread();
-    enable_preemptive (current_thread);
+    enable_preemptive ();
     GCToOSInterface::Sleep (1);
-    disable_preemptive (current_thread, TRUE);
+    disable_preemptive (true);
 }
 
 void gc_heap::reset_ww_by_chunk (uint8_t* start_address, size_t total_reset_size)
@@ -10267,8 +10219,7 @@ gc_heap* gc_heap::make_gc_heap (
 uint32_t
 gc_heap::wait_for_gc_done(int32_t timeOut)
 {
-    Thread* current_thread = GCToEEInterface::GetThread();
-    BOOL cooperative_mode = enable_preemptive (current_thread);
+    bool cooperative_mode = enable_preemptive ();
 
     uint32_t dwWaitResult = NOERROR;
 
@@ -10286,7 +10237,7 @@ gc_heap::wait_for_gc_done(int32_t timeOut)
 
         dwWaitResult = wait_heap->gc_done_event.Wait(timeOut, FALSE); 
     }
-    disable_preemptive (current_thread, cooperative_mode);
+    disable_preemptive (cooperative_mode);
 
     return dwWaitResult;
 }
@@ -12369,13 +12320,12 @@ BOOL gc_heap::allocate_small (int gen_number,
         background_soh_alloc_count++;
         if ((background_soh_alloc_count % bgc_alloc_spin_count) == 0)
         {
-            Thread* current_thread = GCToEEInterface::GetThread();
             add_saved_spinlock_info (me_release, mt_alloc_small);
             dprintf (SPINLOCK_LOG, ("[%d]spin Lmsl", heap_number));
             leave_spin_lock (&more_space_lock);
-            BOOL cooperative_mode = enable_preemptive (current_thread);
+            bool cooperative_mode = enable_preemptive ();
             GCToOSInterface::Sleep (bgc_alloc_spin);
-            disable_preemptive (current_thread, cooperative_mode);
+            disable_preemptive (cooperative_mode);
             enter_spin_lock (&more_space_lock);
             add_saved_spinlock_info (me_acquire, mt_alloc_small);
             dprintf (SPINLOCK_LOG, ("[%d]spin Emsl", heap_number));
@@ -12898,13 +12848,12 @@ BOOL gc_heap::allocate_large (int gen_number,
             {
                 if (!bgc_alloc_spin_loh)
                 {
-                    Thread* current_thread = GCToEEInterface::GetThread();
                     add_saved_spinlock_info (me_release, mt_alloc_large);
                     dprintf (SPINLOCK_LOG, ("[%d]spin Lmsl loh", heap_number));
                     leave_spin_lock (&more_space_lock);
-                    BOOL cooperative_mode = enable_preemptive (current_thread);
+                    bool cooperative_mode = enable_preemptive ();
                     GCToOSInterface::YieldThread (bgc_alloc_spin_loh);
-                    disable_preemptive (current_thread, cooperative_mode);
+                    disable_preemptive (cooperative_mode);
                     enter_spin_lock (&more_space_lock);
                     add_saved_spinlock_info (me_acquire, mt_alloc_large);
                     dprintf (SPINLOCK_LOG, ("[%d]spin Emsl loh", heap_number));
@@ -15648,12 +15597,11 @@ void gc_heap::gc1()
         )
     {
 #ifdef BACKGROUND_GC
-        Thread* current_thread = GCToEEInterface::GetThread();
-        BOOL cooperative_mode = TRUE;
+        bool cooperative_mode = true;
 
         if (settings.concurrent)
         {
-            cooperative_mode = enable_preemptive (current_thread);
+            cooperative_mode = enable_preemptive ();
 
 #ifdef MULTIPLE_HEAPS
             bgc_t_join.join(this, gc_join_suspend_ee_verify);
@@ -15734,7 +15682,7 @@ void gc_heap::gc1()
             restart_EE();
 #endif //MULTIPLE_HEAPS
 
-            disable_preemptive (current_thread, cooperative_mode);
+            disable_preemptive (cooperative_mode);
         }
 #endif //BACKGROUND_GC
     }
@@ -25178,11 +25126,15 @@ void gc_heap::recover_bgc_settings()
 void gc_heap::allow_fgc()
 {
     assert (bgc_thread == GCToEEInterface::GetThread());
+    bool bToggleGC = false;
 
-    if (GCToEEInterface::IsPreemptiveGCDisabled(bgc_thread) && GCToEEInterface::CatchAtSafePoint(bgc_thread))
+    if (g_fSuspensionPending > 0)
     {
-        GCToEEInterface::EnablePreemptiveGC(bgc_thread);
-        GCToEEInterface::DisablePreemptiveGC(bgc_thread);
+        bToggleGC = GCToEEInterface::EnablePreemptiveGC();
+        if (bToggleGC)
+        {
+            GCToEEInterface::DisablePreemptiveGC();
+        }
     }
 }
 
@@ -25623,7 +25575,6 @@ void gc_heap::background_mark_phase ()
     sc.concurrent = FALSE;
 
     THREAD_FROM_HEAP;
-    Thread* current_thread = GCToEEInterface::GetThread();
     BOOL cooperative_mode = TRUE;
 #ifndef MULTIPLE_HEAPS
     const int thread = heap_number;
@@ -25762,7 +25713,7 @@ void gc_heap::background_mark_phase ()
         if (bgc_t_join.joined())
 #endif //MULTIPLE_HEAPS
         {
-            disable_preemptive (current_thread, TRUE);
+            disable_preemptive (true);
 
 #ifndef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
             // When software write watch is enabled, resetting write watch is done while the runtime is suspended above. The
@@ -25807,7 +25758,7 @@ void gc_heap::background_mark_phase ()
 
             current_c_gc_state = c_gc_state_marking;
 
-            enable_preemptive (current_thread);
+            enable_preemptive ();
 
 #ifdef MULTIPLE_HEAPS
             dprintf(3, ("Joining BGC threads after resetting writewatch"));
@@ -25815,13 +25766,13 @@ void gc_heap::background_mark_phase ()
 #endif //MULTIPLE_HEAPS
         }
 
-        disable_preemptive (current_thread, TRUE);
+        disable_preemptive (true);
 
         if (num_sizedrefs > 0)
         {
             GCScan::GcScanSizedRefs(background_promote, max_generation, max_generation, &sc);
 
-            enable_preemptive (current_thread);
+            enable_preemptive ();
 
 #ifdef MULTIPLE_HEAPS
             bgc_t_join.join(this, gc_join_scan_sizedref_done);
@@ -25832,7 +25783,7 @@ void gc_heap::background_mark_phase ()
             }
 #endif //MULTIPLE_HEAPS
 
-            disable_preemptive (current_thread, TRUE);
+            disable_preemptive (true);
         }
 
         dprintf (3,("BGC: handle table marking"));
@@ -25854,7 +25805,7 @@ void gc_heap::background_mark_phase ()
         //concurrent_print_time_delta ("concurrent marking dirtied pages on LOH");
         concurrent_print_time_delta ("CRre");
 
-        enable_preemptive (current_thread);
+        enable_preemptive ();
 
 #ifdef MULTIPLE_HEAPS
         bgc_t_join.join(this, gc_join_concurrent_overflow);
@@ -25884,7 +25835,7 @@ void gc_heap::background_mark_phase ()
         }
 #endif //MULTIPLE_HEAPS
 
-        disable_preemptive (current_thread, TRUE);
+        disable_preemptive (true);
 
         dprintf (2, ("before CRov count: %d", bgc_overflow_count));
         bgc_overflow_count = 0;
@@ -25899,7 +25850,7 @@ void gc_heap::background_mark_phase ()
 
         dprintf (2, ("Stopping the EE"));
 
-        enable_preemptive (current_thread);
+        enable_preemptive ();
 
 #ifdef MULTIPLE_HEAPS
         bgc_t_join.join(this, gc_join_suspend_ee);
@@ -26938,7 +26889,6 @@ void gc_heap::bgc_thread_function()
 
     BOOL do_exit = FALSE;
 
-    Thread* current_thread = GCToEEInterface::GetThread();
     BOOL cooperative_mode = TRUE;
     bgc_thread_id.SetToCurrentThread();
     dprintf (1, ("bgc_thread_id is set to %x", (uint32_t)GCToOSInterface::GetCurrentThreadIdForLogging()));
@@ -26947,7 +26897,7 @@ void gc_heap::bgc_thread_function()
         // Wait for work to do...
         dprintf (3, ("bgc thread: waiting..."));
 
-        cooperative_mode = enable_preemptive (current_thread);
+        cooperative_mode = enable_preemptive ();
         //current_thread->m_fPreemptiveGCDisabled = 0;
 
         uint32_t result = bgc_start_event.Wait(
@@ -27017,7 +26967,7 @@ void gc_heap::bgc_thread_function()
         //trace_gc = FALSE;
 #endif //TRACE_GC
 
-        enable_preemptive (current_thread);
+        enable_preemptive ();
 #ifdef MULTIPLE_HEAPS
         bgc_t_join.join(this, gc_join_done);
         if (bgc_t_join.joined())
@@ -31246,7 +31196,6 @@ void gc_heap::background_ephemeral_sweep()
 
 void gc_heap::background_sweep()
 {
-    Thread* current_thread  = GCToEEInterface::GetThread();
     generation* gen         = generation_of (max_generation);
     dynamic_data* dd        = dynamic_data_of (max_generation);
     // For SOH segments we go backwards.
@@ -31368,7 +31317,7 @@ void gc_heap::background_sweep()
 #endif //MULTIPLE_HEAPS
     }
 
-    disable_preemptive (current_thread, TRUE);
+    disable_preemptive (true);
 
     dprintf (2, ("bgs: sweeping gen2 objects"));
     dprintf (2, ("bgs: seg: %Ix, [%Ix, %Ix[%Ix", (size_t)seg,
@@ -31592,7 +31541,7 @@ void gc_heap::background_sweep()
     // be accurate.
     compute_new_dynamic_data (max_generation);
 
-    enable_preemptive (current_thread);
+    enable_preemptive ();
 
 #ifdef MULTIPLE_HEAPS
     bgc_t_join.join(this, gc_join_set_state_free);
@@ -31610,7 +31559,7 @@ void gc_heap::background_sweep()
 #endif //MULTIPLE_HEAPS
     }
 
-    disable_preemptive (current_thread, TRUE);
+    disable_preemptive (true);
 
     if (gc_lh_block_event.IsValid())
     {
@@ -34981,8 +34930,7 @@ GCHeap::GarbageCollectGeneration (unsigned int gen, gc_reason reason)
 #else
     gc_heap* hpt = 0;
 #endif //MULTIPLE_HEAPS
-    Thread* current_thread = GCToEEInterface::GetThread();
-    BOOL cooperative_mode = TRUE;
+    bool cooperative_mode = true;
     dynamic_data* dd = hpt->dynamic_data_of (gen);
     size_t localCount = dd_collection_count (dd);
 
@@ -35042,14 +34990,14 @@ GCHeap::GarbageCollectGeneration (unsigned int gen, gc_reason reason)
         init_sync_log_stats();
 
 #ifndef MULTIPLE_HEAPS
-        cooperative_mode = gc_heap::enable_preemptive (current_thread);
+        cooperative_mode = gc_heap::enable_preemptive ();
 
         dprintf (2, ("Suspending EE"));
         BEGIN_TIMING(suspend_ee_during_log);
         GCToEEInterface::SuspendEE(SUSPEND_FOR_GC);
         END_TIMING(suspend_ee_during_log);
         gc_heap::proceed_with_gc_p = gc_heap::should_proceed_with_gc();
-        gc_heap::disable_preemptive (current_thread, cooperative_mode);
+        gc_heap::disable_preemptive (cooperative_mode);
         if (gc_heap::proceed_with_gc_p)
             pGenGCHeap->settings.init_mechanisms();
         else
@@ -35083,14 +35031,14 @@ GCHeap::GarbageCollectGeneration (unsigned int gen, gc_reason reason)
 #ifdef MULTIPLE_HEAPS
     GcCondemnedGeneration = condemned_generation_number;
 
-    cooperative_mode = gc_heap::enable_preemptive (current_thread);
+    cooperative_mode = gc_heap::enable_preemptive ();
 
     BEGIN_TIMING(gc_during_log);
     gc_heap::ee_suspend_event.Set();
     gc_heap::wait_for_gc_done();
     END_TIMING(gc_during_log);
 
-    gc_heap::disable_preemptive (current_thread, cooperative_mode);
+    gc_heap::disable_preemptive (cooperative_mode);
 
     condemned_generation_number = GcCondemnedGeneration;
 #else
@@ -35302,7 +35250,7 @@ int GCHeap::GetHomeHeapNumber ()
     {
         if (pThread)
         {
-            gc_alloc_context* ctx = GCToEEInterface::GetAllocContext(pThread);
+            gc_alloc_context* ctx = GCToEEInterface::GetAllocContext();
             GCHeap *hp = static_cast<alloc_context*>(ctx)->get_home_heap();
             if (hp == gc_heap::g_heaps[i]->vm_heap) return i;
         }
@@ -35757,7 +35705,7 @@ void CFinalize::EnterFinalizeLock()
 {
     _ASSERTE(dbgOnly_IsSpecialEEThread() ||
              GCToEEInterface::GetThread() == 0 ||
-             GCToEEInterface::IsPreemptiveGCDisabled(GCToEEInterface::GetThread()));
+             GCToEEInterface::IsPreemptiveGCDisabled());
 
 retry:
     if (Interlocked::CompareExchange(&lock, 0, -1) >= 0)
@@ -35784,7 +35732,7 @@ void CFinalize::LeaveFinalizeLock()
 {
     _ASSERTE(dbgOnly_IsSpecialEEThread() ||
              GCToEEInterface::GetThread() == 0 ||
-             GCToEEInterface::IsPreemptiveGCDisabled(GCToEEInterface::GetThread()));
+             GCToEEInterface::IsPreemptiveGCDisabled());
 
 #ifdef _DEBUG
     lockowner_threadid.Clear();
index a0e09cd..3768166 100644 (file)
@@ -136,6 +136,8 @@ extern "C" uint32_t g_max_generation;
 extern "C" MethodTable* g_gc_pFreeObjectMethodTable;
 extern "C" uint32_t g_num_processors;
 
+extern VOLATILE(int32_t) g_fSuspensionPending;
+
 ::IGCHandleManager*  CreateGCHandleManager();
 
 namespace WKS {
index 0184566..e882431 100644 (file)
@@ -35,6 +35,8 @@ uint8_t* g_shadow_lowest_address = NULL;
 
 uint32_t* g_gc_card_table;
 
+VOLATILE(int32_t) g_fSuspensionPending = 0;
+
 #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
 uint32_t* g_gc_card_bundle_table;
 #endif
index b399cde..52f2eb3 100644 (file)
@@ -455,24 +455,19 @@ void gc_heap::fire_etw_pin_object_event (uint8_t* object, uint8_t** ppObject)
 uint32_t gc_heap::user_thread_wait (GCEvent *event, BOOL no_mode_change, int time_out_ms)
 {
     Thread* pCurThread = NULL;
-    bool mode = false;
+    bool bToggleGC = false;
     uint32_t dwWaitResult = NOERROR;
     
     if (!no_mode_change)
     {
-        pCurThread = GCToEEInterface::GetThread();
-        mode = pCurThread ? GCToEEInterface::IsPreemptiveGCDisabled(pCurThread) : false;
-        if (mode)
-        {
-            GCToEEInterface::EnablePreemptiveGC(pCurThread);
-        }
+        bToggleGC = GCToEEInterface::EnablePreemptiveGC();
     }
 
     dwWaitResult = event->Wait(time_out_ms, FALSE);
 
-    if (!no_mode_change && mode)
+    if (bToggleGC)
     {
-        GCToEEInterface::DisablePreemptiveGC(pCurThread);
+        GCToEEInterface::DisablePreemptiveGC();
     }
 
     return dwWaitResult;
@@ -608,6 +603,18 @@ bool GCHeap::RuntimeStructuresValid()
     return GCScan::GetGcRuntimeStructuresValid();
 }
 
+void GCHeap::SetSuspensionPending(bool fSuspensionPending)
+{
+    if (fSuspensionPending)
+    {
+        Interlocked::Increment(&g_fSuspensionPending);
+    }
+    else
+    {
+        Interlocked::Decrement(&g_fSuspensionPending);
+    }
+}
+
 void GCHeap::ControlEvents(GCEventKeyword keyword, GCEventLevel level)
 {
     GCEventStatus::Set(GCEventProvider_Default, keyword, level);
index 665bd32..c4ec29d 100644 (file)
@@ -83,30 +83,28 @@ inline void GCToEEInterface::SyncBlockCachePromotionsGranted(int max_gen)
     g_theGCToCLR->SyncBlockCachePromotionsGranted(max_gen);
 }
 
-
 inline uint32_t GCToEEInterface::GetActiveSyncBlockCount()
 {
     assert(g_theGCToCLR != nullptr);
     return g_theGCToCLR->GetActiveSyncBlockCount();
 }
 
-inline bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread)
+inline bool GCToEEInterface::IsPreemptiveGCDisabled()
 {
     assert(g_theGCToCLR != nullptr);
-    return g_theGCToCLR->IsPreemptiveGCDisabled(pThread);
+    return g_theGCToCLR->IsPreemptiveGCDisabled();
 }
 
-
-inline void GCToEEInterface::EnablePreemptiveGC(Thread * pThread)
+inline bool GCToEEInterface::EnablePreemptiveGC()
 {
     assert(g_theGCToCLR != nullptr);
-    g_theGCToCLR->EnablePreemptiveGC(pThread);
+    return  g_theGCToCLR->EnablePreemptiveGC();
 }
 
-inline void GCToEEInterface::DisablePreemptiveGC(Thread * pThread)
+inline void GCToEEInterface::DisablePreemptiveGC()
 {
     assert(g_theGCToCLR != nullptr);
-    g_theGCToCLR->DisablePreemptiveGC(pThread);
+    g_theGCToCLR->DisablePreemptiveGC();
 }
 
 inline Thread* GCToEEInterface::GetThread()
@@ -115,22 +113,10 @@ inline Thread* GCToEEInterface::GetThread()
     return g_theGCToCLR->GetThread();
 }
 
-inline bool GCToEEInterface::TrapReturningThreads()
-{
-    assert(g_theGCToCLR != nullptr);
-    return g_theGCToCLR->TrapReturningThreads();
-}
-
-inline gc_alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread)
-{
-    assert(g_theGCToCLR != nullptr);
-    return g_theGCToCLR->GetAllocContext(pThread);
-}
-
-inline bool GCToEEInterface::CatchAtSafePoint(Thread * pThread)
+inline gc_alloc_context * GCToEEInterface::GetAllocContext()
 {
     assert(g_theGCToCLR != nullptr);
-    return g_theGCToCLR->CatchAtSafePoint(pThread);
+    return g_theGCToCLR->GetAllocContext();
 }
 
 inline void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* param)
index 7210b9b..261e26e 100644 (file)
@@ -91,6 +91,8 @@ public:
 
     bool RuntimeStructuresValid();
 
+    void SetSuspensionPending(bool fSuspensionPending);
+
     void SetWaitForGCEvent();
     void ResetWaitForGCEvent();
 
@@ -258,7 +260,7 @@ private:
         // to threads returning to cooperative mode is down after gc.
         // In other words, if the sequence in GCHeap::RestartEE changes,
         // the condition here may have to change as well.
-        return !GCToEEInterface::TrapReturningThreads();
+        return g_fSuspensionPending == 0;
     }
 public:
     //return TRUE if GC actually happens, otherwise FALSE
index e6e3bca..2d811e4 100644 (file)
@@ -221,17 +221,19 @@ public:
     virtual
     uint32_t GetActiveSyncBlockCount() = 0;
 
-    // Queries whether or not the given thread has preemptive GC disabled.
+    // Queries whether or not the current thread has preemptive GC disabled.
     virtual
-    bool IsPreemptiveGCDisabled(Thread * pThread) = 0;
+    bool IsPreemptiveGCDisabled() = 0;
 
-    // Enables preemptive GC on the given thread.
+    // Enables preemptive GC on the current thread. Returns true if the thread mode 
+    // was changed and false if the thread mode wasn't changed or the thread is not
+    // a managed thread. 
     virtual
-    void EnablePreemptiveGC(Thread * pThread) = 0;
+    bool EnablePreemptiveGC() = 0;
 
-    // Disables preemptive GC on the given thread.
+    // Disables preemptive GC on the current thread.
     virtual
-    void DisablePreemptiveGC(Thread * pThread) = 0;
+    void DisablePreemptiveGC() = 0;
 
     // Gets the Thread instance for the current thread, or null if no thread
     // instance is associated with this thread.
@@ -241,17 +243,9 @@ public:
     virtual
     Thread* GetThread() = 0;
 
-    // Returns whether or not a thread suspension is pending.
+    // Retrieves the alloc context associated with the current thread.
     virtual
-    bool TrapReturningThreads() = 0;
-
-    // Retrieves the alloc context associated with a given thread.
-    virtual
-    gc_alloc_context * GetAllocContext(Thread * pThread) = 0;
-
-    // Returns true if this thread is waiting to reach a safe point.
-    virtual
-    bool CatchAtSafePoint(Thread * pThread) = 0;
+    gc_alloc_context * GetAllocContext() = 0;
 
     // Calls the given enum_alloc_context_func with every active alloc context.
     virtual
index 0d9aff8..d0b6334 100644 (file)
@@ -717,6 +717,9 @@ public:
     // Gets whether or not the GC runtime structures are in a valid state for heap traversal.
     virtual bool RuntimeStructuresValid() = 0;
 
+    // Tells the GC when the VM is suspending threads.
+    virtual void SetSuspensionPending(bool fSuspensionPending) = 0;
+
     /*
     ============================================================================
     Add/RemoveMemoryPressure support routines. These are on the interface
index 4924e8c..2c66ace 100644 (file)
@@ -2797,12 +2797,12 @@ public:
     PER_HEAP_ISOLATED
     uint32_t wait_for_gc_done(int32_t timeOut = INFINITE);
 
-    // Returns TRUE if the thread used to be in cooperative mode 
+    // Returns TRUE if the current thread used to be in cooperative mode 
     // before calling this function.
     PER_HEAP_ISOLATED
-    BOOL enable_preemptive (Thread* current_thread);
+    bool enable_preemptive ();
     PER_HEAP_ISOLATED
-    void disable_preemptive (Thread* current_thread, BOOL restore_cooperative);
+    void disable_preemptive (bool restore_cooperative);
 
     /* ------------------- per heap members --------------------------*/
 
index 3d03032..996701e 100644 (file)
@@ -11,8 +11,6 @@
 
 MethodTable * g_pFreeObjectMethodTable;
 
-int32_t g_TrapReturningThreads;
-
 EEConfig * g_pConfig;
 
 gc_alloc_context g_global_alloc_context;
@@ -88,18 +86,14 @@ uint32_t CLREventStatic::Wait(uint32_t dwMilliseconds, bool bAlertable)
 
         if (NULL != pCurThread)
         {
-            if (GCToEEInterface::IsPreemptiveGCDisabled(pCurThread))
-            {
-                GCToEEInterface::EnablePreemptiveGC(pCurThread);
-                disablePreemptive = true;
-            }
+            disablePreemptive = GCToEEInterface::EnablePreemptiveGC();
         }
 
         result = WaitForSingleObjectEx(m_hEvent, dwMilliseconds, bAlertable);
 
         if (disablePreemptive)
         {
-            GCToEEInterface::DisablePreemptiveGC(pCurThread);
+            GCToEEInterface::DisablePreemptiveGC();
         }
     }
 
@@ -175,18 +169,32 @@ bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject)
     return false;
 }
 
-bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread)
+bool GCToEEInterface::IsPreemptiveGCDisabled()
 {
+    Thread* pThread = ::GetThread();
     return pThread->PreemptiveGCDisabled();
 }
 
-void GCToEEInterface::EnablePreemptiveGC(Thread * pThread)
+bool GCToEEInterface::EnablePreemptiveGC()
 {
-    return pThread->EnablePreemptiveGC();
+    bool bToggleGC = false;
+    Thread* pThread = ::GetThread();
+
+    if (pThread)
+    {
+        bToggleGC = !!pThread->PreemptiveGCDisabled();
+        if (bToggleGC)
+        {
+            pThread->EnablePreemptiveGC();
+        }
+    }
+
+    return bToggleGC;
 }
 
-void GCToEEInterface::DisablePreemptiveGC(Thread * pThread)
+void GCToEEInterface::DisablePreemptiveGC()
 {
+    Thread* pThread = ::GetThread();
     pThread->DisablePreemptiveGC();
 }
 
@@ -195,21 +203,12 @@ Thread* GCToEEInterface::GetThread()
     return ::GetThread();
 }
 
-bool GCToEEInterface::TrapReturningThreads()
-{
-    return !!g_TrapReturningThreads;
-}
-
-gc_alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread)
+gc_alloc_context * GCToEEInterface::GetAllocContext()
 {
+    Thread* pThread = ::GetThread();
     return pThread->GetAllocContext();
 }
 
-bool GCToEEInterface::CatchAtSafePoint(Thread * pThread)
-{
-    return pThread->CatchAtSafePoint();
-}
-
 void GCToEEInterface::GcEnumAllocContexts (enum_alloc_context_func* fn, void* param)
 {
     Thread * pThread = NULL;
index 54b596e..012ab44 100644 (file)
@@ -124,13 +124,6 @@ public:
     void SetGCSpecial(bool fGCSpecial)
     {
     }
-
-    bool CatchAtSafePoint()
-    {
-        // This is only called by the GC on a background GC worker thread that's explicitly interested in letting
-        // a foreground GC proceed at that point. So it's always safe to return true.
-        return true;
-    }
 };
 
 Thread * GetThread();
index 0759768..590cc10 100644 (file)
@@ -169,7 +169,7 @@ void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen,
         STRESS_LOG2(LF_GC | LF_GCROOTS, LL_INFO100, "{ Starting scan of Thread %p ID = %x\n", pThread, pThread->GetThreadId());
 
         if (GCHeapUtilities::GetGCHeap()->IsThreadUsingAllocationContextHeap(
-            GCToEEInterface::GetAllocContext(pThread), sc->thread_number))
+            pThread->GetAllocContext(), sc->thread_number))
         {
             sc->thread_under_crawl = pThread;
 #ifdef FEATURE_EVENT_TRACE
@@ -315,18 +315,15 @@ uint32_t GCToEEInterface::GetActiveSyncBlockCount()
     return SyncBlockCache::GetSyncBlockCache()->GetActiveCount();   
 }
 
-gc_alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread)
+gc_alloc_context * GCToEEInterface::GetAllocContext()
 {
     WRAPPER_NO_CONTRACT;
+    
+    Thread* pThread = ::GetThread();
+    assert(pThread != nullptr);
     return pThread->GetAllocContext();
 }
 
-bool GCToEEInterface::CatchAtSafePoint(Thread * pThread)
-{
-    WRAPPER_NO_CONTRACT;
-    return !!pThread->CatchAtSafePoint();
-}
-
 void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* param)
 {
     CONTRACTL
@@ -350,22 +347,47 @@ void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* par
     }
 }
 
-bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread)
+bool GCToEEInterface::IsPreemptiveGCDisabled()
 {
     WRAPPER_NO_CONTRACT;
-    return !!pThread->PreemptiveGCDisabled();
+
+    Thread* pThread = ::GetThread();
+    if (pThread)
+    {
+        return !!pThread->PreemptiveGCDisabled();
+    }
+
+    return false;
 }
 
-void GCToEEInterface::EnablePreemptiveGC(Thread * pThread)
+bool GCToEEInterface::EnablePreemptiveGC()
 {
     WRAPPER_NO_CONTRACT;
-    pThread->EnablePreemptiveGC();
+
+    bool bToggleGC = false;
+    Thread* pThread = ::GetThread();
+
+    if (pThread)
+    {
+        bToggleGC = !!pThread->PreemptiveGCDisabled();
+        if (bToggleGC)
+        {
+            pThread->EnablePreemptiveGC();
+        }
+    }
+
+    return bToggleGC;
 }
 
-void GCToEEInterface::DisablePreemptiveGC(Thread * pThread)
+void GCToEEInterface::DisablePreemptiveGC()
 {
     WRAPPER_NO_CONTRACT;
-    pThread->DisablePreemptiveGC();
+
+    Thread* pThread = ::GetThread();
+    if (pThread)
+    {
+        pThread->DisablePreemptiveGC();
+    }
 }
 
 Thread* GCToEEInterface::GetThread()
@@ -375,12 +397,6 @@ Thread* GCToEEInterface::GetThread()
     return ::GetThread();
 }
 
-bool GCToEEInterface::TrapReturningThreads()
-{
-    WRAPPER_NO_CONTRACT;
-    return !!g_TrapReturningThreads;
-}
-
 struct BackgroundThreadStubArgs
 {
     Thread* thread;
index 4529669..97413e3 100644 (file)
@@ -29,13 +29,11 @@ public:
     void SyncBlockCacheDemote(int max_gen);
     void SyncBlockCachePromotionsGranted(int max_gen);
     uint32_t GetActiveSyncBlockCount();
-    bool IsPreemptiveGCDisabled(Thread * pThread);
-    void EnablePreemptiveGC(Thread * pThread);
-    void DisablePreemptiveGC(Thread * pThread);
+    bool IsPreemptiveGCDisabled();
+    bool EnablePreemptiveGC();
+    void DisablePreemptiveGC();
     Thread* GetThread();
-    bool TrapReturningThreads();
-    gc_alloc_context * GetAllocContext(Thread * pThread);
-    bool CatchAtSafePoint(Thread * pThread);
+    gc_alloc_context * GetAllocContext();
     void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param);
 
     // Diagnostics methods.
index 821b6a9..12fbc90 100644 (file)
@@ -3572,6 +3572,7 @@ void ThreadStore::TrapReturningThreads(BOOL yes)
         FastInterlockIncrement(&g_trtChgStamp);
 #endif
 
+        GCHeapUtilities::GetGCHeap()->SetSuspensionPending(true);
         FastInterlockIncrement (&g_TrapReturningThreads);
 #ifdef ENABLE_FAST_GCPOLL_HELPER
         EnableJitGCPoll();
@@ -3585,10 +3586,15 @@ void ThreadStore::TrapReturningThreads(BOOL yes)
     else
     {
         FastInterlockDecrement (&g_TrapReturningThreads);
+        GCHeapUtilities::GetGCHeap()->SetSuspensionPending(false);
+
 #ifdef ENABLE_FAST_GCPOLL_HELPER
         if (0 == g_TrapReturningThreads)
+        {
             DisableJitGCPoll();
+        }
 #endif
+
         _ASSERTE(g_TrapReturningThreads >= 0);
     }
 #ifdef ENABLE_FAST_GCPOLL_HELPER