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

Zephyr 3.7.0 · Kernel · Data Passing

Stack

정해진 수의 native-word integer 또는 pointer value를 LIFO 순서로 저장하고 thread·ISR에서 회수합니다.

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

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

Part 1

요약·해설

32·64-bit stack_data_t array, static·resource-pool buffer, full-stack 검사와 priority/oldest waiter 선택을 다룹니다.

Order

last in · first out

Value

native word

Capacity

fixed maximum

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 7BE88B6548E08A5099C7F6DF552FE43BF9B5F0A5D112D0BB9FAA245461CB39C6
.. _stacks_v2:

Stacks
######

A :dfn:`stack` is a kernel object that implements a traditional
last in, first out (LIFO) queue, allowing threads and ISRs
to add and remove a limited number of integer data values.

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

Concepts
********

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

A stack has the following key properties:

* A **queue** of integer data values that have been added but not yet removed.
  The queue is implemented using an array of stack_data_t values
  and must be aligned on a native word boundary.
  The stack_data_t type corresponds to the native word size i.e. 32 bits or
  64 bits depending on the CPU architecture and compilation mode.

* A **maximum quantity** of data values that can be queued in the array.

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

A data value can be **added** to a stack by a thread or an ISR.
The value is given directly to a waiting thread, if one exists;
otherwise the value is added to the LIFO's queue.

.. note::
    If :kconfig:option:`CONFIG_NO_RUNTIME_CHECKS` is enabled, the kernel will *not* detect
    and prevent attempts to add a data value to a stack that has already reached
    its maximum quantity of queued values. Adding a data value to a stack that is
    already full will result in array overflow, and lead to unpredictable behavior.

A data value may be **removed** from a stack by a thread.
If the stack's queue is empty a thread may choose to wait for it to be given.
Any number of threads may wait on an empty stack 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 stack, however
    the ISR must not attempt to wait if the stack is empty.

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

Defining a Stack
================

A stack is defined using a variable of type :c:struct:`k_stack`.
It must then be initialized by calling :c:func:`k_stack_init` or
:c:func:`k_stack_alloc_init`. In the latter case, a buffer is not
provided and it is instead allocated from the calling thread's resource
pool.

The following code defines and initializes an empty stack capable of holding
up to ten word-sized data values.

.. code-block:: c

    #define MAX_ITEMS 10

    stack_data_t my_stack_array[MAX_ITEMS];
    struct k_stack my_stack;

    k_stack_init(&my_stack, my_stack_array, MAX_ITEMS);

Alternatively, a stack can be defined and initialized at compile time
by calling :c:macro:`K_STACK_DEFINE`.

The following code has the same effect as the code segment above. Observe
that the macro defines both the stack and its array of data values.

.. code-block:: c

    K_STACK_DEFINE(my_stack, MAX_ITEMS);

Pushing to a Stack
==================

A data item is added to a stack by calling :c:func:`k_stack_push`.

The following code builds on the example above, and shows how a thread
can create a pool of data structures by saving their memory addresses
in a stack.

.. code-block:: c

    /* define array of data structures */
    struct my_buffer_type {
        int field1;
        ...
	};
    struct my_buffer_type my_buffers[MAX_ITEMS];

    /* save address of each data structure in a stack */
    for (int i = 0; i < MAX_ITEMS; i++) {
        k_stack_push(&my_stack, (stack_data_t)&my_buffers[i]);
    }

Popping from a Stack
====================

A data item is taken from a stack by calling :c:func:`k_stack_pop`.

The following code builds on the example above, and shows how a thread
can dynamically allocate an unused data structure.
When the data structure is no longer required, the thread must push
its address back on the stack to allow the data structure to be reused.

.. code-block:: c

    struct my_buffer_type *new_buffer;

    k_stack_pop(&buffer_stack, (stack_data_t *)&new_buffer, K_FOREVER);
    new_buffer->field1 = ...

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

Use a stack to store and retrieve integer data values in a "last in,
first out" manner, when the maximum number of stored items is known.

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

Related configuration options:

* None.

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

.. doxygengroup:: stack_apis

Part 3

한국어 전문 번역

Stack은 전통적인 last-in, first-out(LIFO) queue를 구현한 kernel object입니다. Thread와 ISR이 제한된 수의 integer data value를 추가하고 제거할 수 있습니다.

개념

사용 가능한 RAM 범위에서 원하는 수의 stack을 정의하고 memory 주소로 참조합니다.

Stack은 아직 제거하지 않은 integer value의 queue와 array가 보관할 최대 value 수를 가집니다. Queue는 stack_data_t array로 구현하며 native word boundary에 정렬해야 합니다. stack_data_t는 CPU architecture와 compilation mode에 따라 native word 크기인 32-bit 또는 64-bit입니다.

첫 사용 전 stack을 초기화하면 queue가 비게 됩니다.

Thread나 ISR이 value를 추가할 때 기다리는 thread가 있으면 그 thread에 직접 전달하고, 대기자가 없으면 LIFO queue에 넣습니다.

Thread는 stack에서 value를 제거할 수 있고 비어 있으면 value가 올 때까지 선택적으로 기다릴 수 있습니다. 여러 thread가 동시에 기다리면 priority가 가장 높은 thread 중 가장 오래 기다린 thread가 먼저 value를 받습니다.

구현

Stack 정의

struct k_stack variable을 정의한 뒤 k_stack_init() 또는 k_stack_alloc_init()으로 초기화합니다. Alloc variant는 caller resource pool에서 buffer를 할당합니다. 다음 stack은 word-size value 최대 10개를 담습니다.

#define MAX_ITEMS 10

stack_data_t my_stack_array[MAX_ITEMS];
struct k_stack my_stack;

k_stack_init(&my_stack, my_stack_array, MAX_ITEMS);

K_STACK_DEFINE macro는 stack과 value array를 함께 compile time에 정의하고 초기화합니다.

K_STACK_DEFINE(my_stack, MAX_ITEMS);

Stack에 push

k_stack_push()으로 item을 추가합니다. 다음 예제는 data structure array의 각 memory 주소를 stack에 저장해 재사용 가능한 object pool을 만듭니다.

/* define array of data structures */
struct my_buffer_type {
    int field1;
    ...
    };
struct my_buffer_type my_buffers[MAX_ITEMS];

/* save address of each data structure in a stack */
for (int i = 0; i < MAX_ITEMS; i++) {
    k_stack_push(&my_stack, (stack_data_t)&my_buffers[i]);
}

Stack에서 pop

k_stack_pop()으로 가장 나중에 넣은 item을 꺼냅니다. 다음 예제는 사용하지 않는 data structure 주소를 동적으로 얻습니다. Object가 더 필요 없으면 주소를 stack에 다시 push해 재사용할 수 있게 해야 합니다.

struct my_buffer_type *new_buffer;

k_stack_pop(&buffer_stack, (stack_data_t *)&new_buffer, K_FOREVER);
new_buffer->field1 = ...

권장 용도

저장할 최대 item 수를 알고 있을 때 integer data value를 last-in, first-out 순서로 저장하고 회수하는 데 사용합니다.

설정 옵션

이 문서에 관련 configuration option은 없습니다. 다만 CONFIG_NO_RUNTIME_CHECKS는 full-stack overflow 검출 여부에 영향을 줍니다.

API 참고: stack_apis

K_STACK_DEFINE(name, stack_num_entries)

Stack과 value array를 정적으로 정의하고 초기화합니다. 정의 module 밖에서는 아래 extern declaration으로 접근합니다.

extern struct k_stack <name>;

매개변수

  • name: stack 이름
  • stack_num_entries: stack에 저장할 최대 value 수
k_stack_init(stack, buffer, num_entries)

기존 array buffer를 사용하는 stack을 처음 사용하기 전에 초기화합니다.

매개변수

  • stack: stack 주소
  • buffer: stack value를 담는 array 주소
  • num_entries: 최대 value 수
k_stack_alloc_init(stack, num_entries)

호출 thread resource pool에서 내부 buffer를 할당해 stack을 초기화합니다. k_stack_cleanup()을 호출하거나 userspace에서 마지막 reference가 사라지면 memory가 해제됩니다.

매개변수

  • stack: stack 주소
  • num_entries: 최대 value 수

반환값

  • 0: 성공
  • -ENOMEM: memory 할당 실패
k_stack_cleanup(stack)

k_stack_alloc_init()이 동적으로 할당한 buffer를 해제합니다. 정적 buffer에는 아무 작업도 하지 않습니다.

매개변수

  • stack: stack 주소

반환값

  • 0: 성공
  • -EAGAIN: object가 아직 사용 중
k_stack_push(stack, data)

stack_data_t value를 stack top에 추가합니다. ISR에서도 호출할 수 있습니다.

매개변수

  • stack: stack 주소
  • data: push할 value

반환값

  • 0: 성공
  • -ENOMEM: stack이 가득 참
k_stack_pop(stack, data, timeout)

Stack에서 last-in, first-out 순서로 stack_data_t value를 제거하고 data 위치에 저장합니다. ISR에서는 timeout을 반드시 K_NO_WAIT로 설정해야 합니다.

매개변수

  • stack: stack 주소
  • data: pop한 value를 받을 주소
  • timeout: value 대기 시간, K_NO_WAIT 또는 K_FOREVER

반환값

  • 0: element pop 완료
  • -EBUSY: 기다리지 않고 반환
  • -EAGAIN: 대기 시간 만료

Source

출처

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