text: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  
  #ifndef DORIS_BE_SRC_COMMON_ATOMIC_H
  #define DORIS_BE_SRC_COMMON_ATOMIC_H
  
  #include <algorithm>
  
  #include "common/compiler_util.h"
  #include "gutil/atomicops.h"
  #include "gutil/macros.h"
  
  namespace doris {
  
  class AtomicUtil {
  public:
      // Issues instruction to have the CPU wait, this is less busy (bus traffic
      // etc) than just spinning.
      // For example:
      //  while (1);
      // should be:
      //  while (1) CpuWait();
      static ALWAYS_INLINE void cpu_wait() {
          asm volatile("pause\n": : :"memory");
      }
  
      /// Provides "barrier" semantics (see below) without a memory access.
      static ALWAYS_INLINE void memory_barrier() {
          __sync_synchronize();
      }
  
      /// Provides a compiler barrier. The compiler is not allowed to reorder memory
      /// accesses across this (but the CPU can).  This generates no instructions.
      static ALWAYS_INLINE void compiler_barrier() {
          __asm__ __volatile__("" : : : "memory");
      }
  };
  
  // Wrapper for atomic integers.  This should be switched to c++ 11 when
  // we can switch.
  // This class overloads operators to behave like a regular integer type
  // but all operators and functions are thread safe.
  template<typename T>
  class AtomicInt {
  public:
      AtomicInt(T initial) : _value(initial) {}
      AtomicInt() : _value(0) {}
  
      operator T() const { return _value; }
  
      AtomicInt& operator=(T val) {
          _value = val;
          return *this;
      }
      AtomicInt& operator=(const AtomicInt<T>& val) {
          _value = val._value;
          return *this;
      }
  
      AtomicInt& operator+=(T delta) {
          __sync_add_and_fetch(&_value, delta);
          return *this;
      }
      AtomicInt& operator-=(T delta) {
          __sync_add_and_fetch(&_value, -delta);
          return *this;
      }
  
      AtomicInt& operator|=(T v) {
          __sync_or_and_fetch(&_value, v);
          return *this;
      }
      AtomicInt& operator&=(T v) {
          __sync_and_and_fetch(&_value, v);
          return *this;
      }
  
      // These define the preincrement (i.e. --value) operators.
      AtomicInt& operator++() {
          __sync_add_and_fetch(&_value, 1);
          return *this;
      }
      AtomicInt& operator--() {
          __sync_add_and_fetch(&_value, -1);
          return *this;
      }
  
      // This is post increment, which needs to return a new object.
      AtomicInt<T> operator++(int) {
          T prev = __sync_fetch_and_add(&_value, 1);
          return AtomicInt<T>(prev);
      }
      AtomicInt<T> operator--(int) {
          T prev = __sync_fetch_and_add(&_value, -1);
          return AtomicInt<T>(prev);
      }
  
      // Safe read of the value
      T read() {
          return __sync_fetch_and_add(&_value, 0);
      }
  
      /// Atomic load with "acquire" memory-ordering semantic.
      ALWAYS_INLINE T load() const {
          return base::subtle::Acquire_Load(&_value);
      }
  
      /// Atomic store with "release" memory-ordering semantic.
      ALWAYS_INLINE void store(T x) {
          base::subtle::Release_Store(&_value, x);
      }
  
      /// Atomic add with "barrier" memory-ordering semantic. Returns the new value.
      ALWAYS_INLINE T add(T x) {
          return base::subtle::Barrier_AtomicIncrement(&_value, x);
      }
  
      // Increments by delta (i.e. += delta) and returns the new val
      T update_and_fetch(T delta) {
          return __sync_add_and_fetch(&_value, delta);
      }
  
      // Increment by delta and returns the old val
      T fetch_and_update(T delta) {
          return __sync_fetch_and_add(&_value, delta);
      }
  
      // Updates the int to 'value' if value is larger
      void update_max(T value) {
          while (true) {
              T old_value = _value;
              T new_value = std::max(old_value, value);
              if (LIKELY(compare_and_swap(old_value, new_value))) {
                  break;
              }
          }
      }
      void update_min(T value) {
          while (true) {
              T old_value = _value;
              T new_value = std::min(old_value, value);
              if (LIKELY(compare_and_swap(old_value, new_value))) {
                  break;
              }
          }
      }
  
      // Returns true if the atomic compare-and-swap was successful.
      // If _value == oldVal, make _value = new_val and return true; otherwise return false;
      bool compare_and_swap(T old_val, T new_val) {
          return __sync_bool_compare_and_swap(&_value, old_val, new_val);
      }
  
      // Returns the content of _value before the operation.
      // If returnValue == old_val, then the atomic compare-and-swap was successful.
      T compare_and_swap_val(T old_val, T new_val) {
          return __sync_val_compare_and_swap(&_value, old_val, new_val);
      }
  
      // Atomically updates _value with new_val. Returns the old _value.
      T swap(const T& new_val) {
          return __sync_lock_test_and_set(&_value, new_val);
      }
  
  private:
      T _value;
  };
  
  /// Supported atomic types. Use these types rather than referring to AtomicInt<>
  /// directly.
  typedef AtomicInt<int32_t> AtomicInt32;
  typedef AtomicInt<int64_t> AtomicInt64;
  
  /// Atomic pointer. Operations have the same semantics as AtomicInt.
  template<typename T>
  class AtomicPtr {
  public:
      AtomicPtr(T* initial = nullptr) : _ptr(reinterpret_cast<intptr_t>(initial)) {}
  
      /// Atomic load with "acquire" memory-ordering semantic.
      inline T* load() const { return reinterpret_cast<T*>(_ptr.load()); }
  
      /// Atomic store with "release" memory-ordering semantic.
      inline void store(T* val) { _ptr.store(reinterpret_cast<intptr_t>(val)); }
  
  private:
      AtomicInt<intptr_t> _ptr;
  };
  
  } // end namespace doris
  
  #endif // DORIS_BE_SRC_COMMON_ATOMIC_H
  