summaryrefslogtreecommitdiff
path: root/src/gc/gc.cpp
diff options
context:
space:
mode:
authorDavid Mason <davmason@microsoft.com>2018-03-13 01:24:20 -0700
committerGitHub <noreply@github.com>2018-03-13 01:24:20 -0700
commit8edb3ef2529cc0beb0c034482fdb32fa4c95c606 (patch)
tree369d8ecf4ca45f42341fc50b750ca7fe13086834 /src/gc/gc.cpp
parent0c4344f5a999d817b431b9e3934600ccb97d0e4b (diff)
downloadcoreclr-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.cpp204
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();