src/hotspot/share/gc/shared/taskqueue.cpp
changeset 53545 2c38991dd9b0
parent 52905 bec57b4a6d69
child 53586 5bc1634bc0ca
--- a/src/hotspot/share/gc/shared/taskqueue.cpp	Tue Jan 29 08:28:24 2019 -0500
+++ b/src/hotspot/share/gc/shared/taskqueue.cpp	Tue Jan 29 08:39:04 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -118,6 +118,11 @@
   _queue_set(queue_set),
   _offered_termination(0) {}
 
+ParallelTaskTerminator::~ParallelTaskTerminator() {
+  assert(_offered_termination == 0 || !peek_in_queue_set(), "Precondition");
+  assert(_offered_termination == 0 || _offered_termination == _n_threads, "Terminated or aborted" );
+}
+
 bool ParallelTaskTerminator::peek_in_queue_set() {
   return _queue_set->peek();
 }
@@ -162,6 +167,7 @@
     assert(_offered_termination <= _n_threads, "Invariant");
     // Are all threads offering termination?
     if (_offered_termination == _n_threads) {
+      assert(!peek_in_queue_set(), "Precondition");
       return true;
     } else {
       // Look for more work.
@@ -211,9 +217,7 @@
 #endif
       if (peek_in_queue_set() ||
           (terminator != NULL && terminator->should_exit_termination())) {
-        Atomic::dec(&_offered_termination);
-        assert(_offered_termination < _n_threads, "Invariant");
-        return false;
+        return complete_or_exit_termination();
       }
     }
   }
@@ -229,6 +233,23 @@
 }
 #endif
 
+bool ParallelTaskTerminator::complete_or_exit_termination() {
+  // If termination is ever reached, terminator should stay in such state,
+  // so that all threads see the same state
+  uint current_offered = _offered_termination;
+  uint expected_value;
+  do {
+    if (current_offered == _n_threads) {
+      assert(!peek_in_queue_set(), "Precondition");
+      return true;
+    }
+    expected_value = current_offered;
+  } while ((current_offered = Atomic::cmpxchg(current_offered - 1, &_offered_termination, current_offered)) != expected_value);
+
+  assert(_offered_termination < _n_threads, "Invariant");
+  return false;
+}
+
 void ParallelTaskTerminator::reset_for_reuse() {
   if (_offered_termination != 0) {
     assert(_offered_termination == _n_threads,