Provide ShutdownProtobufLibrary() which frees all startup-allocated objects.
This commit is contained in:
parent
9824eda6b5
commit
63e646b7ad
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
@ -599,6 +602,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++) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 InitGeneratedPool() {
|
||||
GOOGLE_CHECK(generated_pool_ == NULL);
|
||||
generated_database_ = new EncodedDescriptorDatabase;
|
||||
generated_pool_ = new DescriptorPool(generated_database_);
|
||||
void DeleteGeneratedPool() {
|
||||
delete generated_database_;
|
||||
generated_database_ = NULL;
|
||||
delete generated_pool_;
|
||||
generated_pool_ = NULL;
|
||||
}
|
||||
|
||||
// Force InitGeneratedPool to be called at static init time, before any threads
|
||||
// can be created.
|
||||
struct Initializer {
|
||||
Initializer() {
|
||||
if (generated_pool_ == NULL) InitGeneratedPool();
|
||||
}
|
||||
} initializer;
|
||||
void InitGeneratedPool() {
|
||||
generated_database_ = new EncodedDescriptorDatabase;
|
||||
generated_pool_ = new DescriptorPool(generated_database_);
|
||||
internal::OnShutdown(&DeleteGeneratedPool);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 != !?
|
||||
|
@ -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(®istry_init_, &InitRegistry);
|
||||
|
||||
if (!InsertIfNotPresent(registry_, make_pair(containing_type, number),
|
||||
info)) {
|
||||
|
@ -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_;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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); }
|
||||
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user