summaryrefslogtreecommitdiff
path: root/src/gc
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
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')
-rw-r--r--src/gc/env/gcenv.ee.h10
-rw-r--r--src/gc/gc.cpp204
-rw-r--r--src/gc/gc.h2
-rw-r--r--src/gc/gccommon.cpp2
-rw-r--r--src/gc/gcee.cpp25
-rw-r--r--src/gc/gcenv.ee.standalone.inl30
-rw-r--r--src/gc/gcimpl.h4
-rw-r--r--src/gc/gcinterface.ee.h26
-rw-r--r--src/gc/gcinterface.h3
-rw-r--r--src/gc/gcpriv.h6
-rw-r--r--src/gc/sample/gcenv.ee.cpp45
-rw-r--r--src/gc/sample/gcenv.h7
12 files changed, 149 insertions, 215 deletions
diff --git a/src/gc/env/gcenv.ee.h b/src/gc/env/gcenv.ee.h
index 4ef1b93e48..db966310c0 100644
--- a/src/gc/env/gcenv.ee.h
+++ b/src/gc/env/gcenv.ee.h
@@ -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.
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();
diff --git a/src/gc/gc.h b/src/gc/gc.h
index a0e09cd1c5..3768166516 100644
--- a/src/gc/gc.h
+++ b/src/gc/gc.h
@@ -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 {
diff --git a/src/gc/gccommon.cpp b/src/gc/gccommon.cpp
index 01845668e1..e882431fef 100644
--- a/src/gc/gccommon.cpp
+++ b/src/gc/gccommon.cpp
@@ -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
diff --git a/src/gc/gcee.cpp b/src/gc/gcee.cpp
index b399cde14f..52f2eb3179 100644
--- a/src/gc/gcee.cpp
+++ b/src/gc/gcee.cpp
@@ -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);
diff --git a/src/gc/gcenv.ee.standalone.inl b/src/gc/gcenv.ee.standalone.inl
index 665bd32cbd..c4ec29d2d6 100644
--- a/src/gc/gcenv.ee.standalone.inl
+++ b/src/gc/gcenv.ee.standalone.inl
@@ -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)
diff --git a/src/gc/gcimpl.h b/src/gc/gcimpl.h
index 7210b9bcf0..261e26e9aa 100644
--- a/src/gc/gcimpl.h
+++ b/src/gc/gcimpl.h
@@ -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
diff --git a/src/gc/gcinterface.ee.h b/src/gc/gcinterface.ee.h
index e6e3bca49b..2d811e49f2 100644
--- a/src/gc/gcinterface.ee.h
+++ b/src/gc/gcinterface.ee.h
@@ -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
diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h
index 0d9aff8d1f..d0b6334e3b 100644
--- a/src/gc/gcinterface.h
+++ b/src/gc/gcinterface.h
@@ -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
diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h
index 4924e8c109..2c66acef4a 100644
--- a/src/gc/gcpriv.h
+++ b/src/gc/gcpriv.h
@@ -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 --------------------------*/
diff --git a/src/gc/sample/gcenv.ee.cpp b/src/gc/sample/gcenv.ee.cpp
index 3d0303205e..996701e74a 100644
--- a/src/gc/sample/gcenv.ee.cpp
+++ b/src/gc/sample/gcenv.ee.cpp
@@ -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;
diff --git a/src/gc/sample/gcenv.h b/src/gc/sample/gcenv.h
index 54b596e141..012ab44482 100644
--- a/src/gc/sample/gcenv.h
+++ b/src/gc/sample/gcenv.h
@@ -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();