aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-18 01:24:27 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-18 01:24:27 +0000
commit6dcd46c8d21708451bc2f25128816037f8129ceb (patch)
tree9ad172f53948babae0e20d96b4aeba4aed2a0fc3
parentcfa2d8aa87cc0b22b5092a5fb3bf7e394f85cbf1 (diff)
Fix initialization ordering problem in logging code. Based on patch from Wink Saville.
-rw-r--r--CONTRIBUTORS.txt2
-rw-r--r--src/google/protobuf/stubs/common.cc28
2 files changed, 26 insertions, 4 deletions
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 0ad37d93..b01fed62 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -63,3 +63,5 @@ Patch contributors:
* Fixed warnings about generated constructors not explicitly initializing
all fields (only present with certain compiler settings).
* Added generation of field number constants.
+ Wink Saville <wink@google.com>
+ * Fixed initialization ordering problem in logging code.
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
index 54f31ba4..385ea8ae 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -113,7 +113,27 @@ void NullLogHandler(LogLevel level, const char* filename, int line,
static LogHandler* log_handler_ = &DefaultLogHandler;
static int log_silencer_count_ = 0;
-static Mutex log_silencer_count_mutex_;
+
+// Mutex which protects log_silencer_count_. We provide a static function to
+// get it so that it is initialized on first use, which be during
+// initialization time. If we just allocated it as a global variable, it might
+// not be initialized before someone tries to use it.
+static Mutex* LogSilencerMutex() {
+ static Mutex* log_silencer_count_mutex_ = new Mutex;
+ return log_silencer_count_mutex_;
+}
+
+// Forces the above mutex to be initialized during startup. This way we don't
+// have to worry about the initialization itself being thread-safe, since no
+// threads should exist yet at startup time. (Otherwise we'd have no way to
+// make things thread-safe here because we'd need a Mutex for that, and we'd
+// have no way to construct one safely!)
+static struct LogSilencerMutexInitializer {
+ LogSilencerMutexInitializer() {
+ LogSilencerMutex();
+ }
+} log_silencer_mutex_initializer;
+
static string SimpleCtoa(char c) { return string(1, c); }
@@ -140,7 +160,7 @@ void LogMessage::Finish() {
bool suppress = false;
if (level_ != LOGLEVEL_FATAL) {
- MutexLock lock(&internal::log_silencer_count_mutex_);
+ MutexLock lock(internal::LogSilencerMutex());
suppress = internal::log_silencer_count_ > 0;
}
@@ -173,12 +193,12 @@ LogHandler* SetLogHandler(LogHandler* new_func) {
}
LogSilencer::LogSilencer() {
- MutexLock lock(&internal::log_silencer_count_mutex_);
+ MutexLock lock(internal::LogSilencerMutex());
++internal::log_silencer_count_;
};
LogSilencer::~LogSilencer() {
- MutexLock lock(&internal::log_silencer_count_mutex_);
+ MutexLock lock(internal::LogSilencerMutex());
--internal::log_silencer_count_;
};