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

FreeBSD Man Pages

Man Page or Keyword Search:
Man Architecture
Apropos Keyword Search (all sections) Output format
home | help
ATOMIC(9)	       FreeBSD 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);

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

     atomic_testandset_<type>(volatile _type_ *p, u_int	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

     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
     ordered data accesses, special instructions or special variants of
     instructions are used to indicate to the processor	that data accesses
     need to occur in a	certain	order.	As a result, most of the atomic	opera-
     tions 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 an acquire memory barrier.
     This barrier ensures that the effects of this operation are completed
     before the	effects	of any later data accesses.  As	a result, the opera-
     tion 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 per-
     formed, use atomic_subtract_acq_int().

     The third variant of each operation includes a release 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
     accesses 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
     affected 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

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

	     return (*p);

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

	     tmp = *p;
	     *p	= 0;
	     return (tmp);

     The atomic_readandclear() functions are not implemented for the types
     ``char'', ``short'', ``ptr'', ``8'', and ``16'' and do not	have any vari-
     ants 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-

     atomic_swap(p, v)
	     tmp = *p;
	     *p	= v;
	     return (tmp);

     The atomic_swap() 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_testandset(p, v)
	     bit = 1 <<	(v % (sizeof(*p) * NBBY));
	     tmp = (*p & bit) != 0;
	     *p	|= bit;
	     return (tmp);

     The atomic_testandset() functions are only	implemented for	the types
     ``int'', ``long'' and ``32'' and do not have any variants with memory
     barriers at this time.

     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(), atomic_readandclear(), and
     atomic_swap() functions return the	value at the specified address.	 The
     atomic_testandset() function returns the result of	the test operation.

     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()
     operations	were first introduced in FreeBSD 3.0.  This first set only
     supported 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.  The	atomic_swap() and atomic_testandset() opera-
     tions were	added in FreeBSD 10.0.

FreeBSD	10.2			 June 20, 2015			  FreeBSD 10.2


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

home | help