kernel/services/data_passing/fifos.html · kernel/services/data_passing/fifos.rst 공식 원문 ↗

Zephyr 3.7.0 · Kernel · Data Passing

FIFO

임의 크기 item을 먼저 들어온 순서로 thread와 ISR 사이에 전달하고 list 단위 원자적 enqueue를 지원합니다.

Official pathkernel/services/data_passing/fifos.html
Source filekernel/services/data_passing/fifos.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

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

Part 1

요약·해설

첫 word reserved 방식과 alloc_put 방식, waiting-thread 직접 전달, priority/FIFO waiter 선택과 batch list insertion을 설명합니다.

Order

first in · first out

Waiters

priority · oldest

Batch

atomic list put

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 292B0ECB77F24F77944259BE43E60AD2D5994F7B307AD833401E4ACDF5C6A3A1
.. _fifos_v2:

FIFOs
#####

A :dfn:`FIFO` is a kernel object that implements a traditional
first in, first out (FIFO) queue, allowing threads and ISRs
to add and remove data items of any size.

.. contents::
    :local:
    :depth: 2

Concepts
********

Any number of FIFOs can be defined (limited only by available RAM). Each FIFO is
referenced by its memory address.

A FIFO has the following key properties:

* A **queue** of data items that have been added but not yet removed.
  The queue is implemented as a simple linked list.

A FIFO must be initialized before it can be used. This sets its queue to empty.

FIFO data items must be aligned on a word boundary, as the kernel reserves
the first word of an item for use as a pointer to the next data item in
the queue. Consequently, a data item that holds N bytes of application
data requires N+4 (or N+8) bytes of memory. There are no alignment or
reserved space requirements for data items if they are added with
:c:func:`k_fifo_alloc_put`, instead additional memory is temporarily
allocated from the calling thread's resource pool.

.. note::
    FIFO data items are restricted to single active instance across all FIFO
    data queues. Any attempt to re-add a FIFO data item to a queue before
    it has been removed from the queue to which it was previously added will
    result in undefined behavior.

A data item may be **added** to a FIFO by a thread or an ISR.
The item is given directly to a waiting thread, if one exists;
otherwise the item is added to the FIFO's queue.
There is no limit to the number of items that may be queued.

A data item may be **removed** from a FIFO by a thread. If the FIFO's queue
is empty a thread may choose to wait for a data item to be given.
Any number of threads may wait on an empty FIFO simultaneously.
When a data item is added, it is given to the highest priority thread
that has waited longest.

.. note::
    The kernel does allow an ISR to remove an item from a FIFO, however
    the ISR must not attempt to wait if the FIFO is empty.

If desired, **multiple data items** can be added to a FIFO in a single operation
if they are chained together into a singly-linked list. This capability can be
useful if multiple writers are adding sets of related data items to the FIFO,
as it ensures the data items in each set are not interleaved with other data
items. Adding multiple data items to a FIFO is also more efficient than adding
them one at a time, and can be used to guarantee that anyone who removes
the first data item in a set will be able to remove the remaining data items
without waiting.

Implementation
**************

Defining a FIFO
===============

A FIFO is defined using a variable of type :c:struct:`k_fifo`.
It must then be initialized by calling :c:func:`k_fifo_init`.

The following code defines and initializes an empty FIFO.

.. code-block:: c

    struct k_fifo my_fifo;

    k_fifo_init(&my_fifo);

Alternatively, an empty FIFO can be defined and initialized at compile time
by calling :c:macro:`K_FIFO_DEFINE`.

The following code has the same effect as the code segment above.

.. code-block:: c

    K_FIFO_DEFINE(my_fifo);

Writing to a FIFO
=================

A data item is added to a FIFO by calling :c:func:`k_fifo_put`.

The following code builds on the example above, and uses the FIFO
to send data to one or more consumer threads.

.. code-block:: c

    struct data_item_t {
        void *fifo_reserved;   /* 1st word reserved for use by FIFO */
        ...
    };

    struct data_item_t tx_data;

    void producer_thread(int unused1, int unused2, int unused3)
    {
        while (1) {
            /* create data item to send */
            tx_data = ...

            /* send data to consumers */
            k_fifo_put(&my_fifo, &tx_data);

            ...
        }
    }

Additionally, a singly-linked list of data items can be added to a FIFO
by calling :c:func:`k_fifo_put_list` or :c:func:`k_fifo_put_slist`.

Finally, a data item can be added to a FIFO with :c:func:`k_fifo_alloc_put`.
With this API, there is no need to reserve space for the kernel's use in
the data item, instead additional memory will be allocated from the calling
thread's resource pool until the item is read.

Reading from a FIFO
===================

A data item is removed from a FIFO by calling :c:func:`k_fifo_get`.

The following code builds on the example above, and uses the FIFO
to obtain data items from a producer thread,
which are then processed in some manner.

.. code-block:: c

    void consumer_thread(int unused1, int unused2, int unused3)
    {
        struct data_item_t  *rx_data;

        while (1) {
            rx_data = k_fifo_get(&my_fifo, K_FOREVER);

            /* process FIFO data item */
            ...
        }
    }

Suggested Uses
**************

Use a FIFO to asynchronously transfer data items of arbitrary size
in a "first in, first out" manner.

Configuration Options
*********************

Related configuration options:

* None

API Reference
*************

.. doxygengroup:: fifo_apis

Part 3

한국어 전문 번역

FIFO는 전통적인 first-in, first-out queue를 구현하는 kernel object입니다. Thread와 ISR이 임의 크기 data item을 추가할 수 있고 thread는 먼저 들어온 item부터 꺼냅니다.

개념

가용 RAM 범위 안에서 FIFO를 원하는 수만큼 정의하고 각각 memory 주소로 참조합니다. 핵심 상태는 아직 제거되지 않은 data item queue이며 simple linked list로 구현합니다. 첫 사용 전에 초기화하면 queue가 비어 있는 상태가 됩니다.

일반 FIFO item은 word boundary에 정렬해야 합니다. Kernel이 첫 word를 next-item pointer로 예약하므로 application data N byte를 담으려면 32-bit system에서는 N+4, 64-bit system에서는 N+8 byte가 필요합니다. k_fifo_alloc_put()을 쓰면 이 정렬·reserved-space 요구가 없지만 호출 thread resource pool에서 임시 metadata를 할당합니다.

Thread나 ISR이 item을 추가할 때 기다리는 thread가 있으면 queue에 넣지 않고 그 thread에 직접 전달합니다. 대기자가 없으면 queue tail에 추가하며 queued item 수에는 별도 제한이 없습니다.

Thread가 빈 FIFO에서 get을 호출하면 item이 생길 때까지 선택적으로 기다릴 수 있습니다. 여러 thread가 기다리면 priority가 가장 높은 thread가 먼저 받고, 같은 priority에서는 가장 오래 기다린 thread가 먼저 받습니다. ISR도 item을 제거할 수 있지만 빈 queue에서 절대 기다리면 안 됩니다.

Singly linked list로 묶은 여러 item을 한 operation으로 추가할 수도 있습니다. 여러 writer가 관련 item 집합을 넣을 때 다른 writer item과 중간에 섞이지 않으며, 하나씩 넣는 것보다 효율적입니다. 첫 item을 얻은 reader는 같은 집합의 나머지도 기다리지 않고 연속해서 얻을 수 있습니다.

구현

FIFO 정의

struct k_fifo variable을 만들고 k_fifo_init()으로 초기화합니다.

struct k_fifo my_fifo;

k_fifo_init(&my_fifo);

K_FIFO_DEFINE으로 compile time에 같은 효과를 낼 수도 있습니다.

K_FIFO_DEFINE(my_fifo);

FIFO에 쓰기

k_fifo_put()으로 item을 추가합니다. 다음 item type은 첫 word를 FIFO reserved pointer로 둡니다.

struct data_item_t {
    void *fifo_reserved;   /* 1st word reserved for use by FIFO */
    ...
};

struct data_item_t tx_data;

void producer_thread(int unused1, int unused2, int unused3)
{
    while (1) {
        /* create data item to send */
        tx_data = ...

        /* send data to consumers */
        k_fifo_put(&my_fifo, &tx_data);

        ...
    }
}

여러 item list는 k_fifo_put_list() 또는 k_fifo_put_slist()로 원자적으로 넣습니다. Reserved word 없이 넣으려면 k_fifo_alloc_put()을 사용하며 item을 읽을 때까지 임시 bookkeeping memory가 유지됩니다.

FIFO에서 읽기

k_fifo_get()으로 head item을 제거합니다. 다음 consumer는 item이 올 때까지 K_FOREVER로 기다립니다.

void consumer_thread(int unused1, int unused2, int unused3)
{
    struct data_item_t  *rx_data;

    while (1) {
        rx_data = k_fifo_get(&my_fifo, K_FOREVER);

        /* process FIFO data item */
        ...
    }
}

권장 용도

임의 크기 data item을 first-in, first-out 순서로 비동기 전달할 때 사용합니다.

설정 옵션

이 문서에 관련 configuration option은 없습니다.

API 참고: fifo_apis

k_fifo_init(fifo)

첫 사용 전에 FIFO queue를 빈 상태로 초기화합니다.

매개변수

  • fifo: FIFO queue 주소
k_fifo_cancel_wait(fifo)

FIFO에서 가장 먼저 pending 중인 thread가 있으면 k_fifo_get()에서 timeout이 끝난 것처럼 NULL을 받고 반환하게 합니다. ISR에서도 호출할 수 있습니다.

매개변수

  • fifo: FIFO queue 주소
k_fifo_put(fifo, data)

Data item을 FIFO에 넣습니다. Item은 word boundary에 정렬되어야 하고 첫 word는 kernel이 next pointer로 사용하도록 비워 둬야 합니다. ISR에서도 호출할 수 있습니다.

매개변수

  • fifo: FIFO 주소
  • data: data item 주소
k_fifo_alloc_put(fifo, data)

Data item 자체에 reserved word를 두지 않고 FIFO에 넣습니다. 호출 thread의 resource pool에서 임시 bookkeeping structure를 암시적으로 할당하며 item을 꺼낼 때 자동 해제합니다. Data 내용 자체는 복사하지 않습니다. ISR-ok 속성이 있지만 allocation이 필요하므로 호출 context의 resource pool 조건을 충족해야 합니다.

매개변수

  • fifo: FIFO 주소
  • data: data item 주소

반환값: 성공은 0, caller resource pool의 RAM이 부족하면 -ENOMEM입니다.

k_fifo_put_list(fifo, head, tail)

NULL로 끝나는 singly linked list 전체를 한 operation으로 FIFO에 원자적으로 추가합니다. 각 data item의 첫 word가 다음 item을 가리켜야 합니다. ISR에서도 호출할 수 있습니다.

매개변수

  • fifo: FIFO queue 주소
  • head: list 첫 node
  • tail: list 마지막 node
k_fifo_put_slist(fifo, list)

sys_slist_t로 구현된 data-item list를 한 operation으로 FIFO에 원자적으로 추가합니다. 완료 후 전달한 sys_slist_t object는 invalid가 되므로 다시 쓰기 전에 sys_slist_init()으로 초기화해야 합니다. ISR에서도 호출할 수 있습니다.

매개변수

  • fifo: FIFO queue 주소
  • list: sys_slist_t object pointer
k_fifo_get(fifo, timeout)

FIFO head item을 first-in, first-out 순서로 제거해 반환합니다. 첫 word는 kernel reserved 영역입니다. ISR에서 호출할 때 timeout은 반드시 K_NO_WAIT여야 합니다.

매개변수

  • fifo: FIFO queue 주소
  • timeout: 대기 시간, K_NO_WAIT 또는 K_FOREVER

반환값: 성공하면 data item 주소, 기다리지 않고 없거나 timeout이면 NULL입니다.

k_fifo_is_empty(fifo)

FIFO에 data가 있는지 검사합니다. 다른 thread도 읽는다면 함수가 반환하는 순간 이미 상태가 바뀔 수 있으므로 synchronization 판정으로 사용하면 안 됩니다. ISR에서도 호출할 수 있습니다.

매개변수

  • fifo: FIFO queue 주소

반환값: 비어 있으면 non-zero, data가 있으면 0입니다.

k_fifo_peek_head(fifo)

FIFO head element를 제거하지 않고 반환합니다. Element가 container일 때 head container 일부를 처리한 뒤 완전히 빌 때만 queue에서 제거하는 용도로 쓸 수 있습니다.

매개변수

  • fifo: FIFO queue 주소

반환값: Head element 또는 비어 있으면 NULL입니다.

k_fifo_peek_tail(fifo)

FIFO tail element를 제거하지 않고 반환합니다. Tail element가 container이면 마지막 container에 data를 더 붙이는 용도로 쓸 수 있습니다.

매개변수

  • fifo: FIFO queue 주소

반환값: Tail element 또는 비어 있으면 NULL입니다.

K_FIFO_DEFINE(name)

FIFO queue를 정적으로 정의하고 초기화합니다. 정의 module 밖에서는 다음 extern declaration으로 접근합니다.

extern struct k_fifo <name>;

매개변수

  • name: FIFO queue 이름

Source

출처

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