diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index f2447db8210c..7cf65811730e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -306,22 +306,25 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau } bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { + // Only read the cancellation cause once. Other threads may change it. ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->cancelled_gc()) { - if (heap->cancelled_cause() == GCCause::_shenandoah_stop_vm) { - return true; - } + const GCCause::Cause cancelled_cause = heap->cancelled_cause(); + if (cancelled_cause == GCCause::_no_gc) { + return false; + } - if (ShenandoahCollectorPolicy::is_allocation_failure(heap->cancelled_cause())) { - assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle, - "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); - _degen_point = point; - return true; - } + if (cancelled_cause == GCCause::_shenandoah_stop_vm) { + return true; + } - fatal("Unexpected reason for cancellation: %s", GCCause::to_string(heap->cancelled_cause())); + if (ShenandoahCollectorPolicy::is_allocation_failure(cancelled_cause)) { + assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle, + "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); + _degen_point = point; + return true; } - return false; + + fatal("Unexpected reason for cancellation: %s", GCCause::to_string(cancelled_cause)); } void ShenandoahControlThread::stop_service() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 94f3409ac41b..8ab7ded712ce 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -586,30 +586,31 @@ void ShenandoahGenerationalControlThread::service_concurrent_cycle(ShenandoahGen } bool ShenandoahGenerationalControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { - if (!_heap->cancelled_gc()) { + // Only read the cancellation cause once. Other threads may change it. + const GCCause::Cause cancelled_cause = _heap->cancelled_cause(); + if (cancelled_cause == GCCause::_no_gc) { return false; } - if (_heap->cancelled_cause() == GCCause::_shenandoah_stop_vm - || _heap->cancelled_cause() == GCCause::_shenandoah_concurrent_gc) { - log_debug(gc, thread)("Cancellation detected, reason: %s", GCCause::to_string(_heap->cancelled_cause())); + if (cancelled_cause == GCCause::_shenandoah_stop_vm + || cancelled_cause == GCCause::_shenandoah_concurrent_gc) { + log_debug(gc, thread)("Cancellation detected, reason: %s", GCCause::to_string(cancelled_cause)); return true; } - if (ShenandoahCollectorPolicy::is_allocation_failure(_heap->cancelled_cause())) { + if (ShenandoahCollectorPolicy::is_allocation_failure(cancelled_cause)) { assert(_degen_point == ShenandoahGC::_degenerated_unset, "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); - _requested_gc_cause = _heap->cancelled_cause(); + _requested_gc_cause = cancelled_cause; _degen_point = point; log_debug(gc, thread)("Cancellation detected:, reason: %s, degen point: %s", - GCCause::to_string(_heap->cancelled_cause()), + GCCause::to_string(cancelled_cause), ShenandoahGC::degen_point_to_string(_degen_point)); return true; } fatal("Cancel GC either for alloc failure GC, or gracefully exiting, or to pause old generation marking"); - return false; } void ShenandoahGenerationalControlThread::service_stw_full_cycle(GCCause::Cause cause) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index c0df4bbe10cb..aef9ed698d2f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -2257,8 +2257,18 @@ size_t ShenandoahHeap::tlab_used() const { } bool ShenandoahHeap::try_cancel_gc(GCCause::Cause cause) { - const GCCause::Cause prev = _cancelled_gc.xchg(cause); - return prev == GCCause::_no_gc || prev == GCCause::_shenandoah_concurrent_gc; + while (true) { + const GCCause::Cause prev = _cancelled_gc.get(); + if (prev != GCCause::_no_gc && prev != GCCause::_shenandoah_concurrent_gc && cause != GCCause::_shenandoah_stop_vm) { + // Only when the gc has not been cancelled, or it has been cancelled to interrupt an old marking cycle + // do we allow the new cancellation request to happen. We make an exception for stopping the VM. + return false; + } + + if (_cancelled_gc.cmpxchg(cause, prev) == prev) { + return true; + } + } } void ShenandoahHeap::cancel_concurrent_mark() { diff --git a/src/java.base/share/classes/java/lang/doc-files/ValueBased.html b/src/java.base/share/classes/java/lang/doc-files/ValueBased.html index 3b860ce0534f..0bdcf70df3a7 100644 --- a/src/java.base/share/classes/java/lang/doc-files/ValueBased.html +++ b/src/java.base/share/classes/java/lang/doc-files/ValueBased.html @@ -1,6 +1,6 @@