src/hotspot/share/utilities/concurrentHashTable.inline.hpp
changeset 52516 d5eebe1e03fe
parent 52332 d2a3503c72f7
child 52717 b22da519f2e3
--- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp	Tue Nov 13 23:33:17 2018 -0500
+++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp	Wed Nov 14 07:50:37 2018 +0100
@@ -1116,6 +1116,8 @@
 inline void ConcurrentHashTable<VALUE, CONFIG, F>::
   do_scan(Thread* thread, SCAN_FUNC& scan_f)
 {
+  assert(!SafepointSynchronize::is_at_safepoint(),
+         "must be outside a safepoint");
   assert(_resize_lock_owner != thread, "Re-size lock held");
   lock_resize_lock(thread);
   do_scan_locked(thread, scan_f);
@@ -1124,6 +1126,49 @@
 }
 
 template <typename VALUE, typename CONFIG, MEMFLAGS F>
+template <typename SCAN_FUNC>
+inline void ConcurrentHashTable<VALUE, CONFIG, F>::
+  do_safepoint_scan(SCAN_FUNC& scan_f)
+{
+  // We only allow this method to be used during a safepoint.
+  assert(SafepointSynchronize::is_at_safepoint(),
+         "must only be called in a safepoint");
+  assert(Thread::current()->is_VM_thread(),
+         "should be in vm thread");
+
+  // Here we skip protection,
+  // thus no other thread may use this table at the same time.
+  InternalTable* table = get_table();
+  for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
+    Bucket* bucket = table->get_bucket(bucket_it);
+    // If bucket have a redirect the items will be in the new table.
+    // We must visit them there since the new table will contain any
+    // concurrent inserts done after this bucket was resized.
+    // If the bucket don't have redirect flag all items is in this table.
+    if (!bucket->have_redirect()) {
+      if(!visit_nodes(bucket, scan_f)) {
+        return;
+      }
+    } else {
+      assert(bucket->is_locked(), "Bucket must be locked.");
+    }
+  }
+  // If there is a paused resize we also need to visit the already resized items.
+  table = get_new_table();
+  if (table == NULL) {
+    return;
+  }
+  DEBUG_ONLY(if (table == POISON_PTR) { return; })
+  for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
+    Bucket* bucket = table->get_bucket(bucket_it);
+    assert(!bucket->is_locked(), "Bucket must be unlocked.");
+    if (!visit_nodes(bucket, scan_f)) {
+      return;
+    }
+  }
+}
+
+template <typename VALUE, typename CONFIG, MEMFLAGS F>
 template <typename EVALUATE_FUNC, typename DELETE_FUNC>
 inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
   try_bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f)
@@ -1142,6 +1187,8 @@
 inline void ConcurrentHashTable<VALUE, CONFIG, F>::
   bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f)
 {
+  assert(!SafepointSynchronize::is_at_safepoint(),
+         "must be outside a safepoint");
   lock_resize_lock(thread);
   do_bulk_delete_locked(thread, eval_f, del_f);
   unlock_resize_lock(thread);