// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. #include #include #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP // We're only using this as a standard way for getting the thread id. // We're not using any thread functionality. #include // NOLINT #endif // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP #include #include #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace internal { void DestroyMessage(const void* message) { static_cast(message)->~MessageLite(); } void DestroyString(const void* s) { static_cast(s)->~basic_string(); } PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EmptyString fixed_address_empty_string; // NOLINT PROTOBUF_CONSTINIT std::atomic init_protobuf_defaults_state{false}; static bool InitProtobufDefaultsImpl() { ::new (static_cast(&fixed_address_empty_string.value)) std::string(); OnShutdownDestroyString(&fixed_address_empty_string.value); // Verify that we can indeed get the address during constant evaluation. PROTOBUF_CONSTINIT static const std::string& fixed_address_empty_string_test = GetEmptyStringAlreadyInited(); (void)fixed_address_empty_string_test; init_protobuf_defaults_state.store(true, std::memory_order_release); return true; } void InitProtobufDefaultsSlow() { static bool is_inited = InitProtobufDefaultsImpl(); (void)is_inited; } size_t StringSpaceUsedExcludingSelfLong(const std::string& str) { const void* start = &str; const void* end = &str + 1; if (start <= str.data() && str.data() < end) { // The string's data is stored inside the string object itself. return 0; } else { return str.capacity(); } } template const T& Get(const void* ptr) { return *static_cast(ptr); } // PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite. // WireFormatLite has a very inconvenient interface with respect to template // meta-programming. This class wraps the different named functions into // a single Serialize / SerializeToArray interface. template struct PrimitiveTypeHelper; template <> struct PrimitiveTypeHelper { typedef bool Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteBoolNoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteBoolNoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int32 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteInt32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int32 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteSInt32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteSInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint32 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteUInt32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteUInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int64 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteInt64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int64 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteSInt64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteSInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint64 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteUInt64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteUInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint32 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteFixed32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteFixed32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint64 Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteFixed64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteFixed64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper {}; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef int32 Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef int64 Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef float Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef double Type; }; template <> struct PrimitiveTypeHelper { typedef std::string Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { const Type& value = *static_cast(ptr); output->WriteVarint32(value.size()); output->WriteRawMaybeAliased(value.data(), value.size()); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { const Type& value = *static_cast(ptr); return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer); } }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper {}; // We want to serialize to both CodedOutputStream and directly into byte arrays // without duplicating the code. In fact we might want extra output channels in // the future. template struct OutputHelper; template void SerializeTo(const void* ptr, O* output) { OutputHelper::Serialize(ptr, output); } template void WriteTagTo(uint32 tag, O* output) { SerializeTo(&tag, output); } template void WriteLengthTo(uint32 length, O* output) { SerializeTo(&length, output); } // Specialization for coded output stream template struct OutputHelper { static void Serialize(const void* ptr, io::CodedOutputStream* output) { PrimitiveTypeHelper::Serialize(ptr, output); } }; // Specialization for writing into a plain array struct ArrayOutput { uint8* ptr; bool is_deterministic; }; template struct OutputHelper { static void Serialize(const void* ptr, ArrayOutput* output) { output->ptr = PrimitiveTypeHelper::SerializeToArray(ptr, output->ptr); } }; void SerializeMessageNoTable(const MessageLite* msg, io::CodedOutputStream* output) { msg->SerializeWithCachedSizes(output); } void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) { io::ArrayOutputStream array_stream(output->ptr, INT_MAX); io::CodedOutputStream o(&array_stream); o.SetSerializationDeterministic(output->is_deterministic); msg->SerializeWithCachedSizes(&o); output->ptr += o.ByteCount(); } // Helper to branch to fast path if possible void SerializeMessageDispatch(const MessageLite& msg, const FieldMetadata* field_table, int num_fields, int32 cached_size, io::CodedOutputStream* output) { const uint8* base = reinterpret_cast(&msg); SerializeInternal(base, field_table, num_fields, output); } // Helper to branch to fast path if possible void SerializeMessageDispatch(const MessageLite& msg, const FieldMetadata* field_table, int num_fields, int32 cached_size, ArrayOutput* output) { const uint8* base = reinterpret_cast(&msg); output->ptr = SerializeInternalToArray(base, field_table, num_fields, output->is_deterministic, output->ptr); } // Serializing messages is special as it's not a primitive type and needs an // explicit overload for each output type. template void SerializeMessageTo(const MessageLite* msg, const void* table_ptr, O* output) { const SerializationTable* table = static_cast(table_ptr); if (!table) { // Proto1 WriteLengthTo(msg->GetCachedSize(), output); SerializeMessageNoTable(msg, output); return; } const FieldMetadata* field_table = table->field_table; const uint8* base = reinterpret_cast(msg); int cached_size = *reinterpret_cast(base + field_table->offset); WriteLengthTo(cached_size, output); int num_fields = table->num_fields - 1; SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size, output); } // Almost the same as above only it doesn't output the length field. template void SerializeGroupTo(const MessageLite* msg, const void* table_ptr, O* output) { const SerializationTable* table = static_cast(table_ptr); if (!table) { // Proto1 SerializeMessageNoTable(msg, output); return; } const FieldMetadata* field_table = table->field_table; const uint8* base = reinterpret_cast(msg); int cached_size = *reinterpret_cast(base + field_table->offset); int num_fields = table->num_fields - 1; SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size, output); } template struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeTo(field, output); } }; template <> struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeTo(&Get(field).Get(), output); } }; template <> struct SingularFieldHelper : SingularFieldHelper {}; template <> struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeGroupTo(Get(field), static_cast(md.ptr), output); WriteTagTo(md.tag + 1, output); } }; template <> struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeMessageTo(Get(field), static_cast(md.ptr), output); } }; template struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { typedef typename PrimitiveTypeHelper::Type T; const RepeatedField& array = Get >(field); for (int i = 0; i < array.size(); i++) { WriteTagTo(md.tag, output); SerializeTo(&array[i], output); } } }; // We need to use a helper class to get access to the private members class AccessorHelper { public: static int Size(const RepeatedPtrFieldBase& x) { return x.size(); } static void const* Get(const RepeatedPtrFieldBase& x, int idx) { return x.raw_data()[idx]; } }; template <> struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { const internal::RepeatedPtrFieldBase& array = Get(field); for (int i = 0; i < AccessorHelper::Size(array); i++) { WriteTagTo(md.tag, output); SerializeTo(AccessorHelper::Get(array, i), output); } } }; template <> struct RepeatedFieldHelper : RepeatedFieldHelper {}; template <> struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { const internal::RepeatedPtrFieldBase& array = Get(field); for (int i = 0; i < AccessorHelper::Size(array); i++) { WriteTagTo(md.tag, output); SerializeGroupTo( static_cast(AccessorHelper::Get(array, i)), static_cast(md.ptr), output); WriteTagTo(md.tag + 1, output); } } }; template <> struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { const internal::RepeatedPtrFieldBase& array = Get(field); for (int i = 0; i < AccessorHelper::Size(array); i++) { WriteTagTo(md.tag, output); SerializeMessageTo( static_cast(AccessorHelper::Get(array, i)), md.ptr, output); } } }; template struct PackedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { typedef typename PrimitiveTypeHelper::Type T; const RepeatedField& array = Get >(field); if (array.empty()) return; WriteTagTo(md.tag, output); int cached_size = Get(static_cast(field) + sizeof(RepeatedField)); WriteLengthTo(cached_size, output); for (int i = 0; i < array.size(); i++) { SerializeTo(&array[i], output); } } }; template <> struct PackedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type " << md.type; } }; template <> struct PackedFieldHelper : PackedFieldHelper {}; template <> struct PackedFieldHelper : PackedFieldHelper {}; template <> struct PackedFieldHelper : PackedFieldHelper {}; template struct OneOfFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { SingularFieldHelper::Serialize(field, md, output); } }; void SerializeNotImplemented(int field) { GOOGLE_LOG(FATAL) << "Not implemented field number " << field; } // When switching to c++11 we should make these constexpr functions #define SERIALIZE_TABLE_OP(type, type_class) \ ((type - 1) + static_cast(type_class) * FieldMetadata::kNumTypes) int FieldMetadata::CalculateType(int type, FieldMetadata::FieldTypeClass type_class) { return SERIALIZE_TABLE_OP(type, type_class); } template bool IsNull(const void* ptr) { return *static_cast::Type*>(ptr) == 0; } template <> bool IsNull(const void* ptr) { return static_cast(ptr)->Get().size() == 0; } template <> bool IsNull(const void* ptr) { return static_cast(ptr)->Get().size() == 0; } template <> bool IsNull(const void* ptr) { return Get(ptr) == NULL; } template <> bool IsNull(const void* ptr) { return Get(ptr) == NULL; } #define SERIALIZERS_FOR_TYPE(type) \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence): \ if (!IsPresent(base, field_metadata.has_offset)) continue; \ SingularFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kNoPresence): \ if (IsNull(ptr)) continue; \ SingularFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kRepeated): \ RepeatedFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kPacked): \ PackedFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kOneOf): \ if (!IsOneofPresent(base, field_metadata.has_offset, field_metadata.tag)) \ continue; \ OneOfFieldHelper::Serialize(ptr, field_metadata, output); \ break void SerializeInternal(const uint8* base, const FieldMetadata* field_metadata_table, int32 num_fields, io::CodedOutputStream* output) { SpecialSerializer func = nullptr; for (int i = 0; i < num_fields; i++) { const FieldMetadata& field_metadata = field_metadata_table[i]; const uint8* ptr = base + field_metadata.offset; switch (field_metadata.type) { SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64); // Special cases case FieldMetadata::kSpecial: func = reinterpret_cast( const_cast(field_metadata.ptr)); func(base, field_metadata.offset, field_metadata.tag, field_metadata.has_offset, output); break; default: // __builtin_unreachable() SerializeNotImplemented(field_metadata.type); } } } uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* field_metadata_table, int32 num_fields, bool is_deterministic, uint8* buffer) { ArrayOutput array_output = {buffer, is_deterministic}; ArrayOutput* output = &array_output; SpecialSerializer func = nullptr; for (int i = 0; i < num_fields; i++) { const FieldMetadata& field_metadata = field_metadata_table[i]; const uint8* ptr = base + field_metadata.offset; switch (field_metadata.type) { SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64); // Special cases case FieldMetadata::kSpecial: { io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX); io::CodedOutputStream output(&array_stream); output.SetSerializationDeterministic(is_deterministic); func = reinterpret_cast( const_cast(field_metadata.ptr)); func(base, field_metadata.offset, field_metadata.tag, field_metadata.has_offset, &output); array_output.ptr += output.ByteCount(); } break; default: // __builtin_unreachable() SerializeNotImplemented(field_metadata.type); } } return array_output.ptr; } #undef SERIALIZERS_FOR_TYPE void ExtensionSerializer(const uint8* ptr, uint32 offset, uint32 tag, uint32 has_offset, io::CodedOutputStream* output) { reinterpret_cast(ptr + offset) ->SerializeWithCachedSizes(tag, has_offset, output); } void UnknownFieldSerializerLite(const uint8* ptr, uint32 offset, uint32 tag, uint32 has_offset, io::CodedOutputStream* output) { output->WriteString( reinterpret_cast(ptr + offset) ->unknown_fields(&internal::GetEmptyString)); } MessageLite* DuplicateIfNonNullInternal(MessageLite* message) { if (message) { MessageLite* ret = message->New(); ret->CheckTypeAndMergeFrom(*message); return ret; } else { return NULL; } } void GenericSwap(MessageLite* m1, MessageLite* m2) { std::unique_ptr tmp(m1->New()); tmp->CheckTypeAndMergeFrom(*m1); m1->Clear(); m1->CheckTypeAndMergeFrom(*m2); m2->Clear(); m2->CheckTypeAndMergeFrom(*tmp); } // Returns a message owned by this Arena. This may require Own()ing or // duplicating the message. MessageLite* GetOwnedMessageInternal(Arena* message_arena, MessageLite* submessage, Arena* submessage_arena) { GOOGLE_DCHECK(submessage->GetArena() == submessage_arena); GOOGLE_DCHECK(message_arena != submessage_arena); if (message_arena != NULL && submessage_arena == NULL) { message_arena->Own(submessage); return submessage; } else { MessageLite* ret = submessage->New(message_arena); ret->CheckTypeAndMergeFrom(*submessage); return ret; } } namespace { void InitSCC_DFS(SCCInfoBase* scc) { if (scc->visit_status.load(std::memory_order_relaxed) != SCCInfoBase::kUninitialized) return; scc->visit_status.store(SCCInfoBase::kRunning, std::memory_order_relaxed); // Each base is followed by an array of void*, containing first pointers to // SCCInfoBase and then pointers-to-pointers to SCCInfoBase. auto deps = reinterpret_cast(scc + 1); auto strong_deps = reinterpret_cast(deps); for (int i = 0; i < scc->num_deps; ++i) { if (strong_deps[i]) InitSCC_DFS(strong_deps[i]); } auto implicit_weak_deps = reinterpret_cast(deps + scc->num_deps); for (int i = 0; i < scc->num_implicit_weak_deps; ++i) { if (*implicit_weak_deps[i]) { InitSCC_DFS(*implicit_weak_deps[i]); } } scc->init_func(); // Mark done (note we use memory order release here), other threads could // now see this as initialized and thus the initialization must have happened // before. scc->visit_status.store(SCCInfoBase::kInitialized, std::memory_order_release); } } // namespace void InitSCCImpl(SCCInfoBase* scc) { static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED}; // Either the default in case no initialization is running or the id of the // thread that is currently initializing. #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP static std::atomic runner; auto me = std::this_thread::get_id(); #else // This is a lightweight replacement for std::thread::id. std::thread does not // work on Windows XP SP2 with the latest VC++ libraries, because it utilizes // the Concurrency Runtime that is only supported on Windows XP SP3 and above. static std::atomic_llong runner(-1); auto me = ::GetCurrentThreadId(); #endif // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP // This will only happen because the constructor will call InitSCC while // constructing the default instance. if (runner.load(std::memory_order_relaxed) == me) { // Because we're in the process of constructing the default instance. // We can be assured that we're already exploring this SCC. GOOGLE_CHECK_EQ(scc->visit_status.load(std::memory_order_relaxed), SCCInfoBase::kRunning); return; } InitProtobufDefaults(); mu.Lock(); runner.store(me, std::memory_order_relaxed); InitSCC_DFS(scc); #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP runner.store(std::thread::id{}, std::memory_order_relaxed); #else runner.store(-1, std::memory_order_relaxed); #endif // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP mu.Unlock(); } } // namespace internal } // namespace protobuf } // namespace google