src/share/vm/gc_implementation/g1/concurrentMark.cpp

Print this page
rev 6345 : 8040803: G1: Concurrent mark hangs when mark stack overflows
Reviewed-by: TDB

@@ -976,28 +976,37 @@
   }
 
   if (concurrent()) {
     SuspendibleThreadSet::leave();
   }
-  _first_overflow_barrier_sync.enter();
+
+  bool barrier_aborted = !_first_overflow_barrier_sync.enter();
+
   if (concurrent()) {
     SuspendibleThreadSet::join();
   }
   // at this point everyone should have synced up and not be doing any
   // more work
 
   if (verbose_low()) {
+    if (barrier_aborted) {
+      gclog_or_tty->print_cr("[%u] aborted first barrier", worker_id);
+    } else {
     gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id);
   }
+  }
 
   // If we're executing the concurrent phase of marking, reset the marking
   // state; otherwise the marking state is reset after reference processing,
   // during the remark pause.
   // If we reset here as a result of an overflow during the remark we will
   // see assertion failures from any subsequent set_concurrency_and_phase()
   // calls.
-  if (concurrent()) {
+  // If the barrier aborted we don't need to reset the marking state here
+  // since ConcurrentMark::abort() did that for us and we will now ignore
+  // the overflow condition and just abort the whole marking phase.
+  if (!barrier_aborted && concurrent()) {
     // let the task associated with with worker 0 do this
     if (worker_id == 0) {
       // task 0 is responsible for clearing the global data structures
       // We should be here because of an overflow. During STW we should
       // not clear the overflow flag since we rely on it being true when

@@ -1024,19 +1033,25 @@
   }
 
   if (concurrent()) {
     SuspendibleThreadSet::leave();
   }
-  _second_overflow_barrier_sync.enter();
+
+  bool barrier_aborted = !_second_overflow_barrier_sync.enter();
+
   if (concurrent()) {
     SuspendibleThreadSet::join();
   }
   // at this point everything should be re-initialized and ready to go
 
   if (verbose_low()) {
+    if (barrier_aborted) {
+      gclog_or_tty->print_cr("[%u] aborted second barrier", worker_id);
+    } else {
     gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id);
   }
+  }
 }
 
 #ifndef PRODUCT
 void ForceOverflowSettings::init() {
   _num_remaining = G1ConcMarkForceOverflow;

@@ -3238,10 +3253,12 @@
   // Empty mark stack
   reset_marking_state();
   for (uint i = 0; i < _max_worker_id; ++i) {
     _tasks[i]->clear_region_fields();
   }
+  _first_overflow_barrier_sync.abort();
+  _second_overflow_barrier_sync.abort();
   _has_aborted = true;
 
   SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
   satb_mq_set.abandon_partial_marking();
   // This can be called either during or outside marking, we'll read