| .. _atomic_v2: |
| |
| Atomic Services |
| ############### |
| |
| An :dfn:`atomic variable` is one that can be read and modified |
| by threads and ISRs in an uninterruptible manner. It 32-bit on |
| 32-bit machines and 64-bit on 64-bit machines. |
| |
| .. contents:: |
| :local: |
| :depth: 2 |
| |
| 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 :c:type:`atomic_t`. |
| |
| By default an atomic variable is initialized to zero. However, it can be given |
| a different value using :c:macro:`ATOMIC_INIT`: |
| |
| .. code-block:: c |
| |
| 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 mid-increment if a thread calling the function is interrupted if |
| by a higher priority context that also calls the routine. |
| |
| .. code-block:: c |
| |
| 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 32-bit atomic variables can be defined in the conventional manner. |
| However, you can also define an N-bit array of atomic variables using |
| :c:macro:`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 :c:func:`_bit`. |
| |
| The following code shows how a set of 200 flag bits can be implemented |
| using an array of atomic variables. |
| |
| .. code-block:: c |
| |
| #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 |
| architecture-specific 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 32-bit 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: |
| |
| * :kconfig:option:`CONFIG_ATOMIC_OPERATIONS_BUILTIN` |
| * :kconfig:option:`CONFIG_ATOMIC_OPERATIONS_ARCH` |
| * :kconfig:option:`CONFIG_ATOMIC_OPERATIONS_C` |
| |
| API Reference |
| ************* |
| |
| .. important:: |
| All atomic services APIs can be used by both threads and ISRs. |
| |
| .. doxygengroup:: atomic_apis |