diff options
author | David Mason <davmason@microsoft.com> | 2018-03-13 01:24:20 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-13 01:24:20 -0700 |
commit | 8edb3ef2529cc0beb0c034482fdb32fa4c95c606 (patch) | |
tree | 369d8ecf4ca45f42341fc50b750ca7fe13086834 /src/gc/gc.cpp | |
parent | 0c4344f5a999d817b431b9e3934600ccb97d0e4b (diff) | |
download | coreclr-8edb3ef2529cc0beb0c034482fdb32fa4c95c606.tar.gz coreclr-8edb3ef2529cc0beb0c034482fdb32fa4c95c606.tar.bz2 coreclr-8edb3ef2529cc0beb0c034482fdb32fa4c95c606.zip |
[local gc] refactor apis for threading and suspension to avoid redundant calls in to the runtime (#16765)
* [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
Diffstat (limited to 'src/gc/gc.cpp')
-rw-r--r-- | src/gc/gc.cpp | 204 |
1 files changed, 76 insertions, 128 deletions
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp index fe0b36bfbc..3bc2809564 100644 --- a/src/gc/gc.cpp +++ b/src/gc/gc.cpp @@ -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(); |