| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/sampling_heap_profiler/lock_free_address_hash_set.h" |
| |
| #include <limits> |
| |
| #include "base/bits.h" |
| |
| namespace base { |
| |
| LockFreeAddressHashSet::LockFreeAddressHashSet(size_t buckets_count) |
| : buckets_(buckets_count), bucket_mask_(buckets_count - 1) { |
| DCHECK(bits::IsPowerOfTwo(buckets_count)); |
| DCHECK(bucket_mask_ <= std::numeric_limits<uint32_t>::max()); |
| } |
| |
| LockFreeAddressHashSet::~LockFreeAddressHashSet() { |
| for (subtle::AtomicWord bucket : buckets_) { |
| Node* node = reinterpret_cast<Node*>(bucket); |
| while (node) { |
| Node* next = reinterpret_cast<Node*>(node->next); |
| delete node; |
| node = next; |
| } |
| } |
| } |
| |
| void LockFreeAddressHashSet::Insert(void* key) { |
| // TODO(alph): Replace with DCHECK. |
| CHECK(key != nullptr); |
| CHECK(!Contains(key)); |
| subtle::NoBarrier_AtomicIncrement(&size_, 1); |
| uint32_t h = Hash(key); |
| subtle::AtomicWord* bucket_ptr = &buckets_[h & bucket_mask_]; |
| Node* node = reinterpret_cast<Node*>(subtle::NoBarrier_Load(bucket_ptr)); |
| // First iterate over the bucket nodes and try to reuse an empty one if found. |
| for (; node != nullptr; node = next_node(node)) { |
| if (subtle::NoBarrier_CompareAndSwap( |
| &node->key, 0, reinterpret_cast<subtle::AtomicWord>(key)) == 0) { |
| return; |
| } |
| } |
| DCHECK(node == nullptr); |
| // There are no empty nodes to reuse in the bucket. |
| // Create a new node and prepend it to the list. |
| Node* new_node = new Node(key); |
| subtle::AtomicWord current_head = subtle::NoBarrier_Load(bucket_ptr); |
| subtle::AtomicWord expected_head; |
| do { |
| subtle::NoBarrier_Store(&new_node->next, current_head); |
| expected_head = current_head; |
| current_head = subtle::Release_CompareAndSwap( |
| bucket_ptr, current_head, |
| reinterpret_cast<subtle::AtomicWord>(new_node)); |
| } while (current_head != expected_head); |
| } |
| |
| void LockFreeAddressHashSet::Copy(const LockFreeAddressHashSet& other) { |
| DCHECK_EQ(0u, size()); |
| for (subtle::AtomicWord bucket : other.buckets_) { |
| for (Node* node = reinterpret_cast<Node*>(bucket); node; |
| node = next_node(node)) { |
| subtle::AtomicWord k = subtle::NoBarrier_Load(&node->key); |
| if (k) |
| Insert(reinterpret_cast<void*>(k)); |
| } |
| } |
| } |
| |
| } // namespace base |