kernel/data_structures/ring_buffers.html · kernel/data_structures/ring_buffers.rst 공식 원문 ↗

Zephyr 3.7.0 · Kernel · Data Structures

Ring Buffers

FIFO circular buffer에서 복사 API와 zero-copy에 가까운 claim/finish API를 용도에 맞게 사용합니다.

Official pathkernel/data_structures/ring_buffers.html
Source filekernel/data_structures/ring_buffers.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

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

Part 1

요약·해설

Byte mode는 부분 복사와 직접 memory claim을 지원하고, item mode는 metadata를 가진 32-bit word item 전체를 원자적 단위로 처리합니다.

Byte mode

put/get · claim/finish

Item mode

32-bit words · metadata

Concurrency

Caller-managed

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 AAA797EBC506163F2D8C7D749E8BAE5EDC1B3655D8BF5AAFA6A29C2A8C034122
.. _ring_buffers_v2:

Ring Buffers
############

A :dfn:`ring buffer` is a circular buffer, whose contents are stored in
first-in-first-out order.

For circumstances where an application needs to implement asynchronous
"streaming" copying of data, Zephyr provides a ``struct ring_buf``
abstraction to manage copies of such data in and out of a shared
buffer of memory.

Two content data modes are supported:

* **Byte mode**: raw bytes can be enqueued and dequeued.

* **Data item mode**: Multiple 32-bit word data items with metadata
  can be enqueued and dequeued from the ring buffer in
  chunks of up to 1020 bytes.  Each data item also has two
  associated metadata values:  a type identifier and a 16-bit
  integer value, both of which are application-specific.

While the underlying data structure is the same, it is not
legal to mix these two modes on a single ring buffer instance.  A ring
buffer initialized with a byte count must be used only with the
"bytes" API, one initialized with a word count must use the "items"
calls.


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

Concepts
********

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

A ring buffer has the following key properties:

* A **data buffer** of bytes or 32-bit words. The data buffer contains the raw
  bytes or 32-bit words that have been added to the ring buffer but not yet
  removed.

* A **data buffer size**, measured in bytes or 32-bit words. This governs
  the maximum amount of data (including possible metadata values) the ring
  buffer can hold.

A ring buffer must be initialized before it can be used. This sets its
data buffer to empty.

A ``struct ring_buf`` may be placed anywhere in user-accessible
memory, and must be initialized with :c:func:`ring_buf_init` or
:c:func:`ring_buf_item_init` before use. This must be provided a region
of user-controlled memory for use as the buffer itself.  Note carefully that the units of the size of the
buffer passed change (either bytes or words) depending on how the ring
buffer will be used later.  Macros for combining these steps in a
single static declaration exist for convenience.
:c:macro:`RING_BUF_DECLARE` will declare and statically initialize a ring
buffer with a specified byte count, where
:c:macro:`RING_BUF_ITEM_DECLARE` will declare and statically
initialize a buffer with a given count of 32 bit words.
:c:macro:`RING_BUF_ITEM_SIZEOF` will compute the size in 32-bit words
corresponding to a type or an expression.  Note: rounds up if the size is
not a multiple of 32 bits.

"Bytes" data may be copied into the ring buffer using
:c:func:`ring_buf_put`, passing a data pointer and byte count.  These
bytes will be copied into the buffer in order, as many as will fit in
the allocated buffer.  The total number of bytes copied (which may be
fewer than provided) will be returned.  Likewise :c:func:`ring_buf_get`
will copy bytes out of the ring buffer in the order that they were
written, into a user-provided buffer, returning the number of bytes
that were transferred.

To avoid multiply-copied-data situations, a "claim" API exists for
byte mode.  :c:func:`ring_buf_put_claim` takes a byte size value from the
user and returns a pointer to memory internal to the ring buffer that
can be used to receive those bytes, along with a size of the
contiguous internal region (which may be smaller than requested).  The
user can then copy data into that region at a later time without
assembling all the bytes in a single region first.  When complete,
:c:func:`ring_buf_put_finish` can be used to signal the buffer that the
transfer is complete, passing the number of bytes actually
transferred.  At this point a new transfer can be initiated.
Similarly, :c:func:`ring_buf_get_claim` returns a pointer to internal ring
buffer data from which the user can read without making a verbatim
copy, and :c:func:`ring_buf_get_finish` signals the buffer with how many
bytes have been consumed and allows for a new transfer to begin.

"Items" mode works similarly to bytes mode, except that all transfers
are in units of 32 bit words and all memory is assumed to be aligned
on 32 bit boundaries.  The write and read operations are
:c:func:`ring_buf_item_put` and :c:func:`ring_buf_item_get`, and work
otherwise identically to the bytes mode APIs.  There no "claim" API
provided for items mode.  One important difference is that unlike
:c:func:`ring_buf_put`, :c:func:`ring_buf_item_put` will not do a partial
transfer; it will return an error in the case where the provided data
does not fit in its entirety.

The user can manage the capacity of a ring buffer without modifying it
using either :c:func:`ring_buf_space_get` or :c:func:`ring_buf_item_space_get`
which returns the number of free bytes or free 32-bit item words respectively,
or by testing the :c:func:`ring_buf_is_empty` predicate.

Finally, a :c:func:`ring_buf_reset` call exists to immediately empty a
ring buffer, discarding the tracking of any bytes or items already
written to the buffer.  It does not modify the memory contents of the
buffer itself, however.


Byte mode
=========

A **byte mode** ring buffer instance is declared using
:c:macro:`RING_BUF_DECLARE()` and accessed using:
:c:func:`ring_buf_put_claim`, :c:func:`ring_buf_put_finish`,
:c:func:`ring_buf_get_claim`, :c:func:`ring_buf_get_finish`,
:c:func:`ring_buf_put` and :c:func:`ring_buf_get`.

Data can be copied into the ring buffer (see
:c:func:`ring_buf_put`) or ring buffer memory can be used
directly by the user. In the latter case, the operation is split into three stages:

1. allocating the buffer (:c:func:`ring_buf_put_claim`) when
   user requests the destination location where data can be written.
#. writing the data by the user (e.g. buffer written by DMA).
#. indicating the amount of data written to the provided buffer
   (:c:func:`ring_buf_put_finish`). The amount
   can be less than or equal to the allocated amount.

Data can be retrieved from a ring buffer through copying
(see :c:func:`ring_buf_get`) or accessed directly by address. In the latter
case, the operation is split into three stages:

1. retrieving source location with valid data written to a ring buffer
   (see :c:func:`ring_buf_get_claim`).
#. processing data
#. freeing processed data (see :c:func:`ring_buf_get_finish`).
   The amount freed can be less than or equal or to the retrieved amount.

Data item mode
==============

A **data item mode** ring buffer instance is declared using
:c:macro:`RING_BUF_ITEM_DECLARE()` and accessed using
:c:func:`ring_buf_item_put` and :c:func:`ring_buf_item_get`.

A ring buffer **data item** is an array of 32-bit words from 0 to 1020 bytes
in length. When a data item is **enqueued** (:c:func:`ring_buf_item_put`)
its contents are copied to the data buffer, along with its associated metadata
values (which occupy one additional 32-bit word). If the ring buffer has
insufficient space to hold the new data item the enqueue operation fails.

A data item is **dequeued** (:c:func:`ring_buf_item_get`) from a ring
buffer by removing the oldest enqueued item. The contents of the dequeued data
item, as well as its two metadata values, are copied to areas supplied by the
retriever. If the ring buffer is empty, or if the data array supplied by the
retriever is not large enough to hold the data item's data, the dequeue
operation fails.

Concurrency
===========

The ring buffer APIs do not provide any concurrency control.
Depending on usage (particularly with respect to number of concurrent
readers/writers) applications may need to protect the ring buffer with
mutexes and/or use semaphores to notify consumers that there is data to
read.

For the trivial case of one producer and one consumer, concurrency
control shouldn't be needed.

Internal Operation
==================

Data streamed through a ring buffer is always written to the next byte
within the buffer, wrapping around to the first element after reaching
the end, thus the "ring" structure.  Internally, the ``struct
ring_buf`` contains its own buffer pointer and its size, and also a
set of "head" and "tail" indices representing where the next read and write
operations may occur.

This boundary is invisible to the user using the normal put/get APIs,
but becomes a barrier to the "claim" API, because obviously no
contiguous region can be returned that crosses the end of the buffer.
This can be surprising to application code, and produce performance
artifacts when transfers need to happen close to the end of the
buffer, as the number of calls to claim/finish needs to double for such
transfers.


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

Defining a Ring Buffer
======================

A ring buffer is defined using a variable of type :c:struct:`ring_buf`.
It must then be initialized by calling :c:func:`ring_buf_init` or
:c:func:`ring_buf_item_init`.

The following code defines and initializes an empty **data item mode** ring
buffer (which is part of a larger data structure). The ring buffer's data buffer
is capable of holding 64 words of data and metadata information.

.. code-block:: c

    #define MY_RING_BUF_WORDS 64

    struct my_struct {
        struct ring_buf rb;
        uint32_t buffer[MY_RING_BUF_WORDS];
        ...
    };
    struct my_struct ms;

    void init_my_struct {
        ring_buf_item_init(&ms.rb, MY_RING_BUF_WORDS, ms.buffer);
        ...
    }

Alternatively, a ring buffer can be defined and initialized at compile time
using one of two macros at file scope. Each macro defines both the ring
buffer itself and its data buffer.

The following code defines a **data item mode** ring buffer:

.. code-block:: c

    #define MY_RING_BUF_WORDS 93
    RING_BUF_ITEM_DECLARE(my_ring_buf, MY_RING_BUF_WORDS);

The following code defines a ring buffer intended to be used for raw bytes:

.. code-block:: c

    #define MY_RING_BUF_BYTES 93
    RING_BUF_DECLARE(my_ring_buf, MY_RING_BUF_BYTES);

Enqueuing Data
==============

Bytes are copied to a **byte mode** ring buffer by calling
:c:func:`ring_buf_put`.

.. code-block:: c

    uint8_t my_data[MY_RING_BUF_BYTES];
    uint32_t ret;

    ret = ring_buf_put(&ring_buf, my_data, MY_RING_BUF_BYTES);
    if (ret != MY_RING_BUF_BYTES) {
        /* not enough room, partial copy. */
	...
    }

Data can be added to a **byte mode** ring buffer by directly accessing the
ring buffer's memory.  For example:

.. code-block:: c

    uint32_t size;
    uint32_t rx_size;
    uint8_t *data;
    int err;

    /* Allocate buffer within a ring buffer memory. */
    size = ring_buf_put_claim(&ring_buf, &data, MY_RING_BUF_BYTES);

    /* Work directly on a ring buffer memory. */
    rx_size = uart_rx(data, size);

    /* Indicate amount of valid data. rx_size can be equal or less than size. */
    err = ring_buf_put_finish(&ring_buf, rx_size);
    if (err != 0) {
        /* This shouldn't happen unless rx_size > size */
	...
    }

A data item is added to a ring buffer by calling
:c:func:`ring_buf_item_put`.

.. code-block:: c

    uint32_t data[MY_DATA_WORDS];
    int ret;

    ret = ring_buf_item_put(&ring_buf, TYPE_FOO, 0, data, MY_DATA_WORDS);
    if (ret == -EMSGSIZE) {
        /* not enough room for the data item */
	...
    }

If the data item requires only the type or application-specific integer value
(i.e. it has no data array), a size of 0 and data pointer of :c:macro:`NULL`
can be specified.

.. code-block:: c

    int ret;

    ret = ring_buf_item_put(&ring_buf, TYPE_BAR, 17, NULL, 0);
    if (ret == -EMSGSIZE) {
        /* not enough room for the data item */
	...
    }

Retrieving Data
===============

Data bytes are copied out from a **byte mode** ring buffer by calling
:c:func:`ring_buf_get`. For example:

.. code-block:: c

    uint8_t my_data[MY_DATA_BYTES];
    size_t  ret;

    ret = ring_buf_get(&ring_buf, my_data, sizeof(my_data));
    if (ret != sizeof(my_data)) {
        /* Fewer bytes copied. */
    } else {
        /* Requested amount of bytes retrieved. */
        ...
    }

Data can be retrieved from a **byte mode** ring buffer by direct
operations on the ring buffer's memory.  For example:

.. code-block:: c

    uint32_t size;
    uint32_t proc_size;
    uint8_t *data;
    int err;

    /* Get buffer within a ring buffer memory. */
    size = ring_buf_get_claim(&ring_buf, &data, MY_RING_BUF_BYTES);

    /* Work directly on a ring buffer memory. */
    proc_size = process(data, size);

    /* Indicate amount of data that can be freed. proc_size can be equal or less
     * than size.
     */
    err = ring_buf_get_finish(&ring_buf, proc_size);
    if (err != 0) {
        /* proc_size exceeds amount of valid data in a ring buffer. */
	...
    }

A data item is removed from a ring buffer by calling
:c:func:`ring_buf_item_get`.

.. code-block:: c

    uint32_t my_data[MY_DATA_WORDS];
    uint16_t my_type;
    uint8_t  my_value;
    uint8_t  my_size;
    int ret;

    my_size = MY_DATA_WORDS;
    ret = ring_buf_item_get(&ring_buf, &my_type, &my_value, my_data, &my_size);
    if (ret == -EMSGSIZE) {
        printk("Buffer is too small, need %d uint32_t\n", my_size);
    } else if (ret == -EAGAIN) {
        printk("Ring buffer is empty\n");
    } else {
        printk("Got item of type %u value &u of size %u dwords\n",
               my_type, my_value, my_size);
        ...
    }

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

Related configuration options:

* :kconfig:option:`CONFIG_RING_BUFFER`: Enable ring buffer.

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

The following ring buffer APIs are provided by :zephyr_file:`include/zephyr/sys/ring_buffer.h`:

.. doxygengroup:: ring_buffer_apis

Part 3

한국어 전문 번역

Ring buffer는 내용을 FIFO(first-in-first-out) 순서로 저장하는 circular buffer입니다.

애플리케이션이 asynchronous streaming 방식으로 데이터를 복사해야 할 때 Zephyr의 struct ring_buf abstraction을 사용하면 공유 memory buffer에 데이터를 넣고 빼는 복사를 관리할 수 있습니다.

두 가지 content data mode를 지원합니다.

  • Byte mode: Raw byte를 enqueue·dequeue합니다.
  • Data item mode: Metadata가 붙은 여러 32-bit word data item을 최대 1020 byte chunk로 enqueue·dequeue합니다. 각 item에는 애플리케이션이 정의하는 type identifier와 16-bit integer value라는 두 metadata 값이 있습니다.

내부 자료구조는 같지만 ring buffer instance 하나에서 두 mode를 섞는 것은 허용되지 않습니다. Byte 수로 초기화한 buffer는 bytes API만, word 수로 초기화한 buffer는 items API만 사용해야 합니다.

개념

사용 가능한 RAM이 허용하는 만큼 ring buffer를 여러 개 정의할 수 있으며, 각 ring buffer는 memory address로 참조합니다.

Ring buffer의 핵심 속성은 다음과 같습니다.

  • Data buffer: 아직 제거하지 않은 raw byte 또는 32-bit word를 담습니다.
  • Data buffer size: Byte 또는 32-bit word 단위로 측정하며 metadata를 포함해 buffer가 보관할 수 있는 최대 데이터 양을 결정합니다.

Ring buffer는 사용 전에 초기화하여 data buffer를 빈 상태로 만들어야 합니다.

struct ring_buf는 사용자가 접근할 수 있는 어느 메모리에나 둘 수 있습니다. ring_buf_init() 또는 ring_buf_item_init()에 사용자가 관리하는 buffer memory 영역을 제공해 초기화합니다. 나중에 사용할 mode에 따라 size 단위가 byte 또는 word로 달라진다는 점에 주의해야 합니다.

RING_BUF_DECLARE는 지정한 byte 수의 ring buffer를 선언하고 정적으로 초기화합니다. RING_BUF_ITEM_DECLARE는 지정한 32-bit word 수의 item buffer를 선언·초기화합니다. RING_BUF_ITEM_SIZEOF는 type이나 expression에 필요한 크기를 32-bit word 단위로 계산하며 32 bit 배수가 아니면 올림합니다.

Byte data는 ring_buf_put()에 data pointer와 byte 수를 전달해 복사합니다. 할당된 buffer에 들어가는 만큼 순서대로 복사하고 실제 복사한 byte 수를 반환하므로 요청보다 적을 수 있습니다. ring_buf_get()은 쓴 순서대로 사용자 buffer에 byte를 복사하고 전송한 수를 반환합니다.

중복 복사를 피하기 위해 byte mode에는 claim API가 있습니다. ring_buf_put_claim()은 요청 size를 받아 ring buffer 내부의 쓰기 가능한 memory pointer와 연속 영역 크기를 반환합니다. Buffer 끝 때문에 실제 연속 크기는 요청보다 작을 수 있습니다. 사용자가 나중에 그 영역에 직접 쓰고 ring_buf_put_finish()에 실제 전송 byte 수를 전달해 완료를 알리면 새 전송을 시작할 수 있습니다.

ring_buf_get_claim()은 복사 없이 읽을 수 있는 내부 data pointer를 반환하고, ring_buf_get_finish()은 소비한 byte 수를 알려 새 전송을 시작할 수 있게 합니다.

Item mode도 비슷하지만 전송 단위가 모두 32-bit word이고 memory가 32-bit boundary에 정렬되어 있다고 가정합니다. ring_buf_item_put()과 ring_buf_item_get()을 사용하며 claim API는 없습니다. ring_buf_item_put()은 ring_buf_put()과 달리 부분 전송을 하지 않아 item 전체가 들어가지 않으면 오류를 반환합니다.

ring_buf_space_get()과 ring_buf_item_space_get()으로 각각 빈 byte 수와 빈 32-bit item word 수를 얻고, ring_buf_is_empty()로 빈 상태를 검사하여 수정 없이 capacity를 관리할 수 있습니다.

ring_buf_reset()은 이미 쓴 byte나 item의 추적 정보를 버리고 즉시 buffer를 비웁니다. Buffer memory 내용 자체는 변경하지 않습니다.

Byte mode

Byte mode instance는 RING_BUF_DECLARE()로 선언하며 ring_buf_put_claim, ring_buf_put_finish, ring_buf_get_claim, ring_buf_get_finish, ring_buf_put, ring_buf_get을 사용합니다.

Data를 복사해 넣거나 ring buffer memory에 직접 접근할 수 있습니다. 직접 쓰기는 세 단계입니다.

  1. ring_buf_put_claim()으로 data를 쓸 목적지 위치를 요청해 buffer를 할당합니다.
  2. 사용자가 data를 씁니다. 예를 들어 DMA가 buffer에 기록할 수 있습니다.
  3. ring_buf_put_finish()으로 제공된 buffer에 실제 쓴 양을 알립니다. 이 양은 할당량보다 작거나 같을 수 있습니다.

Data를 복사해 꺼내거나 address로 직접 접근할 수 있습니다. 직접 읽기는 세 단계입니다.

  1. ring_buf_get_claim()으로 ring buffer의 유효 data 위치를 얻습니다.
  2. Data를 처리합니다.
  3. ring_buf_get_finish()으로 처리한 data를 해제합니다. 해제량은 얻은 양보다 작거나 같을 수 있습니다.

Data item mode

Data item mode instance는 RING_BUF_ITEM_DECLARE()로 선언하며 ring_buf_item_put()과 ring_buf_item_get()을 사용합니다.

Ring buffer data item은 길이가 0~1020 byte인 32-bit word 배열입니다. ring_buf_item_put()으로 enqueue하면 item 내용과 32-bit word 하나를 차지하는 두 metadata 값을 data buffer에 복사합니다. 새 item 전체를 담을 공간이 부족하면 enqueue가 실패합니다.

ring_buf_item_get()은 가장 오래전에 enqueue한 item을 제거해 dequeue합니다. Item 내용과 두 metadata 값을 호출자가 제공한 영역에 복사합니다. Buffer가 비었거나 호출자가 제공한 data array가 item을 담기에 작으면 실패합니다.

동시성

Ring buffer API는 concurrency control을 제공하지 않습니다. 동시에 접근하는 reader·writer 수에 따라 애플리케이션이 mutex로 buffer를 보호하고 semaphore로 consumer에게 읽을 data가 있음을 알릴 수 있습니다.

Producer 하나와 consumer 하나뿐인 단순한 경우에는 concurrency control이 필요하지 않습니다.

내부 동작

struct ring_buf는 자체 buffer pointer와 size, 다음 read·write 위치를 나타내는 head·tail index 집합을 가집니다. Data는 항상 다음 byte에 쓰고 buffer 끝에 도달하면 첫 element로 wrap하므로 ring 구조가 됩니다.

일반 put/get API에서는 이 경계가 보이지 않지만 claim API는 buffer 끝을 넘어가는 연속 영역을 반환할 수 없어 경계의 영향을 받습니다. Buffer 끝 가까이에서 전송하면 claim/finish 호출을 두 배 해야 할 수 있어 애플리케이션이 예상하지 못한 성능 차이가 생길 수 있습니다.

구현

Ring buffer 정의

struct ring_buf variable을 정의하고 ring_buf_init() 또는 ring_buf_item_init()으로 초기화합니다.

다음 코드는 더 큰 자료구조 안에 빈 data item mode ring buffer를 정의하고 초기화합니다. Data와 metadata를 합쳐 64 word를 담습니다.

#define MY_RING_BUF_WORDS 64

struct my_struct {
    struct ring_buf rb;
    uint32_t buffer[MY_RING_BUF_WORDS];
    ...
};
struct my_struct ms;

void init_my_struct {
    ring_buf_item_init(&ms.rb, MY_RING_BUF_WORDS, ms.buffer);
    ...
}

또는 file scope에서 두 macro 중 하나로 ring buffer와 data buffer를 compile time에 함께 정의·초기화할 수 있습니다. 다음은 data item mode입니다.

#define MY_RING_BUF_WORDS 93
RING_BUF_ITEM_DECLARE(my_ring_buf, MY_RING_BUF_WORDS);

다음은 raw byte용 ring buffer입니다.

#define MY_RING_BUF_BYTES 93
RING_BUF_DECLARE(my_ring_buf, MY_RING_BUF_BYTES);

Data enqueue

ring_buf_put()으로 byte mode ring buffer에 byte를 복사합니다.

uint8_t my_data[MY_RING_BUF_BYTES];
uint32_t ret;

ret = ring_buf_put(&ring_buf, my_data, MY_RING_BUF_BYTES);
if (ret != MY_RING_BUF_BYTES) {
    /* not enough room, partial copy. */
    ...
}

Ring buffer memory에 직접 접근해 data를 추가할 수도 있습니다.

uint32_t size;
uint32_t rx_size;
uint8_t *data;
int err;

/* Allocate buffer within a ring buffer memory. */
size = ring_buf_put_claim(&ring_buf, &data, MY_RING_BUF_BYTES);

/* Work directly on a ring buffer memory. */
rx_size = uart_rx(data, size);

/* Indicate amount of valid data. rx_size can be equal or less than size. */
err = ring_buf_put_finish(&ring_buf, rx_size);
if (err != 0) {
    /* This shouldn't happen unless rx_size > size */
    ...
}

ring_buf_item_put()으로 data item을 추가합니다.

uint32_t data[MY_DATA_WORDS];
int ret;

ret = ring_buf_item_put(&ring_buf, TYPE_FOO, 0, data, MY_DATA_WORDS);
if (ret == -EMSGSIZE) {
    /* not enough room for the data item */
    ...
}

Data item에 type 또는 애플리케이션별 integer value만 필요하고 data array가 없다면 size 0과 NULL data pointer를 지정합니다.

int ret;

ret = ring_buf_item_put(&ring_buf, TYPE_BAR, 17, NULL, 0);
if (ret == -EMSGSIZE) {
    /* not enough room for the data item */
    ...
}

Data 검색·제거

ring_buf_get()으로 byte mode ring buffer에서 byte를 복사해 꺼냅니다.

uint8_t my_data[MY_DATA_BYTES];
size_t  ret;

ret = ring_buf_get(&ring_buf, my_data, sizeof(my_data));
if (ret != sizeof(my_data)) {
    /* Fewer bytes copied. */
} else {
    /* Requested amount of bytes retrieved. */
    ...
}

Ring buffer memory에 직접 접근해 data를 처리하고 해제할 수도 있습니다.

uint32_t size;
uint32_t proc_size;
uint8_t *data;
int err;

/* Get buffer within a ring buffer memory. */
size = ring_buf_get_claim(&ring_buf, &data, MY_RING_BUF_BYTES);

/* Work directly on a ring buffer memory. */
proc_size = process(data, size);

/* Indicate amount of data that can be freed. proc_size can be equal or less
 * than size.
 */
err = ring_buf_get_finish(&ring_buf, proc_size);
if (err != 0) {
    /* proc_size exceeds amount of valid data in a ring buffer. */
    ...
}

ring_buf_item_get()으로 data item을 제거합니다.

uint32_t my_data[MY_DATA_WORDS];
uint16_t my_type;
uint8_t  my_value;
uint8_t  my_size;
int ret;

my_size = MY_DATA_WORDS;
ret = ring_buf_item_get(&ring_buf, &my_type, &my_value, my_data, &my_size);
if (ret == -EMSGSIZE) {
    printk("Buffer is too small, need %d uint32_t\n", my_size);
} else if (ret == -EAGAIN) {
    printk("Ring buffer is empty\n");
} else {
    printk("Got item of type %u value &u of size %u dwords\n",
           my_type, my_value, my_size);
    ...
}

구성 옵션

CONFIG_RING_BUFFER: Ring buffer를 활성화합니다.

API 참고

include/zephyr/sys/ring_buffer.h는 API group ring_buffer_apis의 단순 ring buffer 구현을 제공합니다.

매크로와 정의

RING_BUF_DECLARE(name, size8)

Byte data용 ring buffer를 정의하고 초기화합니다. 기본 저장 단위는 byte이며 임의 크기를 사용할 수 있습니다.

extern struct ring_buf <name>;

매개변수

  • name: ring buffer 이름
  • size8: byte 단위 ring buffer 크기
RING_BUF_ITEM_DECLARE(name, size32)

Item mode ring buffer를 정의하고 초기화합니다. 각 item은 0~1020 byte의 32-bit word 배열과 16-bit type identifier, 8-bit integer value로 구성됩니다.

extern struct ring_buf <name>;

매개변수

  • name: ring buffer 이름
  • size32: 32-bit word 단위 ring buffer 크기
RING_BUF_ITEM_DECLARE_SIZE(name, size32)

RING_BUF_ITEM_DECLARE의 이전 버전 호환 macro입니다. 새 code는 RING_BUF_ITEM_DECLARE를 사용해야 합니다.

매개변수

  • name: ring buffer 이름
  • size32: 32-bit word 단위 크기
RING_BUF_ITEM_DECLARE_POW2(name, pow)

2의 거듭제곱 크기로 item mode ring buffer를 정의·초기화하는 이전 버전 호환 macro입니다. 새 code는 RING_BUF_ITEM_DECLARE를 사용해야 합니다.

매개변수

  • name: ring buffer 이름
  • pow: ring buffer size exponent
RING_BUF_ITEM_SIZEOF(expr)

Element 저장에 필요한 ring buffer 크기를 32-bit word 단위로 계산합니다. Type 또는 expression을 받을 수 있으며 32-bit 배수가 아니면 올림합니다.

매개변수

  • expr: 크기를 계산할 expression 또는 type

함수

static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)

Ring buffer 내부 상태를 주어진 값으로 강제 설정합니다. 0이 아닌 값은 validation test context에서만 의미가 있습니다.

static inline void ring_buf_init(struct ring_buf *buf, uint32_t size, uint8_t *data)

RING_BUF_DECLARE로 정의하지 않은 byte data용 ring buffer를 처음 사용하기 전에 초기화합니다.

매개변수

  • buf: ring buffer 주소
  • size: byte 단위 크기
  • data: uint8_t data[size] 형식의 data 영역
static inline void ring_buf_item_init(struct ring_buf *buf, uint32_t size, uint32_t *data)

RING_BUF_ITEM_DECLARE로 정의하지 않은 item mode ring buffer를 처음 사용하기 전에 초기화합니다. Item은 0~1020 byte의 32-bit word 배열, 16-bit type identifier, 8-bit integer value로 구성됩니다.

매개변수

  • buf: ring buffer 주소
  • size: 32-bit word 단위 크기
  • data: uint32_t data[size] 형식의 data 영역
static inline bool ring_buf_is_empty(struct ring_buf *buf)

Ring buffer가 비었는지 확인합니다.

매개변수

  • buf: ring buffer 주소

반환값: 비었으면 true, 아니면 false입니다.

static inline void ring_buf_reset(struct ring_buf *buf)

Ring buffer 상태를 reset합니다.

매개변수

  • buf: ring buffer 주소
static inline uint32_t ring_buf_space_get(struct ring_buf *buf)

Ring buffer의 빈 공간을 구합니다.

매개변수

  • buf: ring buffer 주소

반환값: Byte 단위 빈 공간입니다.

static inline uint32_t ring_buf_item_space_get(struct ring_buf *buf)

Item mode ring buffer의 빈 공간을 구합니다.

매개변수

  • buf: ring buffer 주소

반환값: 32-bit word 단위 빈 공간입니다.

static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf)

Ring buffer capacity를 반환합니다.

매개변수

  • buf: ring buffer 주소

반환값: Byte 단위 capacity입니다.

static inline uint32_t ring_buf_size_get(struct ring_buf *buf)

Ring buffer에서 사용 중인 공간을 구합니다.

매개변수

  • buf: ring buffer 주소

반환값: Byte 단위 사용 공간입니다.

uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)

Data를 쓸 buffer를 할당합니다. 내부 memory를 직접 사용해 복사를 줄이고, write 뒤 ring_buf_put_finish()로 쓴 byte 수를 확정해야 합니다.

매개변수

  • buf: [in] ring buffer 주소
  • data: [out] ring buffer 내부 위치로 설정할 address pointer
  • size: [in] 요청 byte 수

반환값: 할당된 연속 buffer 크기입니다. 빈 공간 부족이나 wrap 때문에 요청보다 작을 수 있습니다.

int ring_buf_put_finish(struct ring_buf *buf, uint32_t size)

Claim한 buffer에 실제 쓴 byte 수를 알립니다. 이전 put_claim 전체 합보다 작거나 같아야 하며 0도 가능합니다. 남는 byte는 다시 빈 공간이 됩니다.

매개변수

  • buf: ring buffer 주소
  • size: 할당된 buffer의 유효 byte 수

반환값: 0은 성공, -EINVAL은 size가 ring buffer 빈 공간을 초과했음을 뜻합니다.

uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size)

Data를 ring buffer에 복사해 씁니다.

매개변수

  • buf: ring buffer 주소
  • data: data 주소
  • size: byte 단위 data 크기

반환값: 실제로 쓴 byte 수입니다.

uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)

Ring buffer 안 유효 data의 주소를 얻어 복사를 줄입니다. 처리 뒤 ring_buf_get_finish()로 해제해야 합니다.

매개변수

  • buf: [in] ring buffer 주소
  • data: [out] ring buffer 내부 위치로 설정할 address pointer
  • size: [in] 요청 byte 수

반환값: 제공된 buffer의 유효 byte 수입니다. data 부족이나 wrap 때문에 요청보다 작을 수 있습니다.

int ring_buf_get_finish(struct ring_buf *buf, uint32_t size)

Claim한 buffer에서 읽은 byte 수를 알립니다. 이전 get_claim 전체 합보다 작거나 같아야 하며 0도 가능합니다. 남는 byte는 buffer에 계속 남습니다.

매개변수

  • buf: ring buffer 주소
  • size: 해제 가능한 byte 수

반환값: 0은 성공, -EINVAL은 size가 유효 byte 수를 초과했음을 뜻합니다.

uint32_t ring_buf_get(struct ring_buf *buf, uint8_t *data, uint32_t size)

Ring buffer에서 data를 읽어 복사합니다.

매개변수

  • buf: ring buffer 주소
  • data: 출력 buffer 주소. Data를 버리려면 NULL도 가능합니다.
  • size: byte 단위 data 크기

반환값: 출력 buffer에 쓴 byte 수입니다.

uint32_t ring_buf_peek(struct ring_buf *buf, uint8_t *data, uint32_t size)

Data를 제거하지 않고 ring buffer에서 읽어 봅니다. Peek를 여러 번 호출하면 같은 data가 반복해서 반환됩니다. 제거하려면 ring_buf_get() 또는 ring_buf_get_claim() 뒤 0이 아닌 size의 ring_buf_get_finish()를 사용합니다.

매개변수

  • buf: ring buffer 주소
  • data: 출력 buffer 주소이며 NULL일 수 없습니다.
  • size: byte 단위 data 크기

반환값: 출력 buffer에 쓴 byte 수입니다.

int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value, uint32_t *data, uint8_t size32)

Data item을 ring buffer에 씁니다. Item은 0~1020 byte의 32-bit word 배열과 16-bit type identifier, 8-bit integer value로 구성됩니다.

매개변수

  • buf: ring buffer 주소
  • type: 애플리케이션별 type identifier
  • value: 애플리케이션별 integer value
  • data: data item 주소
  • size32: 32-bit word 수로 나타낸 item 크기

반환값: 0은 쓰기 성공, -EMSGSIZE는 빈 공간 부족입니다.

int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value, uint32_t *data, uint8_t *size32)

Ring buffer에서 data item을 읽습니다. Item은 최대 1020 byte의 32-bit word 배열과 16-bit type identifier, 8-bit integer value로 구성됩니다.

매개변수

  • buf: ring buffer 주소
  • type: type identifier를 저장할 영역
  • value: integer value를 저장할 영역
  • data: item을 저장할 영역. Data를 버리려면 NULL도 가능합니다.
  • size32: 32-bit chunk 수로 나타낸 저장 영역 크기

반환값: 0은 성공이며 size32에 읽은 word 수가 들어갑니다. -EAGAIN은 빈 buffer, -EMSGSIZE는 data 영역 부족이며 이때 size32에 필요한 word 수가 들어갑니다.

구조체

struct ring_buf

<ring_buffer.h>에 정의된 ring buffer 표현 구조체입니다.

Source

출처

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