summaryrefslogtreecommitdiffstats
path: root/base/metrics
diff options
context:
space:
mode:
authormad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-23 14:40:10 +0000
committermad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-23 14:40:10 +0000
commitd144255434dd27109c30c4e7a8124d76d7e83a4b (patch)
tree2d3c9768230161683305bbac9cae4d60cb3b6a06 /base/metrics
parent6d5e8255ed5b7e8865fd20af2530953990376f9f (diff)
downloadchromium_src-d144255434dd27109c30c4e7a8124d76d7e83a4b.zip
chromium_src-d144255434dd27109c30c4e7a8124d76d7e83a4b.tar.gz
chromium_src-d144255434dd27109c30c4e7a8124d76d7e83a4b.tar.bz2
Properly lock access to static variables.
There were a few race conditions where the static method would test the validity of the hitograms_ static variable before attempting to use the lock_ to protect access to it but nothing then prevented the destructor to free both the lock_ and the hitograms_ memory. So I decided to not use a dynamic allocation of the static lock_ to resolve this problem. BUG=38354 TEST=Hard to repro exit scenario crashes. Review URL: http://codereview.chromium.org/5784005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70054 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/metrics')
-rw-r--r--base/metrics/histogram.cc51
-rw-r--r--base/metrics/histogram.h2
2 files changed, 40 insertions, 13 deletions
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index d87640f..75df12e 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -904,12 +904,21 @@ double CustomHistogram::GetBucketSize(Count current, size_t i) const {
// provide support for all future calls.
StatisticsRecorder::StatisticsRecorder() {
DCHECK(!histograms_);
- lock_ = new Lock;
+ if (lock_ == NULL) {
+ // This will leak on purpose. It's the only way to make sure we won't race
+ // against the static uninitialization of the module while one of our
+ // static methods relying on the lock get called at an inappropriate time
+ // during the termination phase. Since it's a static data member, we will
+ // leak one per process, which would be similar to the instance allocated
+ // during static initialization and released only on process termination.
+ lock_ = new Lock;
+ }
+ AutoLock auto_lock(*lock_);
histograms_ = new HistogramMap;
}
StatisticsRecorder::~StatisticsRecorder() {
- DCHECK(histograms_);
+ DCHECK(histograms_ && lock_);
if (dump_on_exit_) {
std::string output;
@@ -917,14 +926,22 @@ StatisticsRecorder::~StatisticsRecorder() {
LOG(INFO) << output;
}
// Clean up.
- delete histograms_;
- histograms_ = NULL;
- delete lock_;
- lock_ = NULL;
+ HistogramMap* histograms = NULL;
+ {
+ AutoLock auto_lock(*lock_);
+ histograms = histograms_;
+ histograms_ = NULL;
+ }
+ delete histograms;
+ // We don't delete lock_ on purpose to avoid having to properly protect
+ // against it going away after we checked for NULL in the static methods.
}
// static
-bool StatisticsRecorder::WasStarted() {
+bool StatisticsRecorder::IsActive() {
+ if (lock_ == NULL)
+ return false;
+ AutoLock auto_lock(*lock_);
return NULL != histograms_;
}
@@ -935,10 +952,12 @@ bool StatisticsRecorder::WasStarted() {
// destroyed before assignment (when value was returned by new).
// static
void StatisticsRecorder::Register(Histogram* histogram) {
+ if (lock_ == NULL)
+ return;
+ AutoLock auto_lock(*lock_);
if (!histograms_)
return;
const std::string name = histogram->histogram_name();
- AutoLock auto_lock(*lock_);
// Avoid overwriting a previous registration.
if (histograms_->end() == histograms_->find(name))
(*histograms_)[name] = histogram;
@@ -947,7 +966,7 @@ void StatisticsRecorder::Register(Histogram* histogram) {
// static
void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
std::string* output) {
- if (!histograms_)
+ if (!IsActive())
return;
output->append("<html><head><title>About Histograms");
if (!query.empty())
@@ -971,7 +990,7 @@ void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
// static
void StatisticsRecorder::WriteGraph(const std::string& query,
std::string* output) {
- if (!histograms_)
+ if (!IsActive())
return;
if (query.length())
StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
@@ -990,9 +1009,11 @@ void StatisticsRecorder::WriteGraph(const std::string& query,
// static
void StatisticsRecorder::GetHistograms(Histograms* output) {
- if (!histograms_)
+ if (lock_ == NULL)
return;
AutoLock auto_lock(*lock_);
+ if (!histograms_)
+ return;
for (HistogramMap::iterator it = histograms_->begin();
histograms_->end() != it;
++it) {
@@ -1003,9 +1024,11 @@ void StatisticsRecorder::GetHistograms(Histograms* output) {
bool StatisticsRecorder::FindHistogram(const std::string& name,
scoped_refptr<Histogram>* histogram) {
- if (!histograms_)
+ if (lock_ == NULL)
return false;
AutoLock auto_lock(*lock_);
+ if (!histograms_)
+ return false;
HistogramMap::iterator it = histograms_->find(name);
if (histograms_->end() == it)
return false;
@@ -1016,7 +1039,11 @@ bool StatisticsRecorder::FindHistogram(const std::string& name,
// private static
void StatisticsRecorder::GetSnapshot(const std::string& query,
Histograms* snapshot) {
+ if (lock_ == NULL)
+ return;
AutoLock auto_lock(*lock_);
+ if (!histograms_)
+ return;
for (HistogramMap::iterator it = histograms_->begin();
histograms_->end() != it;
++it) {
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 562f252..6b09aa3 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -643,7 +643,7 @@ class StatisticsRecorder {
~StatisticsRecorder();
// Find out if histograms can now be registered into our list.
- static bool WasStarted();
+ static bool IsActive();
// Register, or add a new histogram to the collection of statistics.
static void Register(Histogram* histogram);