| OLD | NEW |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/metrics/persistent_memory_allocator.h" | 5 #include "base/metrics/persistent_memory_allocator.h" |
| 6 | 6 |
| 7 #include <assert.h> | 7 #include <assert.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 | 9 |
| 10 #if defined(OS_WIN) | 10 #if defined(OS_WIN) |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 if (!block) { // Memory is corrupt. | 211 if (!block) { // Memory is corrupt. |
| 212 allocator_->SetCorrupt(); | 212 allocator_->SetCorrupt(); |
| 213 return kReferenceNull; | 213 return kReferenceNull; |
| 214 } | 214 } |
| 215 | 215 |
| 216 // Update the "last_record" pointer to be the reference being returned. | 216 // Update the "last_record" pointer to be the reference being returned. |
| 217 // If it fails then another thread has already iterated past it so loop | 217 // If it fails then another thread has already iterated past it so loop |
| 218 // again. Failing will also load the existing value into "last" so there | 218 // again. Failing will also load the existing value into "last" so there |
| 219 // is no need to do another such load when the while-loop restarts. A | 219 // is no need to do another such load when the while-loop restarts. A |
| 220 // "strong" compare-exchange is used because failing unnecessarily would | 220 // "strong" compare-exchange is used because failing unnecessarily would |
| 221 // mean repeating some fairly costly validations above. This operation | 221 // mean repeating some fairly costly validations above. |
| 222 // is "relaxed" because the iterator has no other values to protect and | |
| 223 // the referenced object will be accessed via an "acquire" in GetAsObject. | |
| 224 if (last_record_.compare_exchange_strong( | 222 if (last_record_.compare_exchange_strong( |
| 225 last, next, std::memory_order_relaxed, std::memory_order_relaxed)) { | 223 last, next, std::memory_order_acq_rel, std::memory_order_acquire)) { |
| 226 *type_return = block->type_id.load(std::memory_order_relaxed); | 224 *type_return = block->type_id.load(std::memory_order_relaxed); |
| 227 break; | 225 break; |
| 228 } | 226 } |
| 229 } | 227 } |
| 230 | 228 |
| 231 // Memory corruption could cause a loop in the list. Such must be detected | 229 // Memory corruption could cause a loop in the list. Such must be detected |
| 232 // so as to not cause an infinite loop in the caller. This is done by simply | 230 // so as to not cause an infinite loop in the caller. This is done by simply |
| 233 // making sure it doesn't iterate more times than the absolute maximum | 231 // making sure it doesn't iterate more times than the absolute maximum |
| 234 // number of allocations that could have been made. Callers are likely | 232 // number of allocations that could have been made. Callers are likely |
| 235 // to loop multiple times before it is detected but at least it stops. | 233 // to loop multiple times before it is detected but at least it stops. |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 631 // zero then something must have previously run amuck through memory, | 629 // zero then something must have previously run amuck through memory, |
| 632 // writing beyond the allocated space and into unallocated space. | 630 // writing beyond the allocated space and into unallocated space. |
| 633 if (block->size != 0 || | 631 if (block->size != 0 || |
| 634 block->cookie != kBlockCookieFree || | 632 block->cookie != kBlockCookieFree || |
| 635 block->type_id.load(std::memory_order_relaxed) != 0 || | 633 block->type_id.load(std::memory_order_relaxed) != 0 || |
| 636 block->next.load(std::memory_order_relaxed) != 0) { | 634 block->next.load(std::memory_order_relaxed) != 0) { |
| 637 SetCorrupt(); | 635 SetCorrupt(); |
| 638 return kReferenceNull; | 636 return kReferenceNull; |
| 639 } | 637 } |
| 640 | 638 |
| 639 // Load information into the block header. There is no "release" of the |
| 640 // data here because this memory can, currently, be seen only by the thread |
| 641 // performing the allocation. When it comes time to share this, the thread |
| 642 // will call MakeIterable() which does the release operation. |
| 641 block->size = size; | 643 block->size = size; |
| 642 block->cookie = kBlockCookieAllocated; | 644 block->cookie = kBlockCookieAllocated; |
| 643 block->type_id.store(type_id, std::memory_order_relaxed); | 645 block->type_id.store(type_id, std::memory_order_relaxed); |
| 644 return freeptr; | 646 return freeptr; |
| 645 } | 647 } |
| 646 } | 648 } |
| 647 | 649 |
| 648 void PersistentMemoryAllocator::GetMemoryInfo(MemoryInfo* meminfo) const { | 650 void PersistentMemoryAllocator::GetMemoryInfo(MemoryInfo* meminfo) const { |
| 649 uint32_t remaining = std::max( | 651 uint32_t remaining = std::max( |
| 650 mem_size_ - shared_meta()->freeptr.load(std::memory_order_relaxed), | 652 mem_size_ - shared_meta()->freeptr.load(std::memory_order_relaxed), |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 | 925 |
| 924 // static | 926 // static |
| 925 bool FilePersistentMemoryAllocator::IsFileAcceptable( | 927 bool FilePersistentMemoryAllocator::IsFileAcceptable( |
| 926 const MemoryMappedFile& file, | 928 const MemoryMappedFile& file, |
| 927 bool read_only) { | 929 bool read_only) { |
| 928 return IsMemoryAcceptable(file.data(), file.length(), 0, read_only); | 930 return IsMemoryAcceptable(file.data(), file.length(), 0, read_only); |
| 929 } | 931 } |
| 930 #endif // !defined(OS_NACL) | 932 #endif // !defined(OS_NACL) |
| 931 | 933 |
| 932 } // namespace base | 934 } // namespace base |
| OLD | NEW |