wterl/c_src/atomic.h
2013-07-08 13:34:42 -04:00

100 lines
4.4 KiB
C

/*
* File:
* atomic.h
* Author(s):
* Pascal Felber <pascal.felber@unine.ch>
* Patrick Marlier <patrick.marlier@unine.ch>
* Description:
* Atomic operations.
*
* Copyright (c) 2007-2012.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This program has a dual license and can also be distributed
* under the terms of the MIT license.
*/
#ifndef _ATOMIC_H_
# define _ATOMIC_H_
# ifdef ATOMIC_BUILTIN
typedef volatile size_t atomic_t;
# ifdef __INTEL_COMPILER
# define ATOMIC_CB __memory_barrier()
# else /* ! __INTEL_COMPILER, assuming __GNUC__ */
# define ATOMIC_CB __asm__ __volatile__("": : :"memory")
# endif /* ! __INTEL_COMPILER */
# ifndef UNSAFE
# warning "This is experimental and shouldn't be used"
/*
Note: __sync_ is available for GCC 4.2+ and ICC 11.1+
But these definitions are not 100% safe:
* need 'a' to be volatile
* no fence for read/store proposed (only full fence)
C11 and C++11 also propose atomic operations.
*/
# define ATOMIC_CAS_FULL(a, e, v) (__sync_bool_compare_and_swap(a, e, v))
# define ATOMIC_FETCH_INC_FULL(a) (__sync_fetch_and_add(a, 1))
# define ATOMIC_FETCH_DEC_FULL(a) (__sync_fetch_and_add(a, -1))
# define ATOMIC_FETCH_ADD_FULL(a, v) (__sync_fetch_and_add(a, v))
# define ATOMIC_LOAD_ACQ(a) (*(a))
# define ATOMIC_LOAD(a) (*(a))
# define ATOMIC_STORE_REL(a, v) (*(a) = (v))
# define ATOMIC_STORE(a, v) (*(a) = (v))
# define ATOMIC_MB_READ /* Nothing */
# define ATOMIC_MB_WRITE /* Nothing */
# define ATOMIC_MB_FULL __sync_synchronize()
# else
/* Use only for testing purposes (single thread benchmarks) */
# define ATOMIC_CAS_FULL(a, e, v) (*(a) = (v), 1)
# define ATOMIC_FETCH_INC_FULL(a) ((*(a))++)
# define ATOMIC_FETCH_DEC_FULL(a) ((*(a))--)
# define ATOMIC_FETCH_ADD_FULL(a, v) ((*(a)) += (v))
# define ATOMIC_LOAD_ACQ(a) (*(a))
# define ATOMIC_LOAD(a) (*(a))
# define ATOMIC_STORE_REL(a, v) (*(a) = (v))
# define ATOMIC_STORE(a, v) (*(a) = (v))
# define ATOMIC_MB_READ /* Nothing */
# define ATOMIC_MB_WRITE /* Nothing */
# define ATOMIC_MB_FULL /* Nothing */
# endif /* UNSAFE */
# else /* ! ATOMIC_BUILTIN */
/* NOTE: enable fence instructions for i386 and amd64 but the mfence instructions seems costly. */
/* # define AO_USE_PENTIUM4_INSTRS */
# include "atomic_ops/atomic_ops.h"
typedef AO_t atomic_t;
# define ATOMIC_CB AO_compiler_barrier()
# define ATOMIC_CAS_FULL(a, e, v) (AO_compare_and_swap_full((volatile AO_t *)(a), (AO_t)(e), (AO_t)(v)))
# define ATOMIC_FETCH_INC_FULL(a) (AO_fetch_and_add1_full((volatile AO_t *)(a)))
# define ATOMIC_FETCH_DEC_FULL(a) (AO_fetch_and_sub1_full((volatile AO_t *)(a)))
# define ATOMIC_FETCH_ADD_FULL(a, v) (AO_fetch_and_add_full((volatile AO_t *)(a), (AO_t)(v)))
# ifdef SAFE
# define ATOMIC_LOAD_ACQ(a) (AO_load_full((volatile AO_t *)(a)))
# define ATOMIC_LOAD(a) (AO_load_full((volatile AO_t *)(a)))
# define ATOMIC_STORE_REL(a, v) (AO_store_full((volatile AO_t *)(a), (AO_t)(v)))
# define ATOMIC_STORE(a, v) (AO_store_full((volatile AO_t *)(a), (AO_t)(v)))
# define ATOMIC_MB_READ AO_nop_full()
# define ATOMIC_MB_WRITE AO_nop_full()
# define ATOMIC_MB_FULL AO_nop_full()
# else /* ! SAFE */
# define ATOMIC_LOAD_ACQ(a) (AO_load_acquire_read((volatile AO_t *)(a)))
# define ATOMIC_LOAD(a) (*((volatile AO_t *)(a)))
# define ATOMIC_STORE_REL(a, v) (AO_store_release((volatile AO_t *)(a), (AO_t)(v)))
# define ATOMIC_STORE(a, v) (*((volatile AO_t *)(a)) = (AO_t)(v))
# define ATOMIC_MB_READ AO_nop_read()
# define ATOMIC_MB_WRITE AO_nop_write()
# define ATOMIC_MB_FULL AO_nop_full()
# endif /* ! SAFE */
# endif /* ! NO_AO */
#endif /* _ATOMIC_H_ */