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

Zephyr 3.7.0 · Kernel · Data Passing

LIFO

임의 크기 item을 가장 나중에 들어온 순서로 전달하며 waiting thread가 있으면 queue를 거치지 않고 직접 넘깁니다.

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

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

Part 1

요약·해설

Fixed reserved word 또는 resource-pool metadata를 사용하고, get 대기자는 priority와 대기 시간 순으로 선택합니다.

Order

last in · first out

Layout

reserved first word

ISR

K_NO_WAIT get

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 949728295F67C63524DF9AB68B748E9E3B0B771BA523CE47F495F5B303EA2DC9
.. _lifos_v2:

LIFOs
#####

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

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

Concepts
********

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

A LIFO 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 LIFO must be initialized before it can be used. This sets its queue to empty.

LIFO 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_lifo_alloc_put`, instead additional memory is temporarily
allocated from the calling thread's resource pool.

.. note::
    LIFO data items are restricted to single active instance across all LIFO
    data queues. Any attempt to re-add a LIFO 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 LIFO 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 LIFO's queue.
There is no limit to the number of items that may be queued.

A data item may be **removed** from a LIFO by a thread. If the LIFO'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 LIFO 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 LIFO, however
    the ISR must not attempt to wait if the LIFO is empty.

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

Defining a LIFO
===============

A LIFO is defined using a variable of type :c:struct:`k_lifo`.
It must then be initialized by calling :c:func:`k_lifo_init`.

The following defines and initializes an empty LIFO.

.. code-block:: c

    struct k_lifo my_lifo;

    k_lifo_init(&my_lifo);

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

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

.. code-block:: c

    K_LIFO_DEFINE(my_lifo);

Writing to a LIFO
=================

A data item is added to a LIFO by calling :c:func:`k_lifo_put`.

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

.. code-block:: c

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

    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_lifo_put(&my_lifo, &tx_data);

            ...
        }
    }

A data item can be added to a LIFO with :c:func:`k_lifo_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 LIFO
===================

A data item is removed from a LIFO by calling :c:func:`k_lifo_get`.

The following code builds on the example above, and uses the LIFO
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_lifo_get(&my_lifo, K_FOREVER);

            /* process LIFO data item */
            ...
        }
    }

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

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

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

Related configuration options:

* None.

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

.. doxygengroup:: lifo_apis

Part 3

한국어 전문 번역

LIFO는 전통적인 last-in, first-out queue를 구현하는 kernel object입니다. Thread와 ISR이 임의 크기 data item을 넣고 가장 나중에 들어온 item부터 꺼냅니다.

개념

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

일반 item은 word boundary에 정렬하고 kernel용 next pointer로 첫 word를 예약해야 합니다. Application data N byte에는 N+4 또는 N+8 byte가 필요합니다. k_lifo_alloc_put()은 reserved space 없이 쓸 수 있지만 calling thread resource pool에서 임시 metadata를 할당합니다.

Thread나 ISR이 item을 넣을 때 기다리는 thread가 있으면 item을 직접 전달하고, 없으면 LIFO top에 추가합니다. Queue item 수에는 별도 제한이 없습니다.

Thread는 빈 LIFO에서 item을 선택적으로 기다릴 수 있습니다. 여러 대기자 중 priority가 가장 높고, 같다면 가장 오래 기다린 thread가 먼저 받습니다. ISR get도 허용되지만 빈 queue에서 기다리면 안 됩니다.

구현

LIFO 정의

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

struct k_lifo my_lifo;

k_lifo_init(&my_lifo);

K_LIFO_DEFINE으로 compile time에 같은 효과를 냅니다.

K_LIFO_DEFINE(my_lifo);

LIFO에 쓰기

k_lifo_put()으로 item을 top에 추가합니다.

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

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_lifo_put(&my_lifo, &tx_data);

        ...
    }
}

k_lifo_alloc_put()을 쓰면 item에 kernel reserved word를 두지 않고, 읽힐 때까지 resource pool의 임시 bookkeeping을 사용합니다.

LIFO에서 읽기

k_lifo_get()으로 top 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_lifo_get(&my_lifo, K_FOREVER);

        /* process LIFO data item */
        ...
    }
}

권장 용도

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

설정 옵션

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

API 참고: lifo_apis

k_lifo_init(lifo)

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

매개변수

  • lifo: LIFO queue 주소
k_lifo_put(lifo, data)

Data item을 LIFO top에 넣습니다. Item은 word boundary에 정렬되고 첫 word는 kernel용 next pointer로 예약해야 합니다. ISR에서도 호출할 수 있습니다.

매개변수

  • lifo: LIFO queue 주소
  • data: data item 주소
k_lifo_alloc_put(lifo, data)

Reserved word가 없는 item을 LIFO에 넣습니다. 호출 thread resource pool에서 임시 bookkeeping structure를 할당해 item이 제거될 때 자동 해제하며 data 자체는 복사하지 않습니다. ISR-ok 속성이지만 resource-pool allocation 조건을 만족해야 합니다.

매개변수

  • lifo: LIFO 주소
  • data: data item 주소

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

k_lifo_get(lifo, timeout)

가장 나중에 들어온 top item을 last-in, first-out 순서로 제거합니다. Item 첫 word는 kernel reserved 영역이며 ISR에서는 timeout을 반드시 K_NO_WAIT로 설정해야 합니다.

매개변수

  • lifo: LIFO queue 주소
  • timeout: 대기 시간, K_NO_WAIT 또는 K_FOREVER

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

K_LIFO_DEFINE(name)

LIFO queue를 정적으로 정의하고 초기화합니다. 정의 module 밖에서는 다음 extern declaration으로 접근합니다. 생성 문서의 parameter 설명은 이름을 FIFO라고 쓰지만 대상은 LIFO입니다.

extern struct k_lifo <name>;

매개변수

  • name: LIFO queue 이름

Source

출처

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