Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
ATOMIC(9)		 BSD Kernel Developer's	Manual		     ATOMIC(9)

     atomic_add, atomic_clear, atomic_cmpset, atomic_fetchadd, atomic_load,
     atomic_readandclear, atomic_set, atomic_subtract, atomic_store -- atomic

     #include <sys/types.h>
     #include <machine/atomic.h>

     atomic_add_[acq_|rel_]<type>(volatile _type_ *p, _type_ v);

     atomic_clear_[acq_|rel_]<type>(volatile _type_ *p,	_type_ v);

     atomic_cmpset_[acq_|rel_]<type>(volatile _type_ *dst, _type_ old,
	 _type_	new);

     atomic_fetchadd_<type>(volatile _type_ *p,	_type_ v);

     atomic_load_acq_<type>(volatile _type_ *p);

     atomic_readandclear_<type>(volatile _type_	*p);

     atomic_set_[acq_|rel_]<type>(volatile _type_ *p, _type_ v);

     atomic_subtract_[acq_|rel_]<type>(volatile	_type_ *p, _type_ v);

     atomic_store_rel_<type>(volatile _type_ *p, _type_	v);

     Each of the atomic	operations is guaranteed to be atomic in the presence
     of	interrupts.  They can be used to implement reference counts or as
     building blocks for more advanced synchronization primitives such as mu-

     Each atomic operation operates on a specific type.	 The type to use is
     indicated in the function name.  The available types that can be used

	   int	  unsigned integer
	   long	  unsigned long	integer
	   ptr	  unsigned integer the size of a pointer
	   32	  unsigned 32-bit integer
	   64	  unsigned 64-bit integer

     For example, the function to atomically add two integers is called

     Certain architectures also	provide	operations for types smaller than

	   char	  unsigned character
	   short  unsigned short integer
	   8	  unsigned 8-bit integer
	   16	  unsigned 16-bit integer

     These must	not be used in MI code because the instructions	to implement
     them efficiently may not be available.

   Memory Barriers
     Memory barriers are used to guarantee the order of	data accesses in two
     ways.  First, they	specify	hints to the compiler to not re-order or opti-
     mize the operations.  Second, on architectures that do not	guarantee or-
     dered data	accesses, special instructions or special variants of instruc-
     tions are used to indicate	to the processor that data accesses need to
     occur in a	certain	order.	As a result, most of the atomic	operations
     have three	variants in order to include optional memory barriers.	The
     first form	just performs the operation without any	explicit barriers.
     The second	form uses a read memory	barrier, and the third variant uses a
     write memory barrier.

     The second	variant	of each	operation includes a read memory barrier.
     This barrier ensures that the effects of this operation are completed be-
     fore the effects of any later data	accesses.  As a	result,	the operation
     is	said to	have acquire semantics as it acquires a	pseudo-lock requiring
     further operations	to wait	until it has completed.	 To denote this, the
     suffix "_acq" is inserted into the	function name immediately prior	to the
     "_<type>" suffix.	For example, to	subtract two integers ensuring that
     any later writes will happen after	the subtraction	is performed, use

     The third variant of each operation includes a write memory barrier.
     This ensures that all effects of all previous data	accesses are completed
     before this operation takes place.	 As a result, the operation is said to
     have release semantics as it releases any pending data accesses to	be
     completed before its operation is performed.  To denote this, the suffix
     "_rel" is inserted	into the function name immediately prior to the
     "_<type>" suffix.	For example, to	add two	long integers ensuring that
     all previous writes will happen first, use	atomic_add_rel_long().

     A practical example of using memory barriers is to	ensure that data ac-
     cesses that are protected by a lock are all performed while the lock is
     held.  To achieve this, one would use a read barrier when acquiring the
     lock to guarantee that the	lock is	held before any	protected operations
     are performed.  Finally, one would	use a write barrier when releasing the
     lock to ensure that all of	the protected operations are completed before
     the lock is released.

   Multiple Processors
     The current set of	atomic operations do not necessarily guarantee atomic-
     ity across	multiple processors.  To guarantee atomicity across proces-
     sors, not only does the individual	operation need to be atomic on the
     processor performing the operation, but the result	of the operation needs
     to	be pushed out to stable	storage	and the	caches of all other processors
     on	the system need	to invalidate any cache	lines that include the af-
     fected memory region.  On the i386	architecture, the cache	coherency
     model requires that the hardware perform this task, thus the atomic oper-
     ations are	atomic across multiple processors.  On the ia64	architecture,
     coherency is only guaranteed for pages that are configured	to using a
     caching policy of either uncached or write	back.

     This section describes the	semantics of each operation using a C like no-

     atomic_add(p, v)
	     *p	+= v;

     atomic_clear(p, v)
	     *p	&= ~v;

     atomic_cmpset(dst,	old, new)
	     if	(*dst == old) {
		     *dst = new;
		     return 1;
	     } else
		     return 0;

     The atomic_cmpset() functions are not implemented for the types "char",
     "short", "8", and "16".

     atomic_fetchadd(p,	v)
	     tmp = *p;
	     *p	+= v;
	     return tmp;

     The atomic_fetchadd() functions are only implemented for the types	"int",
     "long" and	"32" and do not	have any variants with memory barriers at this

	     return (*addr)

     The atomic_load() functions are only provided with	acquire	memory barri-

	     temp = *addr;
	     *addr = 0;
	     return (temp);

     The atomic_readandclear() functions are not implemented for the types
     "char", "short", "ptr", "8", and "16" and do not have any variants	with
     memory barriers at	this time.

     atomic_set(p, v)
	     *p	|= v;

     atomic_subtract(p,	v)
	     *p	-= v;

     atomic_store(p, v)
	     *p	= v;

     The atomic_store()	functions are only provided with release memory	barri-

     The type "64" is currently	not implemented	for any	of the atomic opera-
     tions on the arm, i386, and powerpc architectures.

     The atomic_cmpset() function returns the result of	the compare operation.
     The atomic_fetchadd(), atomic_load(), and atomic_readandclear() functions
     return the	value at the specified address.

     This example uses the atomic_cmpset_acq_ptr() and atomic_set_ptr()	func-
     tions to obtain a sleep mutex and handle recursion.  Since	the mtx_lock
     member of a struct	mtx is a pointer, the "ptr" type is used.

     /*	Try to obtain mtx_lock once. */
     #define _obtain_lock(mp, tid)					     \
	     atomic_cmpset_acq_ptr(&(mp)->mtx_lock, MTX_UNOWNED, (tid))

     /*	Get a sleep lock, deal with recursion inline. */
     #define _get_sleep_lock(mp, tid, opts, file, line)	do {		     \
	     uintptr_t _tid = (uintptr_t)(tid);				     \
	     if	(!_obtain_lock(mp, tid)) {				     \
		     if	(((mp)->mtx_lock & MTX_FLAGMASK) != _tid)	     \
			     _mtx_lock_sleep((mp), _tid, (opts), (file), (line));\
		     else {						     \
			     atomic_set_ptr(&(mp)->mtx_lock, MTX_RECURSE);   \
			     (mp)->mtx_recurse++;			     \
		     }							     \
	     }								     \
     } while (0)

     The atomic_add(), atomic_clear(), atomic_set(), and atomic_subtract() op-
     erations were first introduced in FreeBSD 3.0.  This first	set only sup-
     ported the	types "char", "short", "int", and "long".  The
     atomic_cmpset(), atomic_load(), atomic_readandclear(), and	atomic_store()
     operations	were added in FreeBSD 5.0.  The	types "8", "16", "32", "64",
     and "ptr" and all of the acquire and release variants were	added in
     FreeBSD 5.0 as well.  The atomic_fetchadd() operations were added in
     FreeBSD 6.0.

BSD			      September	27, 2005			   BSD


Want to link to this manual page? Use this URL:

home | help