Blame libdjvu/atomic.h

Packit df99a1
/* -*- C -*-
Packit df99a1
// -------------------------------------------------------------------
Packit df99a1
// Atomic primitives
Packit df99a1
// Copyright (c) 2008  Leon Bottou. All rights reserved
Packit df99a1
//
Packit df99a1
// Permission is hereby granted, free of charge, to any person obtaining
Packit df99a1
// a copy of this software and associated documentation files (the
Packit df99a1
// "Software"), to deal in the Software without restriction, including
Packit df99a1
// without limitation the rights to use, copy, modify, merge, publish,
Packit df99a1
// distribute, sublicense, and/or sell copies of the Software, and to
Packit df99a1
// permit persons to whom the Software is furnished to do so, subject to
Packit df99a1
// the following conditions:
Packit df99a1
//
Packit df99a1
// The above copyright notice and this permission notice shall be
Packit df99a1
// included in all copies or substantial portions of the Software.
Packit df99a1
//
Packit df99a1
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit df99a1
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit df99a1
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
Packit df99a1
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
Packit df99a1
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
Packit df99a1
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
Packit df99a1
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit df99a1
//
Packit df99a1
// ------------------------------------------------------------------- */
Packit df99a1
Packit df99a1
#ifndef ATOMIC_H
Packit df99a1
#define ATOMIC_H
Packit df99a1
Packit df99a1
#ifdef HAVE_CONFIG_H
Packit df99a1
# include "config.h"
Packit df99a1
#endif
Packit df99a1
Packit df99a1
/* This file defines macros or functions performing
Packit df99a1
// the following atomic operations with a full memory barrier. 
Packit df99a1
//
Packit df99a1
//   int atomicIncrement(int volatile *var) 
Packit df99a1
//   { *var += 1; return *var; } 
Packit df99a1
//   
Packit df99a1
//   int atomicDecrement(int volatile *var);
Packit df99a1
//   { *var -= 1; return *var; } 
Packit df99a1
//   
Packit df99a1
//   int atomicCompareAndSwap(int volatile *var, int oldval, int newval);
Packit df99a1
//   { int val = *var; if (val == oldval) { *var = newval };  returl val; }
Packit df99a1
//   
Packit df99a1
//   int atomicExchange(int volatile *var, int val);
Packit df99a1
//   { int tmp = *var; *var = val; return tmp; }
Packit df99a1
//   
Packit df99a1
//   void* atomicExchangePointer(void* volatile *var, int val);
Packit df99a1
//   { void* tmp = *var; *var = val; return tmp; }
Packit df99a1
*/
Packit df99a1
Packit df99a1
#ifdef __cplusplus
Packit df99a1
extern "C" {
Packit df99a1
#endif
Packit df99a1
Packit df99a1
#if !defined(ATOMIC_MACROS) && defined(_WIN64)
Packit df99a1
# define ATOMIC_MACROS "WIN64"
Packit df99a1
# include <windows.h>
Packit df99a1
# define atomicIncrement(var) \
Packit df99a1
  (int)(InterlockedIncrement((LONG volatile*)(var)))
Packit df99a1
# define atomicDecrement(var) \
Packit df99a1
  (int)(InterlockedDecrement((LONG volatile*)(var)))
Packit df99a1
# define atomicCompareAndSwap(var,ov,nv) \
Packit df99a1
  (InterlockedCompareExchange((LONG volatile*)(var),(LONG)(nv),(LONG)(ov)))
Packit df99a1
# define atomicExchange(var,nv) \
Packit df99a1
  (int)(InterlockedExchange((LONG volatile*)(var),(LONG)(nv)))
Packit df99a1
# define atomicExchangePointer(var,nv) \
Packit df99a1
  (void*)(InterlockedExchangePointer((PVOID volatile*)(var),(PVOID)(nv)))
Packit df99a1
#endif
Packit df99a1
Packit df99a1
#if !defined(ATOMIC_MACROS) && defined(_WIN32)
Packit df99a1
# define ATOMIC_MACROS "WIN32"
Packit df99a1
# include <windows.h>
Packit df99a1
# define atomicIncrement(var) \
Packit df99a1
  (int)(InterlockedIncrement((LONG volatile*)(var)))
Packit df99a1
# define atomicDecrement(var) \
Packit df99a1
  (int)(InterlockedDecrement((LONG volatile*)(var)))
Packit df99a1
# define atomicCompareAndSwap(var,ov,nv) \
Packit df99a1
  (InterlockedCompareExchange((LONG volatile*)(var),(LONG)(nv),(LONG)(ov)))
Packit df99a1
# define atomicExchange(var,nv) \
Packit df99a1
  (int)(InterlockedExchange((LONG volatile*)(var),(LONG)(nv)))
Packit df99a1
# define atomicExchangePointer(var,nv) \
Packit df99a1
  (void*)(InterlockedExchange((LONG volatile*)(var),(LONG)(nv)))
Packit df99a1
#endif
Packit df99a1
Packit df99a1
#if !defined(ATOMIC_MACROS) && defined(HAVE_INTEL_ATOMIC_BUILTINS)
Packit df99a1
# define ATOMIC_MACROS "INTEL"
Packit df99a1
# define atomicIncrement(var) \
Packit df99a1
  (__sync_add_and_fetch((int volatile *)(var), 1))
Packit df99a1
# define atomicDecrement(var) \
Packit df99a1
  (__sync_add_and_fetch((int volatile *)(var), -1))
Packit df99a1
# define atomicCompareAndSwap(var,ov,nv) \
Packit df99a1
  (__sync_val_compare_and_swap((int volatile*)(var),(int)(ov),(int)(nv)))
Packit df99a1
# if defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
Packit df99a1
#  define atomicExchange(var,nv) \
Packit df99a1
   (__sync_lock_test_and_set((int volatile*)(var),(int)(nv)))
Packit df99a1
#  define atomicExchangePointer(var,nv) \
Packit df99a1
   (__sync_lock_test_and_set((void* volatile*)(var),(void*)(nv)))
Packit df99a1
# else
Packit df99a1
  static inline int atomicExchange(int volatile *var, int nv) {
Packit df99a1
    int ov; do { ov = *var;  /* overkill */
Packit df99a1
    } while (! __sync_bool_compare_and_swap(var, ov, nv));
Packit df99a1
    return ov;
Packit df99a1
  }
Packit df99a1
  static inline void* atomicExchangePointer(void* volatile *var, void* nv) {
Packit df99a1
    void *ov; do { ov = *var;  /* overkill */
Packit df99a1
    } while (! __sync_bool_compare_and_swap(var, ov, nv));
Packit df99a1
    return ov;
Packit df99a1
  }
Packit df99a1
# endif
Packit df99a1
#endif
Packit df99a1
Packit df99a1
#if !defined(ATOMIC_MACROS) && defined(__GNUC__)
Packit df99a1
# if defined(__i386__) || defined(__amd64__) || defined(__x86_64__)
Packit df99a1
#  define ATOMIC_MACROS "GNU86"
Packit df99a1
  static inline int atomicIncrement(int volatile *var) {
Packit df99a1
    int ov; __asm__ __volatile__ ("lock; xaddl %0, %1" 
Packit df99a1
          : "=r" (ov), "=m" (*var) : "0" (1), "m" (*var) : "cc" );
Packit df99a1
    return ov + 1;
Packit df99a1
  }
Packit df99a1
  static inline int atomicDecrement(int volatile *var) {
Packit df99a1
    int ov; __asm__ __volatile__ ("lock; xaddl %0, %1" 
Packit df99a1
         : "=r" (ov), "=m" (*var) : "0" (-1), "m" (*var) : "cc" );
Packit df99a1
    return ov - 1;
Packit df99a1
  }
Packit df99a1
  static inline int atomicExchange(int volatile *var, int nv) {
Packit df99a1
    int ov; __asm__ __volatile__ ("xchgl %0, %1"
Packit df99a1
        : "=r" (ov), "=m" (*var) : "0" (nv), "m" (*var)); 
Packit df99a1
    return ov; 
Packit df99a1
  }
Packit df99a1
  static inline int atomicCompareAndSwap(int volatile *var, int ov, int nv) {
Packit df99a1
    int rv; __asm __volatile ("lock; cmpxchgl %2, %1"
Packit df99a1
        : "=a" (rv), "=m" (*var) : "r" (nv), "0" (ov), "m" (*var) : "cc");
Packit df99a1
    return rv;
Packit df99a1
  }
Packit df99a1
  static inline void *atomicExchangePointer(void * volatile *var, void *nv) {
Packit df99a1
    void *ov;  __asm__ __volatile__ (
Packit df99a1
#  if defined(__x86_64__) || defined(__amd64__)
Packit df99a1
         "xchgq %0, %1"
Packit df99a1
#  else
Packit df99a1
         "xchgl %0, %1"
Packit df99a1
#  endif
Packit df99a1
         : "=r" (ov), "=m" (*var) : "0" (nv), "m" (*var)); 
Packit df99a1
    return ov; 
Packit df99a1
  }
Packit df99a1
# endif
Packit df99a1
#endif
Packit df99a1
Packit df99a1
Packit df99a1
#ifndef ATOMIC_MACROS
Packit df99a1
  /* emulation */
Packit df99a1
  extern int atomicIncrement(int volatile *var);
Packit df99a1
  extern int atomicDecrement(int volatile *var);
Packit df99a1
  extern int atomicCompareAndSwap(int volatile *var, int ov, int nv);
Packit df99a1
  extern int atomicExchange(int volatile *var, int nv);
Packit df99a1
  extern void* atomicExchangePointer(void* volatile *var, void* nv);
Packit df99a1
#endif
Packit df99a1
Packit df99a1
  
Packit df99a1
# ifdef __cplusplus
Packit df99a1
}
Packit df99a1
# endif
Packit df99a1
Packit df99a1
#endif