Index: base/metrics/persistent_histogram_allocator.cc |
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc |
index 6006d31fbee70031acb901fb6a0f04a944f5ff04..ab957a69ec5e85c176749f1399f70e7e0e54f0fc 100644 |
--- a/base/metrics/persistent_histogram_allocator.cc |
+++ b/base/metrics/persistent_histogram_allocator.cc |
@@ -109,16 +109,26 @@ struct PersistentHistogramAllocator::PersistentHistogramData { |
char name[1]; |
}; |
+PersistentHistogramAllocator::Iterator::Iterator( |
+ PersistentHistogramAllocator* allocator) |
+ : allocator_(allocator), memory_iter_(allocator->memory_allocator()) {} |
+ |
+scoped_ptr<HistogramBase> |
+PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) { |
+ PersistentMemoryAllocator::Reference ref; |
Ilya Sherman
2016/03/24 02:03:58
nit: s/PersistentMemoryAllocator::Reference/Refere
bcwhite
2016/03/24 14:22:34
PHA::Reference is implemented as a PMA::Reference
|
+ while ((ref = memory_iter_.GetNextOfType(kTypeIdHistogram)) != 0) { |
+ if (ref != ignore) |
+ return allocator_->GetHistogram(ref); |
+ } |
+ return nullptr; |
+} |
+ |
PersistentHistogramAllocator::PersistentHistogramAllocator( |
scoped_ptr<PersistentMemoryAllocator> memory) |
: memory_allocator_(std::move(memory)) {} |
PersistentHistogramAllocator::~PersistentHistogramAllocator() {} |
-void PersistentHistogramAllocator::CreateIterator(Iterator* iter) { |
- memory_allocator_->CreateIterator(&iter->memory_iter); |
-} |
- |
void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) { |
memory_allocator_->CreateTrackingHistograms(name); |
} |
@@ -205,27 +215,23 @@ PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting() { |
// Before releasing the memory, it's necessary to have the Statistics- |
// Recorder forget about the histograms contained therein; otherwise, |
// some operations will try to access them and the released memory. |
- PersistentMemoryAllocator::Iterator iter; |
+ PersistentMemoryAllocator::Iterator iter(memory_allocator); |
PersistentMemoryAllocator::Reference ref; |
- uint32_t type_id; |
- memory_allocator->CreateIterator(&iter); |
- while ((ref = memory_allocator->GetNextIterable(&iter, &type_id)) != 0) { |
- if (type_id == kTypeIdHistogram) { |
- PersistentHistogramData* histogram_data = |
- memory_allocator->GetAsObject<PersistentHistogramData>( |
- ref, kTypeIdHistogram); |
- DCHECK(histogram_data); |
- StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); |
- |
- // If a test breaks here then a memory region containing a histogram |
- // actively used by this code is being released back to the test. |
- // If that memory segment were to be deleted, future calls to create |
- // persistent histograms would crash. To avoid this, have the test call |
- // the method GetCreateHistogramResultHistogram() *before* setting |
- // the (temporary) memory allocator via SetGlobalAllocator() so that |
- // histogram is instead allocated from the process heap. |
- DCHECK_NE(kResultHistogram, histogram_data->name); |
- } |
+ while ((ref = iter.GetNextOfType(kTypeIdHistogram)) != 0) { |
+ PersistentHistogramData* histogram_data = |
+ memory_allocator->GetAsObject<PersistentHistogramData>( |
+ ref, kTypeIdHistogram); |
+ DCHECK(histogram_data); |
+ StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); |
+ |
+ // If a test breaks here then a memory region containing a histogram |
+ // actively used by this code is being released back to the test. |
+ // If that memory segment were to be deleted, future calls to create |
+ // persistent histograms would crash. To avoid this, have the test call |
+ // the method GetCreateHistogramResultHistogram() *before* setting |
+ // the (temporary) memory allocator via SetGlobalAllocator() so that |
+ // histogram is instead allocated from the process heap. |
+ DCHECK_NE(kResultHistogram, histogram_data->name); |
} |
g_allocator = nullptr; |
@@ -413,21 +419,6 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram( |
return CreateHistogram(histogram_data); |
} |
-scoped_ptr<HistogramBase> |
-PersistentHistogramAllocator::GetNextHistogramWithIgnore(Iterator* iter, |
- Reference ignore) { |
- PersistentMemoryAllocator::Reference ref; |
- uint32_t type_id; |
- while ((ref = memory_allocator_->GetNextIterable(&iter->memory_iter, |
- &type_id)) != 0) { |
- if (ref == ignore) |
- continue; |
- if (type_id == kTypeIdHistogram) |
- return GetHistogram(ref); |
- } |
- return nullptr; |
-} |
- |
void PersistentHistogramAllocator::FinalizeHistogram(Reference ref, |
bool registered) { |
// If the created persistent histogram was registered then it needs to |
@@ -555,15 +546,17 @@ void PersistentHistogramAllocator::ImportGlobalHistograms() { |
static base::LazyInstance<base::Lock>::Leaky lock = LAZY_INSTANCE_INITIALIZER; |
if (g_allocator) { |
- // TODO(bcwhite): Investigate a lock-free, thread-safe iterator. |
+ // Even though the iterator is thread-safe, the rest of this code is not |
+ // and has to be protected by a lock. Otherwise, there is no guarantee |
+ // that multiple threads would process histograms in the same order |
+ // they get returned by the iterator. That is important because it |
+ // guarantees all processes will always have the same state. |
base::AutoLock auto_lock(lock.Get()); |
// Each call resumes from where it last left off so a persistant iterator |
// is needed. This class has a constructor so even the definition has to |
// be protected by the lock in order to be thread-safe. |
- static Iterator iter; |
- if (iter.is_clear()) |
- g_allocator->CreateIterator(&iter); |
+ static Iterator iter(g_allocator); |
// Skip the import if it's the histogram that was last created. Should a |
// race condition cause the "last created" to be overwritten before it |
@@ -576,7 +569,7 @@ void PersistentHistogramAllocator::ImportGlobalHistograms() { |
while (true) { |
scoped_ptr<HistogramBase> histogram = |
- g_allocator->GetNextHistogramWithIgnore(&iter, last_created); |
+ iter.GetNextWithIgnore(last_created); |
if (!histogram) |
break; |
StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |