aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/stubs
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-05-06 19:27:03 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-05-06 19:27:03 +0000
commit63e646b7ad6f18228c1807f8d18111ae96e86aa7 (patch)
treefc524e6f55b32b7d786bd41623402394a2f1af26 /src/google/protobuf/stubs
parent9824eda6b558cd88c63064017593521ecad2029f (diff)
Provide ShutdownProtobufLibrary() which frees all startup-allocated objects.
Diffstat (limited to 'src/google/protobuf/stubs')
-rw-r--r--src/google/protobuf/stubs/common.cc89
-rw-r--r--src/google/protobuf/stubs/common.h25
2 files changed, 92 insertions, 22 deletions
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 <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <stdio.h>
#include <errno.h>
+#include <vector>
#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<void (*)()>* shutdown_functions = NULL;
+Mutex* shutdown_functions_mutex = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(shutdown_functions_init);
+
+void InitShutdownFunctions() {
+ shutdown_functions = new vector<void (*)()>;
+ 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
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index 4a55e004..3367d4ce 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -1085,6 +1085,31 @@ LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
} // namespace internal
+// ===================================================================
+// Shutdown support.
+
+// Shut down the entire protocol buffers library, deleting all static-duration
+// objects allocated by the library or by generated .pb.cc files.
+//
+// There are two reasons you might want to call this:
+// * You use a draconian definition of "memory leak" in which you expect
+// every single malloc() to have a corresponding free(), even for objects
+// which live until program exit.
+// * You are writing a dynamically-loaded library which needs to clean up
+// after itself when the library is unloaded.
+//
+// It is safe to call this multiple times. However, it is not safe to use
+// any other part of the protocol buffers library after
+// ShutdownProtobufLibrary() has been called.
+LIBPROTOBUF_EXPORT void ShutdownProtobufLibrary();
+
+namespace internal {
+
+// Register a function to be called when ShutdownProtocolBuffers() is called.
+LIBPROTOBUF_EXPORT void OnShutdown(void (*func)());
+
+} // namespace internal
+
} // namespace protobuf
} // namespace google