|
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
|