Atomic Services
An atomic variable is one that can be read and modified by threads and ISRs in an uninterruptible manner. It is a 32bit variable on 32bit machines and a 64bit variable on 64bit machines.
Concepts
Any number of atomic variables can be defined (limited only by available RAM).
Using the kernel’s atomic APIs to manipulate an atomic variable guarantees that the desired operation occurs correctly, even if higher priority contexts also manipulate the same variable.
The kernel also supports the atomic manipulation of a single bit in an array of atomic variables.
Implementation
Defining an Atomic Variable
An atomic variable is defined using a variable of type atomic_t
.
By default an atomic variable is initialized to zero. However, it can be given
a different value using ATOMIC_INIT
:
atomic_t flags = ATOMIC_INIT(0xFF);
Manipulating an Atomic Variable
An atomic variable is manipulated using the APIs listed at the end of this section.
The following code shows how an atomic variable can be used to keep track of the number of times a function has been invoked. Since the count is incremented atomically, there is no risk that it will become corrupted in midincrement if a thread calling the function is interrupted if by a higher priority context that also calls the routine.
atomic_t call_count;
int call_counting_routine(void)
{
/* increment invocation counter */
atomic_inc(&call_count);
/* do rest of routine's processing */
...
}
Manipulating an Array of Atomic Variables
An array of 32bit atomic variables can be defined in the conventional manner.
However, you can also define an Nbit array of atomic variables using
ATOMIC_DEFINE
.
A single bit in array of atomic variables can be manipulated using
the APIs listed at the end of this section that end with _bit()
.
The following code shows how a set of 200 flag bits can be implemented using an array of atomic variables.
#define NUM_FLAG_BITS 200
ATOMIC_DEFINE(flag_bits, NUM_FLAG_BITS);
/* set specified flag bit & return its previous value */
int set_flag_bit(int bit_position)
{
return (int)atomic_set_bit(flag_bits, bit_position);
}
Memory Ordering
For consistency and correctness, all Zephyr atomic APIs are expected to include a full memory barrier (in the sense of e.g. “serializing” instructions on x86, “DMB” on ARM, or a “sequentially consistent” operation as defined by the C++ memory model) where needed by hardware to guarantee a reliable picture across contexts. Any architecturespecific implementations are responsible for ensuring this behavior.
Suggested Uses
Use an atomic variable to implement critical section processing that only requires the manipulation of a single 32bit value.
Use multiple atomic variables to implement critical section processing on a set of flag bits in a bit array longer than 32 bits.
Note
Using atomic variables is typically far more efficient than using other techniques to implement critical sections such as using a mutex or locking interrupts.
Configuration Options
Related configuration options:
API Reference
Important
All atomic services APIs can be used by both threads and ISRs.
 group atomic_apis
Defines

ATOMIC_INIT(i)
Initialize an atomic variable.
This macro can be used to initialize an atomic variable. For example,
atomic_t my_var = ATOMIC_INIT(75);
 Parameters:
i – Value to assign to atomic variable.

ATOMIC_PTR_INIT(p)
Initialize an atomic pointer variable.
This macro can be used to initialize an atomic pointer variable. For example,
atomic_ptr_t my_ptr = ATOMIC_PTR_INIT(&data);
 Parameters:
p – Pointer value to assign to atomic pointer variable.

ATOMIC_BITMAP_SIZE(num_bits)
This macro computes the number of atomic variables necessary to represent a bitmap with num_bits.
 Parameters:
num_bits – Number of bits.

ATOMIC_DEFINE(name, num_bits)
Define an array of atomic variables.
This macro defines an array of atomic variables containing at least num_bits bits.
Note
If used from file scope, the bits of the array are initialized to zero; if used from within a function, the bits are left uninitialized.
 Parameters:
name – Name of array of atomic variables.
num_bits – Number of bits needed.
Functions

static inline bool atomic_test_bit(const atomic_t *target, int bit)
Atomically test a bit.
This routine tests whether bit number bit of target is set or not. The target may be a single atomic variable or an array of them.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable or array.
bit – Bit number (starting from 0).
 Returns:
true if the bit was set, false if it wasn’t.

static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit)
Atomically test and clear a bit.
Atomically clear bit number bit of target and return its old value. The target may be a single atomic variable or an array of them.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable or array.
bit – Bit number (starting from 0).
 Returns:
false if the bit was already cleared, true if it wasn’t.

static inline bool atomic_test_and_set_bit(atomic_t *target, int bit)
Atomically set a bit.
Atomically set bit number bit of target and return its old value. The target may be a single atomic variable or an array of them.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable or array.
bit – Bit number (starting from 0).
 Returns:
true if the bit was already set, false if it wasn’t.

static inline void atomic_clear_bit(atomic_t *target, int bit)
Atomically clear a bit.
Atomically clear bit number bit of target. The target may be a single atomic variable or an array of them.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable or array.
bit – Bit number (starting from 0).

static inline void atomic_set_bit(atomic_t *target, int bit)
Atomically set a bit.
Atomically set bit number bit of target. The target may be a single atomic variable or an array of them.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable or array.
bit – Bit number (starting from 0).

static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
Atomically set a bit to a given value.
Atomically set bit number bit of target to value val. The target may be a single atomic variable or an array of them.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable or array.
bit – Bit number (starting from 0).
val – true for 1, false for 0.

bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value)
Atomic compareandset.
This routine performs an atomic compareandset on target. If the current value of target equals old_value, target is set to new_value. If the current value of target does not equal old_value, target is left unchanged.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
old_value – Original value to compare against.
new_value – New value to store.
 Returns:
true if new_value is written, false otherwise.

bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, atomic_ptr_val_t new_value)
Atomic compareandset with pointer values.
This routine performs an atomic compareandset on target. If the current value of target equals old_value, target is set to new_value. If the current value of target does not equal old_value, target is left unchanged.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
old_value – Original value to compare against.
new_value – New value to store.
 Returns:
true if new_value is written, false otherwise.

atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
Atomic addition.
This routine performs an atomic addition on target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to add.
 Returns:
Previous value of target.

atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
Atomic subtraction.
This routine performs an atomic subtraction on target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to subtract.
 Returns:
Previous value of target.

atomic_val_t atomic_inc(atomic_t *target)
Atomic increment.
This routine performs an atomic increment by 1 on target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
 Returns:
Previous value of target.

atomic_val_t atomic_dec(atomic_t *target)
Atomic decrement.
This routine performs an atomic decrement by 1 on target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
 Returns:
Previous value of target.

atomic_val_t atomic_get(const atomic_t *target)
Atomic get.
This routine performs an atomic read on target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
 Returns:
Value of target.

atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target)
Atomic get a pointer value.
This routine performs an atomic read on target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of pointer variable.
 Returns:
Value of target.

atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
Atomic getandset.
This routine atomically sets target to value and returns the previous value of target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to write to target.
 Returns:
Previous value of target.

atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value)
Atomic getandset for pointer values.
This routine atomically sets target to value and returns the previous value of target.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to write to target.
 Returns:
Previous value of target.

atomic_val_t atomic_clear(atomic_t *target)
Atomic clear.
This routine atomically sets target to zero and returns its previous value. (Hence, it is equivalent to atomic_set(target, 0).)
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
 Returns:
Previous value of target.

atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target)
Atomic clear of a pointer value.
This routine atomically sets target to zero and returns its previous value. (Hence, it is equivalent to atomic_set(target, 0).)
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
 Returns:
Previous value of target.

atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
Atomic bitwise inclusive OR.
This routine atomically sets target to the bitwise inclusive OR of target and value.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to OR.
 Returns:
Previous value of target.

atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
Atomic bitwise exclusive OR (XOR).
This routine atomically sets target to the bitwise exclusive OR (XOR) of target and value.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to XOR
 Returns:
Previous value of target.

atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
Atomic bitwise AND.
This routine atomically sets target to the bitwise AND of target and value.
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to AND.
 Returns:
Previous value of target.

atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
Atomic bitwise NAND.
This routine atomically sets target to the bitwise NAND of target and value. (This operation is equivalent to target = ~(target & value).)
Note
As for all atomic APIs, includes a full/sequentiallyconsistent memory barrier (where applicable).
 Parameters:
target – Address of atomic variable.
value – Value to NAND.
 Returns:
Previous value of target.

ATOMIC_INIT(i)