You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/atomic_ops.h

186 lines
8.9 KiB

/*
* $Id$
*
* Copyright (C) 2006 iptelorg GmbH
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*!
* \file
* \brief SIP-router core :: Atomic operations and memory barriers
* \ingroup core
* Module: \ref core
* See \ref atomic
*/
/*
* \page atomicops Atomic operations and memory barriers
*
* WARNING: atomic ops do not include memory barriers
*
* memory barriers:
* ----------------
*
* void membar(); - memory barrier (load & store)
* void membar_read() - load (read) memory barrier
* void membar_write() - store (write) memory barrier
* void membar_depends() - read depends memory barrier, needed before using
* the contents of a pointer (for now is needed only
* on Alpha so on all other CPUs it will be a no-op)
* For more info see:
* http://lse.sourceforge.net/locking/wmbdd.html
* http://www.linuxjournal.com/article/8212
*
* void membar_enter_lock() - memory barrier function that should be
* called after a lock operation (where lock is
* an asm inline function that uses atomic store
* operation on the lock var.). It is at most
* a StoreStore|StoreLoad barrier, but could also
* be empty if an atomic op implies a memory
* barrier on the specific arhitecture.
* Example usage:
* raw_lock(l); membar_enter_lock(); ...
* void membar_leave_lock() - memory barrier function that should be called
* before an unlock operation (where unlock is an
* asm inline function that uses at least an atomic
* store to on the lock var.). It is at most a
* LoadStore|StoreStore barrier (but could also be
* empty, see above).
* Example: raw_lock(l); membar_enter_lock(); ..
* ... critical section ...
* membar_leave_lock(); raw_unlock(l);
* void membar_atomic_op() - memory barrier that should be called if a memory
* barrier is needed immediately after or
* immediately before an atomic operation
* (for example: atomic_inc(&i); membar_atomic_op()
* instead of atomic_inc(&i); membar()).
* atomic_op means every atomic operation except get
* and set (for them use membar_atomic_setget()).
* Using membar_atomic_op() instead of membar() in
* these cases will generate faster code on some
* architectures (for now x86 and x86_64), where
* atomic operations act also as memory barriers.
* Note that mb_atomic_<OP>(...) is equivalent to
* membar_atomic_op(); atomic_<OP>(...) and in this
* case the first form is preferred).
* void membar_atomic_setget() - same as above but for atomic_set and
* atomic_get (and not for any other atomic op.,
* including atomic_get_and_set, for them use
* membar_atomic_op()).
* Note that mb_atomic_{get,set}(&i) is equivalent
* and preferred to membar_atomic_setget();
* atomic_{get,set}(&i) (it will generate faster
* code on x86 and x86_64).
* void membar_read_atomic_op() - like membar_atomic_op(), but acts only as
* a read barrier.
* void membar_read_atomic_setget() - like membar_atomic_setget() but acts only
* as a read barrier.
* void membar_write_atomic_op() - like membar_atomic_op(), but acts only as
* a write barrier.
* void membar_write_atomic_setget() - like membar_atomic_setget() but acts
* only as a write barrier.
*
*
* Note: - properly using memory barriers is tricky, in general try not to
* depend on them. Locks include memory barriers, so you don't need
* them for writes/load already protected by locks.
* - membar_enter_lock() and membar_leave_lock() are needed only if
* you implement your own locks using atomic ops (ser locks have the
* membars included)
*
* atomic operations:
* ------------------
* type: atomic_t
*
* not including memory barriers:
*
* void atomic_set(atomic_t* v, int i) - v->val=i
* int atomic_get(atomic_t* v) - return v->val
* int atomic_get_and_set(atomic_t *v, i) - return old v->val, v->val=i
* void atomic_inc(atomic_t* v)
* void atomic_dec(atomic_t* v)
* int atomic_inc_and_test(atomic_t* v) - returns 1 if the result is 0
* int atomic_dec_and_test(atomic_t* v) - returns 1 if the result is 0
* void atomic_or (atomic_t* v, int mask) - v->val|=mask
* void atomic_and(atomic_t* v, int mask) - v->val&=mask
* int atomic_add(atomic_t* v, int i) - v->val+=i; return v->val
* int atomic_cmpxchg(atomic_t* v, o, n) - r=v->val; if (r==o) v->val=n;
* return r (old value)
*
*
* same ops, but with builtin memory barriers:
*
* void mb_atomic_set(atomic_t* v, int i) - v->val=i
* int mb_atomic_get(atomic_t* v) - return v->val
* int mb_atomic_get_and_set(atomic_t *v, i) - return old v->val, v->val=i
* void mb_atomic_inc(atomic_t* v)
* void mb_atomic_dec(atomic_t* v)
* int mb_atomic_inc_and_test(atomic_t* v) - returns 1 if the result is 0
* int mb_atomic_dec_and_test(atomic_t* v) - returns 1 if the result is 0
* void mb_atomic_or(atomic_t* v, int mask - v->val|=mask
* void mb_atomic_and(atomic_t* v, int mask)- v->val&=mask
* int mb_atomic_add(atomic_t* v, int i) - v->val+=i; return v->val
* int mb_atomic_cmpxchg(atomic_t* v, o, n) - r=v->val; if (r==o) v->val=n;
* return r (old value)
*
* Same operations are available for int and long. The functions are named
* after the following rules:
* - add an int or long suffix to the correspondent atomic function
* - volatile int* or volatile long* replace atomic_t* in the functions
* declarations
* - long and int replace the parameter type (if the function has an extra
* parameter) and the return value
* E.g.:
* long atomic_get_long(volatile long* v)
* int atomic_get_int( volatile int* v)
* long atomic_get_and_set(volatile long* v, long l)
* int atomic_get_and_set(volatile int* v, int i)
*
* Config defines: CC_GCC_LIKE_ASM - the compiler support gcc style
* inline asm
* NOSMP - the code will be a little faster, but not SMP
* safe
* __CPU_i386, __CPU_x86_64, X86_OOSTORE - see
* atomic/atomic_x86.h
* __CPU_mips, __CPU_mips2, __CPU_mips64, MIPS_HAS_LLSC - see
* atomic/atomic_mip2.h
* __CPU_ppc, __CPU_ppc64 - see atomic/atomic_ppc.h
* __CPU_sparc - see atomic/atomic_sparc.h
* __CPU_sparc64, SPARC64_MODE - see atomic/atomic_sparc64.h
* __CPU_arm, __CPU_arm6 - see atomic/atomic_arm.h
* __CPU_alpha - see atomic/atomic_alpha.h
*/
/*
* History:
* --------
* 2006-03-08 created by andrei
* 2007-05-13 moved some of the decl. and includes into atomic_common.h and
* atomic_native.h (andrei)
*/
#ifndef __atomic_ops
#define __atomic_ops
#include "atomic/atomic_common.h"
#include "atomic/atomic_native.h"
/*! \brief if no native operations, emulate them using locks */
#if ! defined HAVE_ASM_INLINE_ATOMIC_OPS || ! defined HAVE_ASM_INLINE_MEMBAR
#include "atomic/atomic_unknown.h"
#endif /* if HAVE_ASM_INLINE_ATOMIC_OPS */
#endif