From 92f2ab2e1b5a7c02ea6d3a3a07c7fbbfc725cdea Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 8 Oct 2025 18:14:26 +0000 Subject: [PATCH] 8264851: Shenandoah: Rework control loop mechanics to use timed waits Reviewed-by: kdnilsen, shade --- .../gc/shenandoah/shenandoahControlThread.cpp | 27 ++++++++++++------- .../gc/shenandoah/shenandoahControlThread.hpp | 5 ++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index b960255891f..590e7831f07 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -43,7 +43,8 @@ ShenandoahControlThread::ShenandoahControlThread() : ShenandoahController(), _requested_gc_cause(GCCause::_no_gc), - _degen_point(ShenandoahGC::_degenerated_outside_cycle) { + _degen_point(ShenandoahGC::_degenerated_outside_cycle), + _control_lock(Mutex::nosafepoint - 2, "ShenandoahGCRequest_lock", true) { set_name("Shenandoah Control Thread"); create_and_start(); } @@ -228,7 +229,9 @@ void ShenandoahControlThread::run_service() { sleep = MIN2(ShenandoahControlIntervalMax, MAX2(1, sleep * 2)); last_sleep_adjust_time = current; } - os::naked_short_sleep(sleep); + + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + ml.wait(sleep); } } @@ -343,6 +346,16 @@ void ShenandoahControlThread::request_gc(GCCause::Cause cause) { } } +void ShenandoahControlThread::notify_control_thread(GCCause::Cause cause) { + // Although setting gc request is under _controller_lock, the read side (run_service()) + // does not take the lock. We need to enforce following order, so that read side sees + // latest requested gc cause when the flag is set. + MonitorLocker controller(&_control_lock, Mutex::_no_safepoint_check_flag); + _requested_gc_cause = cause; + _gc_requested.set(); + controller.notify(); +} + void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { if (should_terminate()) { log_info(gc)("Control thread is terminating, no more GCs"); @@ -354,8 +367,7 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { // The whitebox caller thread will arrange for itself to wait until the GC notifies // it that has reached the requested breakpoint (phase in the GC). if (cause == GCCause::_wb_breakpoint) { - _requested_gc_cause = cause; - _gc_requested.set(); + notify_control_thread(cause); return; } @@ -372,12 +384,7 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { size_t current_gc_id = get_gc_id(); size_t required_gc_id = current_gc_id + 1; while (current_gc_id < required_gc_id && !should_terminate()) { - // Although setting gc request is under _gc_waiters_lock, but read side (run_service()) - // does not take the lock. We need to enforce following order, so that read side sees - // latest requested gc cause when the flag is set. - _requested_gc_cause = cause; - _gc_requested.set(); - + notify_control_thread(cause); ml.wait(); current_gc_id = get_gc_id(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp index 4975404bbaa..c9bb6419201 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp @@ -45,6 +45,9 @@ private: GCCause::Cause _requested_gc_cause; ShenandoahGC::ShenandoahDegenPoint _degen_point; + // This lock is used to coordinate waking up the control thread + Monitor _control_lock; + public: ShenandoahControlThread(); @@ -54,6 +57,8 @@ public: void request_gc(GCCause::Cause cause) override; private: + // Sets the requested cause and flag and notifies the control thread + void notify_control_thread(GCCause::Cause cause); bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point); void service_concurrent_normal_cycle(GCCause::Cause cause);