diff options
-rw-r--r-- | src/gc/env/gcenv.ee.h | 10 | ||||
-rw-r--r-- | src/gc/gc.cpp | 204 | ||||
-rw-r--r-- | src/gc/gc.h | 2 | ||||
-rw-r--r-- | src/gc/gccommon.cpp | 2 | ||||
-rw-r--r-- | src/gc/gcee.cpp | 25 | ||||
-rw-r--r-- | src/gc/gcenv.ee.standalone.inl | 30 | ||||
-rw-r--r-- | src/gc/gcimpl.h | 4 | ||||
-rw-r--r-- | src/gc/gcinterface.ee.h | 26 | ||||
-rw-r--r-- | src/gc/gcinterface.h | 3 | ||||
-rw-r--r-- | src/gc/gcpriv.h | 6 | ||||
-rw-r--r-- | src/gc/sample/gcenv.ee.cpp | 45 | ||||
-rw-r--r-- | src/gc/sample/gcenv.h | 7 | ||||
-rw-r--r-- | src/vm/gcenv.ee.cpp | 56 | ||||
-rw-r--r-- | src/vm/gcenv.ee.h | 10 | ||||
-rw-r--r-- | src/vm/threadsuspend.cpp | 6 |
15 files changed, 195 insertions, 241 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(); diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp index 0759768126..590cc1022e 100644 --- a/src/vm/gcenv.ee.cpp +++ b/src/vm/gcenv.ee.cpp @@ -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; diff --git a/src/vm/gcenv.ee.h b/src/vm/gcenv.ee.h index 452966988a..97413e3d53 100644 --- a/src/vm/gcenv.ee.h +++ b/src/vm/gcenv.ee.h @@ -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. diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp index 821b6a9c20..12fbc901a9 100644 --- a/src/vm/threadsuspend.cpp +++ b/src/vm/threadsuspend.cpp @@ -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 |