// 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 #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::max()); } LockFreeAddressHashSet::~LockFreeAddressHashSet() { for (subtle::AtomicWord bucket : buckets_) { Node* node = reinterpret_cast(bucket); while (node) { Node* next = reinterpret_cast(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(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(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(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(bucket); node; node = next_node(node)) { subtle::AtomicWord k = subtle::NoBarrier_Load(&node->key); if (k) Insert(reinterpret_cast(k)); } } } } // namespace base