kernel/services/other/atomic.html · kernel/services/other/atomic.rst 공식 원문 ↗

Zephyr 3.7.0 · Kernel · Other Services

Atomic Service

Thread와 ISR 사이에서 native-word 값과 bit를 중단 없이 갱신하고 full memory ordering을 보장합니다.

Official pathkernel/services/other/atomic.html
Source filekernel/services/other/atomic.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

본문 기준: Zephyr 3.7.0 LTS3 · 이후 유지보수 패치는 별도입니다.

Part 1

요약·해설

Scalar·pointer compare-and-set, arithmetic·bitwise get-and-update, N-bit bitmap과 sequentially consistent barrier 계약을 다룹니다.

Width

32 · 64 bit native

Contexts

thread · ISR

Ordering

full barrier

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 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가 1
  • false: 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: 비교할 pointer
  • new_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

출처

영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.