Skip to content

Commit 64d14f3

Browse files
author
William Kemper
committed
8306334: Handle preemption of old cycle between filling and bootstrap phases
Reviewed-by: kdnilsen
1 parent badb738 commit 64d14f3

File tree

4 files changed

+27
-7
lines changed

4 files changed

+27
-7
lines changed

src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -526,18 +526,40 @@ void ShenandoahControlThread::service_concurrent_old_cycle(const ShenandoahHeap*
526526
_allow_old_preemption.unset();
527527

528528
if (heap->is_prepare_for_old_mark_in_progress()) {
529+
// Coalescing threads detected the cancellation request and aborted. Stay
530+
// in this state so control thread may resume the coalescing work.
529531
assert(old_generation->state() == ShenandoahOldGeneration::FILLING, "Prepare for mark should be in progress");
530532
return;
531533
}
532534

533-
assert(old_generation->state() == ShenandoahOldGeneration::BOOTSTRAPPING, "Finished with filling, should be bootstrapping");
535+
// It is possible for a young generation request to preempt this nascent old
536+
// collection cycle _after_ we've finished making the old regions parseable (filling),
537+
// but _before_ we have unset the preemption flag. It is also possible for an
538+
// allocation failure to occur after the threads have finished filling. We must
539+
// check if we have been cancelled before we start a bootstrap cycle.
540+
if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) {
541+
if (heap->cancelled_gc()) {
542+
// If this was a preemption request, the cancellation would have been cleared
543+
// so that we run a concurrent young cycle. If the cancellation is still set,
544+
// then this is an allocation failure and we need to run a degenerated cycle.
545+
// If this is a preemption request, we're just going to fall through and run
546+
// the bootstrap cycle to start the old generation cycle (the bootstrap cycle is
547+
// a concurrent young cycle - which is what we're being asked to do in that case).
548+
// If the cycle is cancelled for any other reason, we return from here and let
549+
// the control thread return to the top of its decision loop.
550+
log_info(gc)("Preparation for old generation cycle was cancelled");
551+
return;
552+
}
553+
}
554+
old_generation->transition_to(ShenandoahOldGeneration::BOOTSTRAPPING);
534555
}
535556
case ShenandoahOldGeneration::BOOTSTRAPPING: {
536557
// Configure the young generation's concurrent mark to put objects in
537558
// old regions into the concurrent mark queues associated with the old
538559
// generation. The young cycle will run as normal except that rather than
539560
// ignore old references it will mark and enqueue them in the old concurrent
540561
// task queues but it will not traverse them.
562+
set_gc_mode(bootstrapping_old);
541563
young_generation->set_old_gen_task_queues(old_generation->task_queues());
542564
ShenandoahGCSession session(cause, young_generation);
543565
service_concurrent_cycle(heap,young_generation, cause, true);
@@ -556,9 +578,7 @@ void ShenandoahControlThread::service_concurrent_old_cycle(const ShenandoahHeap*
556578

557579
// From here we will 'resume' the old concurrent mark. This will skip reset
558580
// and init mark for the concurrent mark. All of that work will have been
559-
// done by the bootstrapping young cycle. In order to simplify the debugging
560-
// effort, the old cycle will ONLY complete the mark phase. No actual
561-
// collection of the old generation is happening here.
581+
// done by the bootstrapping young cycle.
562582
set_gc_mode(servicing_old);
563583
old_generation->transition_to(ShenandoahOldGeneration::MARKING);
564584
}
@@ -1016,6 +1036,7 @@ const char* ShenandoahControlThread::gc_mode_name(ShenandoahControlThread::GCMod
10161036
case stw_degenerated: return "degenerated";
10171037
case stw_full: return "full";
10181038
case servicing_old: return "old";
1039+
case bootstrapping_old: return "bootstrap";
10191040
default: return "unknown";
10201041
}
10211042
}

src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class ShenandoahControlThread: public ConcurrentGCThread {
7474
concurrent_normal,
7575
stw_degenerated,
7676
stw_full,
77+
bootstrapping_old,
7778
servicing_old
7879
} GCMode;
7980

src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,10 @@ bool ShenandoahOldGeneration::coalesce_and_fill() {
267267
// Remember that we're done with coalesce-and-fill.
268268
heap->set_prepare_for_old_mark_in_progress(false);
269269
old_heuristics->abandon_collection_candidates();
270-
transition_to(BOOTSTRAPPING);
271270
return true;
272271
} else {
272+
// Otherwise, we were preempted before the work was done.
273273
log_debug(gc)("Suspending coalesce-and-fill of old heap regions");
274-
// Otherwise, we got preempted before the work was done.
275274
return false;
276275
}
277276
}

test/hotspot/jtreg/ProblemList.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ gc/stress/TestJNIBlockFullGC/TestJNIBlockFullGC.java 8192647 generic-all
8484
gc/stress/TestStressG1Humongous.java 8286554 windows-x64
8585

8686
gc/shenandoah/TestDynamicSoftMaxHeapSize.java#generational 8306333 generic-all
87-
gc/shenandoah/TestArrayCopyStress.java#generational 8306334 generic-all
8887
gc/shenandoah/oom/TestThreadFailure.java 8306335 generic-all
8988
gc/shenandoah/oom/TestClassLoaderLeak.java 8306336 generic-all
9089
gc/shenandoah/mxbeans/TestChurnNotifications.java#generational 8306337 generic-all

0 commit comments

Comments
 (0)