aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google
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
parent9824eda6b558cd88c63064017593521ecad2029f (diff)
Provide ShutdownProtobufLibrary() which frees all startup-allocated objects.
Diffstat (limited to 'src/google')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc34
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc24
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h4
-rw-r--r--src/google/protobuf/descriptor.cc27
-rw-r--r--src/google/protobuf/descriptor.pb.cc40
-rw-r--r--src/google/protobuf/descriptor.pb.h19
-rw-r--r--src/google/protobuf/extension_set.cc13
-rw-r--r--src/google/protobuf/stubs/common.cc89
-rw-r--r--src/google/protobuf/stubs/common.h25
-rw-r--r--src/google/protobuf/testing/googletest.cc14
12 files changed, 254 insertions, 43 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index dcc48552..f056ed57 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -143,20 +143,23 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// Open namespace.
GenerateNamespaceOpeners(printer);
- // Forward-declare the AddDescriptors and AssignDescriptors functions, so
- // that we can declare them to be friends of each class.
+ // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
+ // functions, so that we can declare them to be friends of each class.
printer->Print(
"\n"
"// Internal implementation detail -- do not call these.\n"
"void $dllexport_decl$ $adddescriptorsname$();\n",
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
"dllexport_decl", dllexport_decl_);
+
printer->Print(
- // Note that we don't put dllexport_decl on this because it is only called
- // by the .pb.cc file in which it is defined.
+ // Note that we don't put dllexport_decl on these because they are only
+ // called by the .pb.cc file in which they are defined.
"void $assigndescriptorsname$();\n"
+ "void $shutdownfilename$();\n"
"\n",
- "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
+ "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
+ "shutdownfilename", GlobalShutdownFileName(file_->name()));
// Generate forward declarations of classes.
for (int i = 0; i < file_->message_type_count(); i++) {
@@ -390,6 +393,23 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// -----------------------------------------------------------------
+ // ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown.
+ printer->Print(
+ "\n"
+ "void $shutdownfilename$() {\n",
+ "shutdownfilename", GlobalShutdownFileName(file_->name()));
+ printer->Indent();
+
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateShutdownCode(printer);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+
+ // -----------------------------------------------------------------
+
// Now generate the AddDescriptors() function.
printer->Print(
"\n"
@@ -462,6 +482,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
message_generators_[i]->GenerateDefaultInstanceInitializer(printer);
}
+ printer->Print(
+ "::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n",
+ "shutdownfilename", GlobalShutdownFileName(file_->name()));
+
printer->Outdent();
printer->Print(
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 214daff9..070fde55 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -276,6 +276,11 @@ string GlobalAssignDescriptorsName(const string& filename) {
return "protobuf_AssignDesc_" + FilenameIdentifier(filename);
}
+// Return the name of the ShutdownFile() function for a given file.
+string GlobalShutdownFileName(const string& filename) {
+ return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 2260a934..55fd7e29 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -102,6 +102,9 @@ string GlobalAddDescriptorsName(const string& filename);
// Return the name of the AssignDescriptors() function for a given file.
string GlobalAssignDescriptorsName(const string& filename);
+// Return the name of the ShutdownFile() function for a given file.
+string GlobalShutdownFileName(const string& filename);
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index c5506699..95f20a60 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -421,17 +421,20 @@ GenerateClassDefinition(io::Printer* printer) {
.GeneratePrivateMembers(printer);
}
- // Declare AddDescriptors() and BuildDescriptors() as friends so that they
- // can assign private static variables like default_instance_ and reflection_.
+ // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
+ // friends so that they can access private static variables like
+ // default_instance_ and reflection_.
printer->Print(
"friend void $dllexport_decl$ $adddescriptorsname$();\n",
"dllexport_decl", dllexport_decl_,
"adddescriptorsname",
GlobalAddDescriptorsName(descriptor_->file()->name()));
printer->Print(
- "friend void $assigndescriptorsname$();\n",
+ "friend void $assigndescriptorsname$();\n"
+ "friend void $shutdownfilename$();\n",
"assigndescriptorsname",
- GlobalAssignDescriptorsName(descriptor_->file()->name()));
+ GlobalAssignDescriptorsName(descriptor_->file()->name()),
+ "shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name()));
// Generate offsets and _has_bits_ boilerplate.
if (descriptor_->field_count() > 0) {
@@ -600,6 +603,19 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
}
void MessageGenerator::
+GenerateShutdownCode(io::Printer* printer) {
+ printer->Print(
+ "delete $classname$::default_instance_;\n"
+ "delete $classname$_reflection_;\n",
+ "classname", classname_);
+
+ // Handle nested types.
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ nested_generators_[i]->GenerateShutdownCode(printer);
+ }
+}
+
+void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
enum_generators_[i]->GenerateMethods(printer);
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 31aa1c4c..105574a7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -98,6 +98,10 @@ class MessageGenerator {
// allocated before any can be initialized.
void GenerateDefaultInstanceInitializer(io::Printer* printer);
+ // Generates code that should be run when ShutdownProtobufLibrary() is called,
+ // to delete all dynamically-allocated objects.
+ void GenerateShutdownCode(io::Printer* printer);
+
// Generate all non-inline methods for this class.
void GenerateClassMethods(io::Printer* printer);
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index ecca3293..dd7f28c8 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -47,6 +47,7 @@
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#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 <google/protobuf/stubs/map-util.h>
@@ -797,30 +798,34 @@ namespace {
EncodedDescriptorDatabase* generated_database_ = NULL;
DescriptorPool* generated_pool_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_);
+
+void DeleteGeneratedPool() {
+ delete generated_database_;
+ generated_database_ = NULL;
+ delete generated_pool_;
+ generated_pool_ = NULL;
+}
void InitGeneratedPool() {
- GOOGLE_CHECK(generated_pool_ == NULL);
generated_database_ = new EncodedDescriptorDatabase;
generated_pool_ = new DescriptorPool(generated_database_);
+ internal::OnShutdown(&DeleteGeneratedPool);
}
-// Force InitGeneratedPool to be called at static init time, before any threads
-// can be created.
-struct Initializer {
- Initializer() {
- if (generated_pool_ == NULL) InitGeneratedPool();
- }
-} initializer;
+inline void InitGeneratedPoolOnce() {
+ GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool);
+}
} // anonymous namespace
const DescriptorPool* DescriptorPool::generated_pool() {
- if (generated_pool_ == NULL) InitGeneratedPool();
+ InitGeneratedPoolOnce();
return generated_pool_;
}
DescriptorPool* DescriptorPool::internal_generated_pool() {
- if (generated_pool_ == NULL) InitGeneratedPool();
+ InitGeneratedPoolOnce();
return generated_pool_;
}
@@ -848,7 +853,7 @@ void DescriptorPool::InternalAddGeneratedFile(
// Therefore, when we parse one, we have to be very careful to avoid using
// any descriptor-based operations, since this might cause infinite recursion
// or deadlock.
- if (generated_pool_ == NULL) InitGeneratedPool();
+ InitGeneratedPoolOnce();
GOOGLE_CHECK(generated_database_->Add(encoded_file_descriptor, size));
}
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 6f0b5b54..d4a7666b 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -451,6 +451,45 @@ void protobuf_RegisterTypes() {
} // namespace
+void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto() {
+ delete FileDescriptorSet::default_instance_;
+ delete FileDescriptorSet_reflection_;
+ delete FileDescriptorProto::default_instance_;
+ delete FileDescriptorProto_reflection_;
+ delete DescriptorProto::default_instance_;
+ delete DescriptorProto_reflection_;
+ delete DescriptorProto_ExtensionRange::default_instance_;
+ delete DescriptorProto_ExtensionRange_reflection_;
+ delete FieldDescriptorProto::default_instance_;
+ delete FieldDescriptorProto_reflection_;
+ delete EnumDescriptorProto::default_instance_;
+ delete EnumDescriptorProto_reflection_;
+ delete EnumValueDescriptorProto::default_instance_;
+ delete EnumValueDescriptorProto_reflection_;
+ delete ServiceDescriptorProto::default_instance_;
+ delete ServiceDescriptorProto_reflection_;
+ delete MethodDescriptorProto::default_instance_;
+ delete MethodDescriptorProto_reflection_;
+ delete FileOptions::default_instance_;
+ delete FileOptions_reflection_;
+ delete MessageOptions::default_instance_;
+ delete MessageOptions_reflection_;
+ delete FieldOptions::default_instance_;
+ delete FieldOptions_reflection_;
+ delete EnumOptions::default_instance_;
+ delete EnumOptions_reflection_;
+ delete EnumValueOptions::default_instance_;
+ delete EnumValueOptions_reflection_;
+ delete ServiceOptions::default_instance_;
+ delete ServiceOptions_reflection_;
+ delete MethodOptions::default_instance_;
+ delete MethodOptions_reflection_;
+ delete UninterpretedOption::default_instance_;
+ delete UninterpretedOption_reflection_;
+ delete UninterpretedOption_NamePart::default_instance_;
+ delete UninterpretedOption_NamePart_reflection_;
+}
+
void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
static bool already_here = false;
if (already_here) return;
@@ -584,6 +623,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
MethodOptions::default_instance_->InitAsDefaultInstance();
UninterpretedOption::default_instance_->InitAsDefaultInstance();
UninterpretedOption_NamePart::default_instance_->InitAsDefaultInstance();
+ ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto);
}
// Force AddDescriptors() to be called at static initialization time.
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 7512e407..7247bfd6 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -28,6 +28,7 @@ namespace protobuf {
// Internal implementation detail -- do not call these.
void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
class FileDescriptorSet;
class FileDescriptorProto;
@@ -210,6 +211,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -381,6 +383,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
::google::protobuf::FileOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -475,6 +478,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
::google::protobuf::int32 end_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -630,6 +634,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
::google::protobuf::MessageOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -849,6 +854,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
::google::protobuf::FieldOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -958,6 +964,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
::google::protobuf::EnumOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1064,6 +1071,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
::google::protobuf::EnumValueOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1173,6 +1181,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
::google::protobuf::ServiceOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1295,6 +1304,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
::google::protobuf::MethodOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1448,6 +1458,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1547,6 +1558,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1696,6 +1708,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1787,6 +1800,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1878,6 +1892,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -1969,6 +1984,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -2060,6 +2076,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -2158,6 +2175,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
bool is_extension_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@@ -2297,6 +2315,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
static const ::std::string _default_string_value_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(6 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 0e618902..f45eafa5 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -78,11 +78,22 @@ struct ExtensionInfo {
typedef hash_map<pair<const Message*, int>, ExtensionInfo> ExtensionRegistry;
ExtensionRegistry* registry_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(registry_init_);
+
+void DeleteRegistry() {
+ delete registry_;
+ registry_ = NULL;
+}
+
+void InitRegistry() {
+ registry_ = new ExtensionRegistry;
+ internal::OnShutdown(&DeleteRegistry);
+}
// This function is only called at startup, so there is no need for thread-
// safety.
void Register(const Message* containing_type, int number, ExtensionInfo info) {
- if (registry_ == NULL) registry_ = new ExtensionRegistry;
+ GoogleOnceInit(&registry_init_, &InitRegistry);
if (!InsertIfNotPresent(registry_, make_pair(containing_type, number),
info)) {
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
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
index 99dbbb32..1339b332 100644
--- a/src/google/protobuf/testing/googletest.cc
+++ b/src/google/protobuf/testing/googletest.cc
@@ -233,5 +233,19 @@ void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename,
}
}
+namespace {
+
+// Force shutdown at process exit so that we can test for memory leaks. To
+// actually check for leaks, I suggest using the heap checker included with
+// google-perftools. Set it to "draconian" mode to ensure that every last
+// call to malloc() has a corresponding free().
+struct ForceShutdown {
+ ~ForceShutdown() {
+ ShutdownProtobufLibrary();
+ }
+} force_shutdown;
+
+} // namespace
+
} // namespace protobuf
} // namespace google