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
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index d87640fa6d..75df12e 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -904,12 +904,21 @@
 // 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 @@
     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 @@
 // 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 @@
 // 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 @@
 // 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 @@
 
 // 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 @@
 
 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 @@
 // 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) {