8264851: Shenandoah: Rework control loop mechanics to use timed waits

Reviewed-by: kdnilsen, shade
This commit is contained in:
William Kemper 2025-10-08 18:14:26 +00:00
parent ac73e688b1
commit 92f2ab2e1b
2 changed files with 22 additions and 10 deletions

View File

@ -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<int>(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();
}

View File

@ -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);