| Index: base/metrics/persistent_memory_allocator.cc
|
| diff --git a/base/metrics/persistent_memory_allocator.cc b/base/metrics/persistent_memory_allocator.cc
|
| index ee668233cf96b176d8962460ecd50054b6d5fec0..324d77f803f6fc375ad4b6530725f5f91bc491a1 100644
|
| --- a/base/metrics/persistent_memory_allocator.cc
|
| +++ b/base/metrics/persistent_memory_allocator.cc
|
| @@ -78,8 +78,8 @@ const uint32_t PersistentMemoryAllocator::kAllocAlignment = 8;
|
| struct PersistentMemoryAllocator::BlockHeader {
|
| uint32_t size; // Number of bytes in this block, including header.
|
| uint32_t cookie; // Constant value indicating completed allocation.
|
| - uint32_t type_id; // A number provided by caller indicating data type.
|
| - std::atomic<uint32_t> next; // Pointer to the next block when iterating.
|
| + std::atomic<uint32_t> type_id; // Arbitrary number indicating data type.
|
| + std::atomic<uint32_t> next; // Pointer to the next block when iterating.
|
| };
|
|
|
| // The shared metadata exists once at the top of the memory segment to
|
| @@ -188,7 +188,7 @@ PersistentMemoryAllocator::Iterator::GetNext(uint32_t* type_return) {
|
| // "strong" compare-exchange is used because failing unnecessarily would
|
| // mean repeating some fairly costly validations above.
|
| if (last_record_.compare_exchange_strong(last, next)) {
|
| - *type_return = block->type_id;
|
| + *type_return = block->type_id.load(std::memory_order_relaxed);
|
| break;
|
| }
|
| }
|
| @@ -295,7 +295,7 @@ PersistentMemoryAllocator::PersistentMemoryAllocator(
|
| shared_meta()->queue.next.load(std::memory_order_relaxed) != 0 ||
|
| first_block->size != 0 ||
|
| first_block->cookie != 0 ||
|
| - first_block->type_id != 0 ||
|
| + first_block->type_id.load(std::memory_order_relaxed) != 0 ||
|
| first_block->next != 0) {
|
| // ...or something malicious has been playing with the metadata.
|
| SetCorrupt();
|
| @@ -422,15 +422,20 @@ uint32_t PersistentMemoryAllocator::GetType(Reference ref) const {
|
| const volatile BlockHeader* const block = GetBlock(ref, 0, 0, false, false);
|
| if (!block)
|
| return 0;
|
| - return block->type_id;
|
| + return block->type_id.load(std::memory_order_relaxed);
|
| }
|
|
|
| -void PersistentMemoryAllocator::SetType(Reference ref, uint32_t type_id) {
|
| +bool PersistentMemoryAllocator::ChangeType(Reference ref,
|
| + uint32_t to_type_id,
|
| + uint32_t from_type_id) {
|
| DCHECK(!readonly_);
|
| volatile BlockHeader* const block = GetBlock(ref, 0, 0, false, false);
|
| if (!block)
|
| - return;
|
| - block->type_id = type_id;
|
| + return false;
|
| +
|
| + // This is a "strong" exchange because there is no loop that can retry in
|
| + // the wake of spurious failures possible with "weak" exchanges.
|
| + return block->type_id.compare_exchange_strong(from_type_id, to_type_id);
|
| }
|
|
|
| PersistentMemoryAllocator::Reference PersistentMemoryAllocator::Allocate(
|
| @@ -544,7 +549,7 @@ PersistentMemoryAllocator::Reference PersistentMemoryAllocator::AllocateImpl(
|
| // writing beyond the allocated space and into unallocated space.
|
| if (block->size != 0 ||
|
| block->cookie != kBlockCookieFree ||
|
| - block->type_id != 0 ||
|
| + block->type_id.load(std::memory_order_relaxed) != 0 ||
|
| block->next.load(std::memory_order_relaxed) != 0) {
|
| SetCorrupt();
|
| return kReferenceNull;
|
| @@ -552,7 +557,7 @@ PersistentMemoryAllocator::Reference PersistentMemoryAllocator::AllocateImpl(
|
|
|
| block->size = size;
|
| block->cookie = kBlockCookieAllocated;
|
| - block->type_id = type_id;
|
| + block->type_id.store(type_id, std::memory_order_relaxed);
|
| return freeptr;
|
| }
|
| }
|
| @@ -684,8 +689,10 @@ PersistentMemoryAllocator::GetBlock(Reference ref, uint32_t type_id,
|
| return nullptr;
|
| if (ref != kReferenceQueue && block->cookie != kBlockCookieAllocated)
|
| return nullptr;
|
| - if (type_id != 0 && block->type_id != type_id)
|
| + if (type_id != 0 &&
|
| + block->type_id.load(std::memory_order_relaxed) != type_id) {
|
| return nullptr;
|
| + }
|
| }
|
|
|
| // Return pointer to block data.
|
|
|