|  | @@ -33,39 +33,197 @@
 | 
	
		
			
				|  |  |  #ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
 | 
	
		
			
				|  |  |  #define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include <atomic>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  namespace google {
 | 
	
		
			
				|  |  |  namespace protobuf {
 | 
	
		
			
				|  |  |  namespace internal {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// This implementation is transitional and maintains the original API for
 | 
	
		
			
				|  |  | +// atomicops.h. This requires casting memory locations to the atomic types, and
 | 
	
		
			
				|  |  | +// assumes that the API and the C++11 implementation are layout-compatible,
 | 
	
		
			
				|  |  | +// which isn't true for all implementations or hardware platforms. The static
 | 
	
		
			
				|  |  | +// assertion should detect this issue, were it to fire then this header
 | 
	
		
			
				|  |  | +// shouldn't be used.
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +// TODO(jfb) If this header manages to stay committed then the API should be
 | 
	
		
			
				|  |  | +//           modified, and all call sites updated.
 | 
	
		
			
				|  |  | +typedef volatile std::atomic<Atomic32>* AtomicLocation32;
 | 
	
		
			
				|  |  | +static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
 | 
	
		
			
				|  |  | +              "incompatible 32-bit atomic layout");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline void MemoryBarrier() {
 | 
	
		
			
				|  |  | +#if defined(__GLIBCXX__)
 | 
	
		
			
				|  |  | +  // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
 | 
	
		
			
				|  |  | +  // not defined, leading to the linker complaining about undefined references.
 | 
	
		
			
				|  |  | +  __atomic_thread_fence(std::memory_order_seq_cst);
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +  std::atomic_thread_fence(std::memory_order_seq_cst);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
 | 
	
		
			
				|  |  |                                           Atomic32 old_value,
 | 
	
		
			
				|  |  |                                           Atomic32 new_value) {
 | 
	
		
			
				|  |  | -  return __sync_val_compare_and_swap(ptr, old_value, new_value);
 | 
	
		
			
				|  |  | +  ((AtomicLocation32)ptr)
 | 
	
		
			
				|  |  | +      ->compare_exchange_strong(old_value,
 | 
	
		
			
				|  |  | +                                new_value,
 | 
	
		
			
				|  |  | +                                std::memory_order_relaxed,
 | 
	
		
			
				|  |  | +                                std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +  return old_value;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -inline void MemoryBarrier() {
 | 
	
		
			
				|  |  | -  __sync_synchronize();
 | 
	
		
			
				|  |  | +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
 | 
	
		
			
				|  |  | +                                         Atomic32 new_value) {
 | 
	
		
			
				|  |  | +  return ((AtomicLocation32)ptr)
 | 
	
		
			
				|  |  | +      ->exchange(new_value, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
 | 
	
		
			
				|  |  | +                                          Atomic32 increment) {
 | 
	
		
			
				|  |  | +  return increment +
 | 
	
		
			
				|  |  | +         ((AtomicLocation32)ptr)
 | 
	
		
			
				|  |  | +             ->fetch_add(increment, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
 | 
	
		
			
				|  |  | +                                        Atomic32 increment) {
 | 
	
		
			
				|  |  | +  return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
 | 
	
		
			
				|  |  |                                         Atomic32 old_value,
 | 
	
		
			
				|  |  |                                         Atomic32 new_value) {
 | 
	
		
			
				|  |  | -  Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
 | 
	
		
			
				|  |  | +  ((AtomicLocation32)ptr)
 | 
	
		
			
				|  |  | +      ->compare_exchange_strong(old_value,
 | 
	
		
			
				|  |  | +                                new_value,
 | 
	
		
			
				|  |  | +                                std::memory_order_acquire,
 | 
	
		
			
				|  |  | +                                std::memory_order_acquire);
 | 
	
		
			
				|  |  | +  return old_value;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
 | 
	
		
			
				|  |  | +                                       Atomic32 old_value,
 | 
	
		
			
				|  |  | +                                       Atomic32 new_value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation32)ptr)
 | 
	
		
			
				|  |  | +      ->compare_exchange_strong(old_value,
 | 
	
		
			
				|  |  | +                                new_value,
 | 
	
		
			
				|  |  | +                                std::memory_order_release,
 | 
	
		
			
				|  |  | +                                std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +  return old_value;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
 | 
	
		
			
				|  |  |    MemoryBarrier();
 | 
	
		
			
				|  |  | -  return ret;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
 | 
	
		
			
				|  |  | -  MemoryBarrier();
 | 
	
		
			
				|  |  | -  *ptr = value;
 | 
	
		
			
				|  |  | +  ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
 | 
	
		
			
				|  |  | +  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
 | 
	
		
			
				|  |  | -  Atomic32 value = *ptr;
 | 
	
		
			
				|  |  | +  return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
 | 
	
		
			
				|  |  | +  MemoryBarrier();
 | 
	
		
			
				|  |  | +  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef volatile std::atomic<Atomic64>* AtomicLocation64;
 | 
	
		
			
				|  |  | +static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
 | 
	
		
			
				|  |  | +              "incompatible 64-bit atomic layout");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
 | 
	
		
			
				|  |  | +                                         Atomic64 old_value,
 | 
	
		
			
				|  |  | +                                         Atomic64 new_value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation64)ptr)
 | 
	
		
			
				|  |  | +      ->compare_exchange_strong(old_value,
 | 
	
		
			
				|  |  | +                                new_value,
 | 
	
		
			
				|  |  | +                                std::memory_order_relaxed,
 | 
	
		
			
				|  |  | +                                std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +  return old_value;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
 | 
	
		
			
				|  |  | +                                         Atomic64 new_value) {
 | 
	
		
			
				|  |  | +  return ((AtomicLocation64)ptr)
 | 
	
		
			
				|  |  | +      ->exchange(new_value, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
 | 
	
		
			
				|  |  | +                                          Atomic64 increment) {
 | 
	
		
			
				|  |  | +  return increment +
 | 
	
		
			
				|  |  | +         ((AtomicLocation64)ptr)
 | 
	
		
			
				|  |  | +             ->fetch_add(increment, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
 | 
	
		
			
				|  |  | +                                        Atomic64 increment) {
 | 
	
		
			
				|  |  | +  return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
 | 
	
		
			
				|  |  | +                                       Atomic64 old_value,
 | 
	
		
			
				|  |  | +                                       Atomic64 new_value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation64)ptr)
 | 
	
		
			
				|  |  | +      ->compare_exchange_strong(old_value,
 | 
	
		
			
				|  |  | +                                new_value,
 | 
	
		
			
				|  |  | +                                std::memory_order_acquire,
 | 
	
		
			
				|  |  | +                                std::memory_order_acquire);
 | 
	
		
			
				|  |  | +  return old_value;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
 | 
	
		
			
				|  |  | +                                       Atomic64 old_value,
 | 
	
		
			
				|  |  | +                                       Atomic64 new_value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation64)ptr)
 | 
	
		
			
				|  |  | +      ->compare_exchange_strong(old_value,
 | 
	
		
			
				|  |  | +                                new_value,
 | 
	
		
			
				|  |  | +                                std::memory_order_release,
 | 
	
		
			
				|  |  | +                                std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +  return old_value;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
 | 
	
		
			
				|  |  |    MemoryBarrier();
 | 
	
		
			
				|  |  | -  return value;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
 | 
	
		
			
				|  |  | +  ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
 | 
	
		
			
				|  |  | +  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
 | 
	
		
			
				|  |  | +  return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
 | 
	
		
			
				|  |  | +  MemoryBarrier();
 | 
	
		
			
				|  |  | +  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#endif  // defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  }  // namespace internal
 | 
	
		
			
				|  |  |  }  // namespace protobuf
 | 
	
		
			
				|  |  |  }  // namespace google
 |