From 63e646b7ad6f18228c1807f8d18111ae96e86aa7 Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Wed, 6 May 2009 19:27:03 +0000 Subject: Provide ShutdownProtobufLibrary() which frees all startup-allocated objects. --- src/google/protobuf/stubs/common.cc | 89 ++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 22 deletions(-) (limited to 'src/google/protobuf/stubs/common.cc') diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc index 385ea8ae..da73c566 100644 --- a/src/google/protobuf/stubs/common.cc +++ b/src/google/protobuf/stubs/common.cc @@ -31,10 +31,12 @@ // Author: kenton@google.com (Kenton Varda) #include +#include #include #include #include #include +#include #include "config.h" @@ -114,26 +116,20 @@ void NullLogHandler(LogLevel level, const char* filename, int line, static LogHandler* log_handler_ = &DefaultLogHandler; static int log_silencer_count_ = 0; -// 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 Mutex* log_silencer_count_mutex_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(log_silencer_count_init_); +void DeleteLogSilencerCount() { + delete log_silencer_count_mutex_; + log_silencer_count_mutex_ = NULL; +} +void InitLogSilencerCount() { + log_silencer_count_mutex_ = new Mutex; + OnShutdown(&DeleteLogSilencerCount); +} +void InitLogSilencerCountOnce() { + GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount); +} static string SimpleCtoa(char c) { return string(1, c); } @@ -160,7 +156,8 @@ void LogMessage::Finish() { bool suppress = false; if (level_ != LOGLEVEL_FATAL) { - MutexLock lock(internal::LogSilencerMutex()); + InitLogSilencerCountOnce(); + MutexLock lock(log_silencer_count_mutex_); suppress = internal::log_silencer_count_ > 0; } @@ -193,12 +190,14 @@ LogHandler* SetLogHandler(LogHandler* new_func) { } LogSilencer::LogSilencer() { - MutexLock lock(internal::LogSilencerMutex()); + internal::InitLogSilencerCountOnce(); + MutexLock lock(internal::log_silencer_count_mutex_); ++internal::log_silencer_count_; }; LogSilencer::~LogSilencer() { - MutexLock lock(internal::LogSilencerMutex()); + internal::InitLogSilencerCountOnce(); + MutexLock lock(internal::log_silencer_count_mutex_); --internal::log_silencer_count_; }; @@ -291,5 +290,51 @@ void Mutex::AssertHeld() { #endif +// =================================================================== +// Shutdown support. + +namespace internal { + +typedef void OnShutdownFunc(); +vector* shutdown_functions = NULL; +Mutex* shutdown_functions_mutex = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(shutdown_functions_init); + +void InitShutdownFunctions() { + shutdown_functions = new vector; + shutdown_functions_mutex = new Mutex; +} + +inline void InitShutdownFunctionsOnce() { + GoogleOnceInit(&shutdown_functions_init, &InitShutdownFunctions); +} + +void OnShutdown(void (*func)()) { + InitShutdownFunctionsOnce(); + MutexLock lock(shutdown_functions_mutex); + shutdown_functions->push_back(func); +} + +} // namespace internal + +void ShutdownProtobufLibrary() { + internal::InitShutdownFunctionsOnce(); + + // We don't need to lock shutdown_functions_mutex because it's up to the + // caller to make sure that no one is using the library before this is + // called. + + // Make it safe to call this multiple times. + if (internal::shutdown_functions == NULL) return; + + for (int i = 0; i < internal::shutdown_functions->size(); i++) { + internal::shutdown_functions->at(i)(); + } + delete internal::shutdown_functions; + internal::shutdown_functions = NULL; + delete internal::shutdown_functions_mutex; + internal::shutdown_functions_mutex = NULL; +} + } // namespace protobuf } // namespace google -- cgit v1.2.3