Part 1
요약·해설
Scalar·pointer compare-and-set, arithmetic·bitwise get-and-update, N-bit bitmap과 sequentially consistent barrier 계약을 다룹니다.
32 · 64 bit native
thread · ISR
full barrier
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
501F421C7B37CD41CE1E5B56D76F9B9ED52FA2D70823F7FDBCF30DF95A707929
.. _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 is a 32-bit variable on
32-bit machines and a 64-bit variable 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
Part 3
한국어 전문 번역
Atomic variable은 thread와 ISR이 중단 불가능한 방식으로 읽고 수정할 수 있는 값입니다. 32-bit machine에서는 32-bit, 64-bit machine에서는 64-bit variable입니다.
개념
사용 가능한 RAM 범위에서 원하는 수의 atomic variable을 정의할 수 있습니다.
Kernel atomic API로 값을 조작하면 더 높은 priority context가 같은 variable을 동시에 다루더라도 원하는 operation이 올바르게 완료됩니다.
Kernel은 atomic variable array 안의 bit 하나도 원자적으로 조작할 수 있습니다.
구현
Atomic variable 정의
atomic_t 형식으로 정의합니다. 기본값은 0이며 ATOMIC_INIT으로 다른 초기값을 줄 수 있습니다.
atomic_t flags = ATOMIC_INIT(0xFF);Atomic variable 조작
문서 끝의 API로 조작합니다. 다음 code는 function 호출 횟수를 셉니다. Increment가 atomic하므로 routine 실행 중 더 높은 priority context가 같은 routine을 호출해도 중간 값이 손상되지 않습니다.
atomic_t call_count;
int call_counting_routine(void)
{
/* increment invocation counter */
atomic_inc(&call_count);
/* do rest of routine's processing */
...
}Atomic variable array 조작
32-bit atomic variable array를 일반 방식으로 정의할 수도 있고 ATOMIC_DEFINE으로 N-bit array를 정의할 수도 있습니다. 이름이 _bit로 끝나는 API가 array의 bit 하나를 조작합니다.
다음 code는 atomic variable array로 flag bit 200개를 구현합니다.
#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
일관성과 정확성을 위해 모든 Zephyr atomic API는 context 사이에서 신뢰할 수 있는 memory view를 보장하는 데 hardware가 요구하는 full memory barrier를 포함해야 합니다. x86 serializing instruction, ARM DMB 또는 C++ memory model의 sequentially consistent operation에 해당하며 architecture-specific 구현이 이 동작을 책임집니다.
권장 용도
32-bit 값 하나만 조작하면 되는 critical section에는 atomic variable을 사용합니다.
32 bit보다 긴 bit array의 flag 집합을 다루는 critical section에는 여러 atomic variable을 사용합니다.
설정 옵션
CONFIG_ATOMIC_OPERATIONS_BUILTIN: compiler builtin 기반 구현을 선택합니다.CONFIG_ATOMIC_OPERATIONS_ARCH: architecture 전용 구현을 선택합니다.CONFIG_ATOMIC_OPERATIONS_C: C 구현을 선택합니다.
API 참고: atomic_apis
ATOMIC_INIT(i)Atomic variable을 지정 값으로 초기화합니다.
atomic_t my_var = ATOMIC_INIT(75);매개변수
i: atomic variable에 넣을 값
ATOMIC_PTR_INIT(p)Atomic pointer variable을 지정 pointer로 초기화합니다.
atomic_ptr_t my_ptr = ATOMIC_PTR_INIT(&data);매개변수
p: atomic pointer에 넣을 값
ATOMIC_BITMAP_SIZE(num_bits)num_bits를 표현하는 bitmap에 필요한 atomic variable 수를 계산합니다.
매개변수
num_bits: bit 수
ATOMIC_DEFINE(name, num_bits)최소 num_bits를 포함하는 atomic variable array를 정의합니다. File scope에서는 bit를 0으로 초기화하지만 function 내부에서는 초기화하지 않습니다.
매개변수
name: array 이름num_bits: 필요한 bit 수
atomic_test_bit(target, bit)지정 bit의 현재 설정 여부를 원자적으로 검사합니다.
매개변수
target: atomic variable 또는 array 주소bit: 0부터 시작하는 bit 번호
반환값
true: bit가 1false: bit가 0
atomic_test_and_clear_bit(target, bit)지정 bit를 원자적으로 0으로 바꾸고 이전 값을 반환합니다.
매개변수
target: atomic variable 또는 array 주소bit: 0부터 시작하는 bit 번호
반환값
false: 이미 0이었음true: 이전에는 1이었음
atomic_test_and_set_bit(target, bit)지정 bit를 원자적으로 1로 바꾸고 이전 값을 반환합니다.
매개변수
target: atomic variable 또는 array 주소bit: 0부터 시작하는 bit 번호
반환값
true: 이미 1이었음false: 이전에는 0이었음
atomic_clear_bit(target, bit)지정 bit를 원자적으로 0으로 만듭니다.
매개변수
target: atomic variable 또는 array 주소bit: 0부터 시작하는 bit 번호
atomic_set_bit(target, bit)지정 bit를 원자적으로 1로 만듭니다.
매개변수
target: atomic variable 또는 array 주소bit: 0부터 시작하는 bit 번호
atomic_set_bit_to(target, bit, val)지정 bit를 val에 따라 1 또는 0으로 원자적으로 설정합니다.
매개변수
target: atomic variable 또는 array 주소bit: 0부터 시작하는 bit 번호
매개변수
val: true이면 1, false이면 0
atomic_cas(target, old_value, new_value)현재 값이 old_value와 같을 때만 new_value를 원자적으로 씁니다. 다르면 변경하지 않습니다.
매개변수
target: atomic variable 주소old_value: 비교할 기존 값new_value: 저장할 새 값
반환값
true: 새 값 기록false: 비교 불일치
atomic_ptr_cas(target, old_value, new_value)Pointer 값을 대상으로 compare-and-set을 수행합니다.
매개변수
target: atomic pointer 주소old_value: 비교할 pointernew_value: 저장할 pointer
반환값
true: 새 pointer 기록false: 비교 불일치
atomic_add(target, value)value를 원자적으로 더하고 연산 전 값을 반환합니다.
매개변수
target: atomic variable 주소value: 더할 값
반환값
previous value: target의 연산 전 값
atomic_sub(target, value)value를 원자적으로 빼고 연산 전 값을 반환합니다.
매개변수
target: atomic variable 주소value: 뺄 값
반환값
previous value: target의 연산 전 값
atomic_inc(target)target을 원자적으로 1 증가시키고 이전 값을 반환합니다.
매개변수
target: atomic variable 주소
반환값
previous value: 증가 전 값
atomic_dec(target)target을 원자적으로 1 감소시키고 이전 값을 반환합니다.
매개변수
target: atomic variable 주소
반환값
previous value: 감소 전 값
atomic_get(target)Atomic variable을 원자적으로 읽습니다.
매개변수
target: atomic variable 주소
반환값
value: 현재 값
atomic_ptr_get(target)Atomic pointer를 원자적으로 읽습니다.
매개변수
target: atomic pointer 주소
반환값
value: 현재 pointer
atomic_set(target, value)target에 value를 원자적으로 쓰고 이전 값을 반환합니다.
매개변수
target: atomic variable 주소value: 새 값
반환값
previous value: 쓰기 전 값
atomic_ptr_set(target, value)Atomic pointer에 새 값을 쓰고 이전 pointer를 반환합니다.
매개변수
target: atomic pointer 주소value: 새 pointer
반환값
previous value: 쓰기 전 pointer
atomic_clear(target)target을 원자적으로 0으로 만들고 이전 값을 반환합니다. atomic_set(target, 0)과 같습니다.
매개변수
target: atomic variable 주소
반환값
previous value: clear 전 값
atomic_ptr_clear(target)Atomic pointer를 원자적으로 0으로 만들고 이전 pointer를 반환합니다.
매개변수
target: atomic pointer 주소
반환값
previous value: clear 전 pointer
atomic_or(target, value)target과 value의 inclusive OR를 원자적으로 기록하고 이전 target을 반환합니다.
매개변수
target: atomic variable 주소value: OR operand
반환값
previous value: 연산 전 값
atomic_xor(target, value)target과 value의 exclusive OR(XOR)를 원자적으로 기록하고 이전 target을 반환합니다.
매개변수
target: atomic variable 주소value: XOR operand
반환값
previous value: 연산 전 값
atomic_and(target, value)target과 value의 bitwise AND를 원자적으로 기록하고 이전 target을 반환합니다.
매개변수
target: atomic variable 주소value: AND operand
반환값
previous value: 연산 전 값
atomic_nand(target, value)target = ~(target & value)에 해당하는 bitwise NAND를 원자적으로 기록하고 이전 target을 반환합니다.
매개변수
target: atomic variable 주소value: NAND operand
반환값
previous value: 연산 전 값
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.