unchanged: --- protobuf-cleaned/src/google/protobuf/stubs/status.cc 2015-12-30 13:21:46.000000000 -0800 +++ protobuf-patched/src/google/protobuf/stubs/status.cc 2016-03-31 13:25:40.888006485 -0700 @@ -82,9 +82,9 @@ } } // namespace error. -const Status Status::OK = Status(); -const Status Status::CANCELLED = Status(error::CANCELLED, ""); -const Status Status::UNKNOWN = Status(error::UNKNOWN, ""); +const StatusPod Status::OK = { error::OK }; +const StatusPod Status::CANCELLED = { error::CANCELLED }; +const StatusPod Status::UNKNOWN = { error::UNKNOWN }; Status::Status() : error_code_(error::OK) { } @@ -100,6 +100,9 @@ : error_code_(other.error_code_), error_message_(other.error_message_) { } +Status::Status(const StatusPod& status_pod) : error_code_(status_pod.code) { +} + Status& Status::operator=(const Status& other) { error_code_ = other.error_code_; error_message_ = other.error_message_; unchanged: --- protobuf-cleaned/src/google/protobuf/stubs/status.h 2015-12-30 13:21:46.000000000 -0800 +++ protobuf-patched/src/google/protobuf/stubs/status.h 2016-03-31 13:25:40.888006485 -0700 @@ -62,6 +62,10 @@ }; } // namespace error +struct StatusPod { + error::Code code; +}; + class LIBPROTOBUF_EXPORT Status { public: // Creates a "successful" status. @@ -73,13 +77,14 @@ // constructed. Status(error::Code error_code, StringPiece error_message); Status(const Status&); + Status(const StatusPod&); Status& operator=(const Status& x); ~Status() {} // Some pre-defined Status objects - static const Status OK; // Identical to 0-arg constructor - static const Status CANCELLED; - static const Status UNKNOWN; + static const StatusPod OK; + static const StatusPod CANCELLED; + static const StatusPod UNKNOWN; // Accessor bool ok() const { only in patch2: unchanged: unchanged: --- protobuf-cleaned/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc +++ protobuf-patched/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc @@ -67,14 +67,12 @@ namespace internal { // Set the flags so that code will run correctly and conservatively, so even // if we haven't been initialized yet, we're probably single threaded, and our // default values should hopefully be pretty safe. -struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = { +AtomicOps_x86CPUFeatureStruct AtomicOps_x86CPUFeatures_Private = { + false, // uninitialized false, // bug can't exist before process spawns multiple threads false, // no SSE2 }; -namespace { - -// Initialize the AtomicOps_Internalx86CPUFeatures struct. void AtomicOps_Internalx86CPUFeaturesInit() { uint32_t eax; uint32_t ebx; @@ -99,6 +97,13 @@ void AtomicOps_Internalx86CPUFeaturesInit() { model += ((eax >> 16) & 0xf) << 4; } + // Rarely, this function may be called from multiple threads at the same time. + // To prevent races, do the initialization in a temporary struct and do a + // lock-free assignment at the end. The assignment will be atomic since the + // struct can fit into a single byte. + AtomicOps_x86CPUFeatureStruct New_AtomicOps_x86CPUFeatures_Private; + New_AtomicOps_x86CPUFeatures_Private.initialized = true; + // Opteron Rev E has a bug in which on very rare occasions a locked // instruction doesn't act as a read-acquire barrier if followed by a // non-locked read-modify-write instruction. Rev F has this bug in @@ -107,27 +112,17 @@ void AtomicOps_Internalx86CPUFeaturesInit() { if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD family == 15 && 32 <= model && model <= 63) { - AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true; + New_AtomicOps_x86CPUFeatures_Private.has_amd_lock_mb_bug = true; } else { - AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false; + New_AtomicOps_x86CPUFeatures_Private.has_amd_lock_mb_bug = false; } // edx bit 26 is SSE2 which we use to tell use whether we can use mfence - AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1); + New_AtomicOps_x86CPUFeatures_Private.has_sse2 = ((edx >> 26) & 1); + + AtomicOps_x86CPUFeatures_Private = New_AtomicOps_x86CPUFeatures_Private; } -class AtomicOpsx86Initializer { - public: - AtomicOpsx86Initializer() { - AtomicOps_Internalx86CPUFeaturesInit(); - } -}; - -// A global to get use initialized on startup via static initialization :/ -AtomicOpsx86Initializer g_initer; - -} // namespace - } // namespace internal } // namespace protobuf } // namespace google unchanged: --- protobuf-cleaned/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h +++ protobuf-patched/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h @@ -33,20 +33,39 @@ #ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_ #define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_ +#include + namespace google { namespace protobuf { namespace internal { -// This struct is not part of the public API of this module; clients may not -// use it. -// Features of this x86. Values may not be correct before main() is run, -// but are set conservatively. +// This struct and its associated functions are not part of the public API of +// this module; clients may not use it. +// +// Features of this x86. struct AtomicOps_x86CPUFeatureStruct { - bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence - // after acquire compare-and-swap. - bool has_sse2; // Processor has SSE2. + // Whether AtomicOps_Internalx86CPUFeaturesInit was called. + bool initialized : 1; + + // Processor has AMD memory-barrier bug; do lfence after acquire + // compare-and-swap. + bool has_amd_lock_mb_bug : 1; + + // Processor has SSE2. + bool has_sse2 : 1; }; -extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures; + +// Initialize |AtomicOps_Internalx86CPUFeatures_Private|. +void AtomicOps_Internalx86CPUFeaturesInit(); + +inline const AtomicOps_x86CPUFeatureStruct& +Get_AtomicOps_Internalx86CPUFeatures() { + extern AtomicOps_x86CPUFeatureStruct AtomicOps_x86CPUFeatures_Private; + if (GOOGLE_PREDICT_FALSE(!AtomicOps_x86CPUFeatures_Private.initialized)) { + AtomicOps_Internalx86CPUFeaturesInit(); + } + return AtomicOps_x86CPUFeatures_Private; +} #define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") @@ -89,7 +108,7 @@ inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, : "+r" (temp), "+m" (*ptr) : : "memory"); // temp now holds the old value of *ptr - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + if (Get_AtomicOps_Internalx86CPUFeatures().has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return temp + increment; @@ -99,7 +118,7 @@ inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + if (Get_AtomicOps_Internalx86CPUFeatures().has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return x; @@ -131,7 +150,7 @@ inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { #else inline void MemoryBarrierInternal() { - if (AtomicOps_Internalx86CPUFeatures.has_sse2) { + if (Get_AtomicOps_Internalx86CPUFeatures().has_sse2) { __asm__ __volatile__("mfence" : : : "memory"); } else { // mfence is faster but not present on PIII Atomic32 x = 0; @@ -140,7 +159,7 @@ inline void MemoryBarrierInternal() { } inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { - if (AtomicOps_Internalx86CPUFeatures.has_sse2) { + if (Get_AtomicOps_Internalx86CPUFeatures().has_sse2) { *ptr = value; __asm__ __volatile__("mfence" : : : "memory"); } else { @@ -213,7 +232,7 @@ inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, : "+r" (temp), "+m" (*ptr) : : "memory"); // temp now contains the previous value of *ptr - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + if (Get_AtomicOps_Internalx86CPUFeatures().has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return temp + increment; @@ -270,7 +289,7 @@ inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + if (Get_AtomicOps_Internalx86CPUFeatures().has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return x;