text: /* This file implements atomic counters using __atomic or __sync macros if
   * available, otherwise synchronizing different threads using a mutex.
   *
   * The exported interaface is composed of three macros:
   *
   * atomicIncr(var,count) -- Increment the atomic counter
   * atomicGetIncr(var,oldvalue_var,count) -- Get and increment the atomic counter
   * atomicDecr(var,count) -- Decrement the atomic counter
   * atomicGet(var,dstvar) -- Fetch the atomic counter value
   * atomicSet(var,value)  -- Set the atomic counter value
   *
   * The variable 'var' should also have a declared mutex with the same
   * name and the "_mutex" postfix, for instance:
   *
   *  long myvar;
   *  pthread_mutex_t myvar_mutex;
   *  atomicSet(myvar,12345);
   *
   * If atomic primitives are availble (tested in config.h) the mutex
   * is not used.
   *
   * Never use return value from the macros, instead use the AtomicGetIncr()
   * if you need to get the current value and increment it atomically, like
   * in the followign example:
   *
   *  long oldvalue;
   *  atomicGetIncr(myvar,oldvalue,1);
   *  doSomethingWith(oldvalue);
   *
   * ----------------------------------------------------------------------------
   *
   * Copyright (c) 2015, Salvatore Sanfilippo <antirez at gmail dot com>
   * All rights reserved.
   *
   * 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 Redis 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.
   */
  
  #include <pthread.h>
  
  #ifndef __ATOMIC_VAR_H
  #  define __ATOMIC_VAR_H
  
  /* To test Redis with Helgrind (a Valgrind tool) it is useful to define
   * the following macro, so that __sync macros are used: those can be detected
   * by Helgrind (even if they are less efficient) so that no false positive
   * is reported. */
  // #define __ATOMIC_VAR_FORCE_SYNC_MACROS
  
  #  if !defined(__ATOMIC_VAR_FORCE_SYNC_MACROS) && defined(__ATOMIC_RELAXED) && !defined(__sun) \
        && (!defined(__clang__) || !defined(__APPLE__) || __apple_build_version__ > 4210057)
  /* Implementation using __atomic macros. */
  
  #    define atomicIncr(var, count) __atomic_add_fetch(&var, (count), __ATOMIC_RELAXED)
  #    define atomicGetIncr(var, oldvalue_var, count)                         \
        do {                                                                  \
          oldvalue_var = __atomic_fetch_add(&var, (count), __ATOMIC_RELAXED); \
        } while (0)
  #    define atomicDecr(var, count) __atomic_sub_fetch(&var, (count), __ATOMIC_RELAXED)
  #    define atomicGet(var, dstvar)                        \
        do {                                                \
          dstvar = __atomic_load_n(&var, __ATOMIC_RELAXED); \
        } while (0)
  #    define atomicSet(var, value) __atomic_store_n(&var, value, __ATOMIC_RELAXED)
  #    define REDIS_ATOMIC_API "atomic-builtin"
  
  #  elif defined(HAVE_ATOMIC)
  /* Implementation using __sync macros. */
  
  #    define atomicIncr(var, count) __sync_add_and_fetch(&var, (count))
  #    define atomicGetIncr(var, oldvalue_var, count)         \
        do {                                                  \
          oldvalue_var = __sync_fetch_and_add(&var, (count)); \
        } while (0)
  #    define atomicDecr(var, count) __sync_sub_and_fetch(&var, (count))
  #    define atomicGet(var, dstvar)              \
        do {                                      \
          dstvar = __sync_sub_and_fetch(&var, 0); \
        } while (0)
  #    define atomicSet(var, value)                               \
        do {                                                      \
          while (!__sync_bool_compare_and_swap(&var, var, value)) \
            ;                                                     \
        } while (0)
  #    define REDIS_ATOMIC_API "sync-builtin"
  
  #  else
  /* Implementation using pthread mutex. */
  
  #    define atomicIncr(var, count)          \
        do {                                  \
          pthread_mutex_lock(&var##_mutex);   \
          var += (count);                     \
          pthread_mutex_unlock(&var##_mutex); \
        } while (0)
  #    define atomicGetIncr(var, oldvalue_var, count) \
        do {                                          \
          pthread_mutex_lock(&var##_mutex);           \
          oldvalue_var = var;                         \
          var += (count);                             \
          pthread_mutex_unlock(&var##_mutex);         \
        } while (0)
  #    define atomicDecr(var, count)          \
        do {                                  \
          pthread_mutex_lock(&var##_mutex);   \
          var -= (count);                     \
          pthread_mutex_unlock(&var##_mutex); \
        } while (0)
  #    define atomicGet(var, dstvar)          \
        do {                                  \
          pthread_mutex_lock(&var##_mutex);   \
          dstvar = var;                       \
          pthread_mutex_unlock(&var##_mutex); \
        } while (0)
  #    define atomicSet(var, value)           \
        do {                                  \
          pthread_mutex_lock(&var##_mutex);   \
          var = value;                        \
          pthread_mutex_unlock(&var##_mutex); \
        } while (0)
  #    define REDIS_ATOMIC_API "pthread-mutex"
  
  #  endif
  #endif /* __ATOMIC_VAR_H */
  