User-space RCU: Atomic-operation and utility API
Many of URCU's atomic operations were derived from the implementations in the BSD-licensed Boehm-Demers-Weiser conservative garbage collector for license-compatibility reasons. This section also includes utility functions that are not strictly speaking atomic, but are often used in conjunction with atomic operations.
With a few exceptions, these operations have one of the following three prefixes:
-
caa_: Concurrent Architecture Abstraction. -
cmm_: Concurrent Memory Model. -
uatomic_: URCU Atomic Operation.
The individual operations are as follows:
-
caa_container_of(ptr, type, member): Given a pointerptrto a field namedmemberin an enclosing structure of typetype, return a pointer to the enclosing structure. -
caa_likely(x)andcaa_unlikely(x): Inform the compiler of the developer's opinion on whether the specified conditionxis likely to evaluate totrue. -
caa_max(a,b)andcaa_min(a,b): Take the maximum or minimum, respectively, ofaandb. -
cmm_barrier(): Prevent the compiler from carrying out any code-motion optimizations that would move memory references across this directive. -
cmm_smp_mb(): Memory barrier that prevents both the compiler and the CPU from carrying out any code-motion optimizations that would move memory references across this directive. -
cmm_smp_rmb(): Memory barrier that prevents both the compiler and the CPU from carrying out any code-motion optimizations that would move reads from memory across this directive. -
cmm_smp_wmb(): Memory barrier that prevents both the compiler and the CPU from carrying out any code-motion optimizations that would move writes to memory across this directive. Please see the memory-barrier menagerie for more details on how these three memory-barrier primitives can be used. -
CMM_ACCESS_ONCE(x): Force the compiler to accessxexactly as specified in the source code, preventing the compiler from carrying out any optimizations that would either combine or split accesses. This is quite similar to the Linux kernel'sACCESS_ONCE()primitive. -
CMM_LOAD_SHARED(p): Perform a load withCMM_ACCESS_ONCE(x)semantics. -
CMM_STORE_SHARED(x, v): Storevtox, withCMM_ACCESS_ONCE(x)semantics on the store and also with type checking. This is similar toCMM_ACCESS_ONCE(x) = v. -
DEFINE_URCU_TLS(type, name): Define a thread-local variable of typetypeof namename. Initializers are not permitted. This macro uses__threadwhere available, and falls back to POSIX get/set specific otherwise (as is also the case forDECLARE_URCU_TLS()andURCU_TLS()below). -
DECLARE_URCU_TLS(type, name): Declare a thread-local variable of typetypeof namenameso that other compilation units can access it. -
URCU_TLS(name): Access a thread-local variable. This produces a C-language lvalue, permitting both loads and stores. -
uatomic_set(addr, v): This is semantically equivalent to the assignment statement*addr = v, but with CMM_STORE_SHARED() semantics. Note that no ordering constraints are placed on the CPU. -
uatomic_read(addr): Load from*addrwith CMM_LOAD_SHARED() semantics. Note that no ordering constraints are placed on the CPU. -
uatomic_cmpxchg(addr, old, _new): Atomically compare the data referenced byaddrwithold, and storing_newif the two values compare equal, in either case returning the previous value referenced byaddr. This is a standard compare-and-swap operation, constraining both the compiler and the CPU to avoid optimizations that would reorder theuatomic_cmpxchg()with code either preceding or following it. -
uatomic_xchg(addr, v): Atomically store the valuevinto the location referenced byaddr, returning the prior value of the location referenced byaddr. This is the standard atomic-exchange operation, constraining both the compiler and the CPU to avoid optimizations that would reorder theuatomic_xchg()with code either preceding or following it. -
uatomic_and(addr, v): Atomically AND the valuevinto the location referenced byaddr. This operation does not return any value, and imposes no ordering constraints on either the compiler or the CPU (this follows the convention in the Linux kernel that ordering is provided only if the atomic primitive returns a value). If such constraints are desired, they may be provided usingcmm_smp_mb__before_uatomic_and()andcmm_smp_mb__after_uatomic_and(). -
uatomic_or(addr, v): Atomically OR the valuevinto the location referenced byaddr. This operation does not return any value, and imposes no ordering constraints on either the compiler or the CPU. If such constraints are desired, they may be provided usingcmm_smp_mb__before_uatomic_or()andcmm_smp_mb__after_uatomic_or(). -
uatomic_add_return(addr, v): Atomically addvto the location referenced byaddr, returning the result. This is a standard add-and-fetch operation, constraining both the compiler and the CPU to avoid optimizations that would reorder theuatomic_add_return()with code either preceding or following it. -
uatomic_add(addr, v): Atomically add the valuevto the location referenced byaddr. This operation does not return any value, and imposes no ordering constraints on either the compiler or the CPU. If such constraints are desired, they may be provided usingcmm_smp_mb__before_uatomic_add()andcmm_smp_mb__after_uatomic_add(). -
uatomic_inc(addr): Atomically increment the location referenced byaddr. This operation does not return any value, and imposes no ordering constraints on either the compiler or the CPU. If such constraints are desired, they may be provided usingcmm_smp_mb__before_uatomic_inc()andcmm_smp_mb__after_uatomic_inc(). -
uatomic_dec(addr): Atomically decrement the location referenced byaddr. This operation does not return any value, and imposes no ordering constraints on either the compiler or the CPU. If such constraints are desired, they may be provided usingcmm_smp_mb__before_uatomic_dec()andcmm_smp_mb__after_uatomic_dec().
Unlike the Linux kernel, userspace RCU's atomic operations are
type-generic, supporting multiple operand sizes.
In some cases, hardware will restrict the available sizes.
If 8-bit atomics are supported, the UATOMIC_HAS_ATOMIC_BYTE
C-preprocessor macro will be defined, and if 16-bit atomics are
supported, the UATOMIC_HAS_ATOMIC_SHORT macro will be
defined.
In addition, 32-bit implementations support 32-bit operands and
64-bit implementations support both 32-bit and 64-bit operands.
Therefore, atomic operations on ints and longs
are portable.
Finally, the operands for atomic operations must be properly aligned,
which means that you should not attempt to use atomic operations on
fields within packed structures.
Although these operations can be used directly, the intent is that
higher-level operations defined elsewhere in the library are intended
to be used in the common case.
Instead, these operations are provided primarily for use by the rest of
this library.
(Log in to post comments)
