ring_buffer: the great simplification

This code is rather hairy. When I look at it I don't like the way it
stares back at me.

First, the rewind business looks fishy. It has to die.

And we don't have to rely on modulus either. Not even for non-power-of-2
buffers. Let's kill that distinction too and make all sizes always
"high performance".

The code is now entirely relying only on simple ALU operations (add,
sub and compare).

The key assumption: 32-bit values do wrap around after max range has
been reached. No saturation. All architectures supported by Zephyr
do that.

Some stats:

lib/os/ring_buffer.c: 62 insertions(+), 124 deletions(-)

ring_buffer.c.obj       before   after    diff
----------------------------------------------
frdm_k64f                 1224    1136     -88
m2gl025_miv               2485    2079    -406
mps2_an385                1228    1132     -96
mps2_an521                1228    1132     -96
native_posix              1546    1496     -50
native_posix_64           1598    1595      -3
nsim_hs_mpuv6             1252    1192     -60
nsim_hs_smp               1252    1192     -60
nsim_sem                  1252    1192     -60
qemu_arc_em               1324    1192    -132
qemu_arc_hs6x             1824    1620    -204
qemu_arc_hs               1252    1192     -60
qemu_cortex_a53_smp       2154    1888    -266
qemu_cortex_a53           2154    1888    -266
qemu_cortex_a9            1938    1792    -146

Before (qemu_cortex_a53):
START - test_ringbuffer_performance
1 byte put-get, avg cycles: 52
4 byte put-get, avg cycles: 47
1 byte put claim-finish, avg cycles: 39
5 byte put claim-finish, avg cycles: 41
5 byte get claim-finish, avg cycles: 52
 PASS - test_ringbuffer_performance in 0.8 seconds

After (qemu_cortex_a53):
START - test_ringbuffer_performance
1 byte put-get, avg cycles: 34
4 byte put-get, avg cycles: 41
1 byte put claim-finish, avg cycles: 27
5 byte put claim-finish, avg cycles: 29
5 byte get claim-finish, avg cycles: 29
 PASS - test_ringbuffer_performance in 0.4 seconds

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2022-02-13 22:16:33 -05:00 committed by Marti Bolivar
parent c2543320d8
commit 099850e916
5 changed files with 126 additions and 254 deletions

View file

@ -60,13 +60,8 @@ 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_SIZE` will declare and statically
: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_DECLARE_POW2` can be used to initialize an
items-mode buffer with a memory region guaranteed to be a power of
two, which enables various optimizations internal to the
implementation. No power-of-two initialization is available for
bytes-mode ring buffers.
"Bytes" data may be copied into the ring buffer using
:c:func:`ring_buf_put`, passing a data pointer and byte count. These
@ -104,7 +99,7 @@ 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 items respectively,
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
@ -117,8 +112,7 @@ Data item mode
==============
A **data item mode** ring buffer instance is declared using
:c:macro:`RING_BUF_ITEM_DECLARE_POW2()` or
:c:macro:`RING_BUF_ITEM_DECLARE_SIZE()` and accessed 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
@ -174,37 +168,26 @@ 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
shouldn't be needed.
control shouldn't be needed.
Internal Operation
==================
If the size of the data buffer is a power of two, the ring buffer
uses efficient masking operations instead of expensive modulo operations
when enqueuing and dequeuing data items. This option is applicable only for
data item mode.
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
"head" and "tail" index representing where the next read and write
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 alias closely to the size of the
buffer, as the number of calls to claim/finish need to double for such
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.
When running in items mode (only), the ring buffer contains two
implementations for the modular arithmetic required to compute "next
element" offsets. One is used for arbitrary sized buffers, but the
other is optimized for power of two sizes and can replace the compare
and subtract steps with a simple bitmask in several places, at the
cost of testing the "mask" value for each call.
Implementation
**************
@ -240,26 +223,14 @@ 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 and initializes an empty **data item mode**
ring with a power-of-two sized data buffer, which can be accessed using
efficient masking operations.
.. code-block:: c
/* Buffer with 2^8 (or 256) words */
RING_BUF_ITEM_DECLARE_POW2(my_ring_buf, 8);
The following code defines a **data item mode** ring with an arbitrary-sized
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_SIZE(my_ring_buf, MY_RING_BUF_WORDS);
RING_BUF_ITEM_DECLARE(my_ring_buf, MY_RING_BUF_WORDS);
The following code defines a ring buffer with an arbitrary-sized data buffer,
which can be accessed using less efficient modulo operations. Ring buffer is
intended to be used for raw bytes.
The following code defines a ring buffer intended to be used for raw bytes:
.. code-block:: c

View file

@ -13,7 +13,6 @@
#include <kernel.h>
#include <sys/util.h>
#include <errno.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
@ -27,31 +26,20 @@ extern "C" {
#define RING_BUFFER_MAX_SIZE 0x80000000U
#define RING_BUFFER_SIZE_ASSERT_MSG \
"Size too big, if it is the ring buffer test check custom max size"
"Size too big"
/**
* @brief A structure to represent a ring buffer
*/
struct ring_buf {
uint32_t head; /**< Index in buf for the head element */
uint32_t tail; /**< Index in buf for the tail element */
union ring_buf_misc {
struct ring_buf_misc_item_mode {
uint32_t dropped_put_count; /**< Running tally of the
* number of failed put
* attempts.
*/
} item_mode;
struct ring_buf_misc_byte_mode {
uint32_t tmp_tail;
uint32_t tmp_head;
} byte_mode;
} misc;
uint32_t size;
uint8_t *buffer;
uint32_t mask; /**< Modulo mask if size is a power of 2 */
struct k_spinlock lock;
int32_t put_head;
int32_t put_tail;
int32_t put_base;
int32_t get_head;
int32_t get_tail;
int32_t get_base;
uint32_t size;
};
/**
@ -61,39 +49,24 @@ struct ring_buf {
*/
/**
* @brief Define and initialize an "item based" high performance ring buffer.
* @brief Define and initialize an "item based" ring buffer with a power of 2.
*
* This macro establishes a ring buffer whose size must be a power of 2;
* that is, the ring buffer contains 2^pow 32-bit words, where @a pow is
* the specified ring buffer size exponent. A high performance ring buffer
* doesn't require the use of modulo arithmetic operations to maintain itself.
*
* Each data item is an array of 32-bit words (from zero to 1020 bytes in
* length), coupled with a 16-bit type identifier and an 8-bit integer value.
*
* The ring buffer can be accessed outside the module where it is defined
* using:
*
* @code extern struct ring_buf <name>; @endcode
* This macro establishes an "item based" ring buffer by specifying its
* size using a power of 2. This exists mainly for backward compatibility
* reasons. @ref RING_BUF_ITEM_DECLARE should be used instead.
*
* @param name Name of the ring buffer.
* @param pow Ring buffer size exponent.
*/
#define RING_BUF_ITEM_DECLARE_POW2(name, pow) \
BUILD_ASSERT(BIT(pow) < RING_BUFFER_MAX_SIZE / 4,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint32_t __noinit _ring_buffer_data_##name[BIT(pow)]; \
struct ring_buf name = { \
.size = 4 * BIT(pow), \
.mask = (4 * BIT(pow)) - 1, \
.buffer = (uint8_t *) _ring_buffer_data_##name \
}
RING_BUF_ITEM_DECLARE(name, BIT(pow))
/**
* @brief Define and initialize a standard ring buffer.
* @brief Define and initialize an "item based" ring buffer.
*
* This macro establishes a ring buffer of an arbitrary size. A standard
* ring buffer uses modulo arithmetic operations to maintain itself.
* This macro establishes an "item based" ring buffer. Each data item is
* an array of 32-bit words (from zero to 1020 bytes in length), coupled
* with a 16-bit type identifier and an 8-bit integer value.
*
* The ring buffer can be accessed outside the module where it is defined
* using:
@ -103,7 +76,7 @@ struct ring_buf {
* @param name Name of the ring buffer.
* @param size32 Size of ring buffer (in 32-bit words).
*/
#define RING_BUF_ITEM_DECLARE_SIZE(name, size32) \
#define RING_BUF_ITEM_DECLARE(name, size32) \
BUILD_ASSERT((size32) < RING_BUFFER_MAX_SIZE / 4,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint32_t __noinit _ring_buffer_data_##name[size32]; \
@ -112,6 +85,18 @@ struct ring_buf {
.buffer = (uint8_t *) _ring_buffer_data_##name \
}
/**
* @brief Define and initialize an "item based" ring buffer.
*
* This exists for backward compatibility reasons. @ref RING_BUF_ITEM_DECLARE
* should be used instead.
*
* @param name Name of the ring buffer.
* @param size32 Size of ring buffer (in 32-bit words).
*/
#define RING_BUF_ITEM_DECLARE_SIZE(name, size32) \
RING_BUF_ITEM_DECLARE(name, size32)
/**
* @brief Define and initialize a ring buffer for byte data.
*
@ -141,10 +126,6 @@ struct ring_buf {
* This routine initializes a ring buffer, prior to its first use. It is only
* used for ring buffers not defined using RING_BUF_DECLARE.
*
* Setting @a size to a power of 2 establishes a high performance ring buffer
* that doesn't require the use of modulo arithmetic operations to maintain
* itself.
*
* @param buf Address of ring buffer.
* @param size Ring buffer size (in bytes).
* @param data Ring buffer data area (uint8_t data[size]).
@ -155,26 +136,20 @@ static inline void ring_buf_init(struct ring_buf *buf,
{
__ASSERT(size < RING_BUFFER_MAX_SIZE, RING_BUFFER_SIZE_ASSERT_MSG);
memset(buf, 0, sizeof(struct ring_buf));
buf->size = size;
buf->buffer = data;
if (is_power_of_two(size)) {
buf->mask = size - 1U;
} else {
buf->mask = 0U;
}
buf->put_head = buf->put_tail = buf->put_base = 0;
buf->get_head = buf->get_tail = buf->get_base = 0;
}
/**
* @brief Initialize an "item based" ring buffer.
*
* This routine initializes a ring buffer, prior to its first use. It is only
* used for ring buffers not defined using RING_BUF_ITEM_DECLARE_POW2 or
* RING_BUF_ITEM_DECLARE_SIZE.
* used for ring buffers not defined using RING_BUF_ITEM_DECLARE.
*
* Setting @a size to a power of 2 establishes a high performance ring buffer
* that doesn't require the use of modulo arithmetic operations to maintain
* itself.
* Each data item is an array of 32-bit words (from zero to 1020 bytes in
* length), coupled with a 16-bit type identifier and an 8-bit integer value.
*
* Each data item is an array of 32-bit words (from zero to 1020 bytes in
* length), coupled with a 16-bit type identifier and an 8-bit integer value.
@ -196,9 +171,12 @@ static inline void ring_buf_item_init(struct ring_buf *buf,
*
* @param buf Address of ring buffer.
*
* @return 1 if the ring buffer is empty, or 0 if not.
* @return true if the ring buffer is empty, or false if not.
*/
int ring_buf_is_empty(struct ring_buf *buf);
static inline bool ring_buf_is_empty(struct ring_buf *buf)
{
return buf->get_head == buf->put_tail;
}
/**
* @brief Reset ring buffer state.
@ -207,9 +185,8 @@ int ring_buf_is_empty(struct ring_buf *buf);
*/
static inline void ring_buf_reset(struct ring_buf *buf)
{
buf->head = 0;
buf->tail = 0;
memset(&buf->misc, 0, sizeof(buf->misc));
buf->put_head = buf->put_tail = buf->put_base = 0;
buf->get_head = buf->get_tail = buf->get_base = 0;
}
/**
@ -219,7 +196,10 @@ static inline void ring_buf_reset(struct ring_buf *buf)
*
* @return Ring buffer free space (in bytes).
*/
uint32_t ring_buf_space_get(struct ring_buf *buf);
static inline uint32_t ring_buf_space_get(struct ring_buf *buf)
{
return buf->size - (buf->put_head - buf->get_tail);
}
/**
* @brief Determine free space in an "item based" ring buffer.
@ -252,7 +232,10 @@ static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf)
*
* @return Ring buffer space used (in bytes).
*/
uint32_t ring_buf_size_get(struct ring_buf *buf);
static inline uint32_t ring_buf_size_get(struct ring_buf *buf)
{
return buf->put_tail - buf->get_head;
}
/**
* @brief Write a data item to a ring buffer.

View file

@ -9,16 +9,6 @@
#include <sys/ring_buffer.h>
#include <string.h>
/* LCOV_EXCL_START */
/* The weak function used to allow overwriting it in the test and trigger
* rewinding earlier.
*/
uint32_t __weak ring_buf_get_rewind_threshold(void)
{
return RING_BUFFER_MAX_SIZE;
}
/* LCOV_EXCL_STOP */
/**
* Internal data structure for a buffer header.
*
@ -31,52 +21,6 @@ struct ring_element {
uint32_t value :8; /**< Room for small integral values */
};
static uint32_t mod(struct ring_buf *buf, uint32_t val)
{
return likely(buf->mask) ? val & buf->mask : val % buf->size;
}
static uint32_t get_rewind_value(uint32_t buf_size, uint32_t threshold)
{
/* Rewind value is rounded to buffer size and decreased by buffer_size.
* This is done to ensure that there will be no negative numbers after
* subtraction. That could happen because tail is rewinded first and
* head (which follows tail) is rewinded on next getting.
*/
return buf_size * (threshold / buf_size - 1);
}
int ring_buf_is_empty(struct ring_buf *buf)
{
uint32_t tail = buf->tail;
uint32_t head = buf->head;
if (tail < head) {
tail += get_rewind_value(buf->size,
ring_buf_get_rewind_threshold());
}
return (head == tail);
}
uint32_t ring_buf_size_get(struct ring_buf *buf)
{
uint32_t tail = buf->tail;
uint32_t head = buf->head;
if (tail < head) {
tail += get_rewind_value(buf->size,
ring_buf_get_rewind_threshold());
}
return tail - head;
}
uint32_t ring_buf_space_get(struct ring_buf *buf)
{
return buf->size - ring_buf_size_get(buf);
}
int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value,
uint32_t *data32, uint8_t size32)
{
@ -163,52 +107,50 @@ int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value,
uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
{
uint32_t space, trail_size, allocated, tmp_trail_mod;
uint32_t head = buf->head;
uint32_t tmp_tail = buf->misc.byte_mode.tmp_tail;
uint32_t free_space, wrap_size;
int32_t base;
if (buf->misc.byte_mode.tmp_tail < head) {
/* Head is already rewinded but tail is not */
tmp_tail += get_rewind_value(buf->size, ring_buf_get_rewind_threshold());
base = buf->put_base;
wrap_size = buf->put_head - base;
if (unlikely(wrap_size >= buf->size)) {
/* put_base is not yet adjusted */
wrap_size -= buf->size;
base += buf->size;
}
wrap_size = buf->size - wrap_size;
tmp_trail_mod = mod(buf, buf->misc.byte_mode.tmp_tail);
space = (head + buf->size) - tmp_tail;
trail_size = buf->size - tmp_trail_mod;
free_space = ring_buf_space_get(buf);
size = MIN(size, free_space);
size = MIN(size, wrap_size);
/* Limit requested size to available size. */
size = MIN(size, space);
*data = &buf->buffer[buf->put_head - base];
buf->put_head += size;
trail_size = buf->size - (tmp_trail_mod);
/* Limit allocated size to trail size. */
allocated = MIN(trail_size, size);
*data = &buf->buffer[tmp_trail_mod];
buf->misc.byte_mode.tmp_tail =
buf->misc.byte_mode.tmp_tail + allocated;
return allocated;
return size;
}
int ring_buf_put_finish(struct ring_buf *buf, uint32_t size)
{
uint32_t rew;
uint32_t threshold = ring_buf_get_rewind_threshold();
uint32_t finish_space, wrap_size;
if ((buf->tail + size) > (buf->head + buf->size)) {
if (unlikely(size == 0)) {
/* claim is cancelled */
buf->put_head = buf->put_tail;
return 0;
}
finish_space = buf->put_head - buf->put_tail;
if (unlikely(size > finish_space)) {
return -EINVAL;
}
/* Check if indexes shall be rewind. */
if (buf->tail > threshold) {
rew = get_rewind_value(buf->size, threshold);
} else {
rew = 0;
}
buf->put_tail += size;
buf->tail += (size - rew);
buf->misc.byte_mode.tmp_tail = buf->tail;
wrap_size = buf->put_tail - buf->put_base;
if (unlikely(wrap_size >= buf->size)) {
/* we wrapped: adjust put_base */
buf->put_base += buf->size;
}
return 0;
}
@ -236,54 +178,50 @@ uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size)
uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
{
uint32_t space, granted_size, trail_size, tmp_head_mod;
uint32_t tail = buf->tail;
uint32_t available_size, wrap_size;
int32_t base;
/* Tail is always ahead, if it is not, it's only because it got rewinded. */
if (tail < buf->misc.byte_mode.tmp_head) {
/* Locally, increment it to pre-rewind value */
tail += get_rewind_value(buf->size,
ring_buf_get_rewind_threshold());
base = buf->get_base;
wrap_size = buf->get_head - base;
if (unlikely(wrap_size >= buf->size)) {
/* get_base is not yet adjusted */
wrap_size -= buf->size;
base += buf->size;
}
wrap_size = buf->size - wrap_size;
tmp_head_mod = mod(buf, buf->misc.byte_mode.tmp_head);
space = tail - buf->misc.byte_mode.tmp_head;
trail_size = buf->size - tmp_head_mod;
available_size = ring_buf_size_get(buf);
size = MIN(size, available_size);
size = MIN(size, wrap_size);
/* Limit requested size to available size. */
granted_size = MIN(size, space);
*data = &buf->buffer[buf->get_head - base];
buf->get_head += size;
/* Limit allocated size to trail size. */
granted_size = MIN(trail_size, granted_size);
*data = &buf->buffer[tmp_head_mod];
buf->misc.byte_mode.tmp_head += granted_size;
return granted_size;
return size;
}
int ring_buf_get_finish(struct ring_buf *buf, uint32_t size)
{
uint32_t tail = buf->tail;
uint32_t rew;
uint32_t finish_space, wrap_size;
/* Tail is always ahead, if it is not, it's only because it got rewinded. */
if (tail < buf->misc.byte_mode.tmp_head) {
/* tail was rewinded. Locally, increment it to pre-rewind value */
rew = get_rewind_value(buf->size,
ring_buf_get_rewind_threshold());
tail += rew;
} else {
rew = 0;
if (unlikely(size == 0)) {
/* claim is cancelled */
buf->get_head = buf->get_tail;
return 0;
}
if ((buf->head + size) > tail) {
finish_space = buf->get_head - buf->get_tail;
if (unlikely(size > finish_space)) {
return -EINVAL;
}
/* Include potential rewinding. */
buf->head += (size - rew);
buf->misc.byte_mode.tmp_head = buf->head;
buf->get_tail += size;
wrap_size = buf->get_tail - buf->get_base;
if (unlikely(wrap_size >= buf->size)) {
/* we wrapped: adjust get_base */
buf->get_base += buf->size;
}
return 0;
}

View file

@ -24,7 +24,7 @@
#define TYPE 0xc
static ZTEST_BMEM SYS_MUTEX_DEFINE(mutex);
RING_BUF_ITEM_DECLARE_SIZE(ringbuf, RINGBUFFER);
RING_BUF_ITEM_DECLARE(ringbuf, RINGBUFFER);
static uint32_t output[LENGTH];
static uint32_t databuffer1[LENGTH];
static uint32_t databuffer2[LENGTH];
@ -252,18 +252,14 @@ static bool consume(void *user_data, uint32_t iter_cnt, bool last, int prio)
return true;
}
extern uint32_t test_rewind_threshold;
static void test_ztress(ztress_handler high_handler,
ztress_handler low_handler,
bool item_mode)
{
uint8_t buf[32];
uint32_t buf32[32];
uint32_t old_rewind_threshold = test_rewind_threshold;
k_timeout_t timeout;
test_rewind_threshold = 256;
if (item_mode) {
ring_buf_item_init(&ringbuf, ARRAY_SIZE(buf32), buf32);
} else {
@ -276,8 +272,6 @@ static void test_ztress(ztress_handler high_handler,
ztress_set_timeout(timeout);
ZTRESS_EXECUTE(ZTRESS_THREAD(high_handler, NULL, 0, 0, Z_TIMEOUT_TICKS(20)),
ZTRESS_THREAD(low_handler, NULL, 0, 2000, Z_TIMEOUT_TICKS(20)));
test_rewind_threshold = old_rewind_threshold;
}
void test_ringbuffer_stress(ztress_handler produce_handler,

View file

@ -21,20 +21,6 @@
#include <logging/log.h>
LOG_MODULE_REGISTER(test);
/* Max size is used internally in the algorithm. Value is decreased in the test
* to trigger rewind algorithm.
*/
#undef RING_BUFFER_MAX_SIZE
#define RING_BUFFER_MAX_SIZE 0x00000800
/* Use global variable that can be modified by the test. */
uint32_t test_rewind_threshold = RING_BUFFER_MAX_SIZE;
uint32_t ring_buf_get_rewind_threshold(void)
{
return test_rewind_threshold;
}
/**
* @defgroup lib_ringbuffer_tests Ringbuffer
* @ingroup all_tests
@ -163,13 +149,13 @@ void test_ring_buffer_main(void)
/**TESTPOINT: init via RING_BUF_ITEM_DECLARE_POW2*/
RING_BUF_ITEM_DECLARE_POW2(ringbuf_pow2, POW);
/**TESTPOINT: init via RING_BUF_ITEM_DECLARE_SIZE*/
/**TESTPOINT: init via RING_BUF_ITEM_DECLARE*/
/**
* @brief define a ring buffer with arbitrary size
*
* @see RING_BUF_ITEM_DECLARE_SIZE(),RING_BUF_DECLARE()
* @see RING_BUF_ITEM_DECLARE(), RING_BUF_DECLARE()
*/
RING_BUF_ITEM_DECLARE_SIZE(ringbuf_size, RINGBUFFER_SIZE);
RING_BUF_ITEM_DECLARE(ringbuf_size, RINGBUFFER_SIZE);
RING_BUF_DECLARE(ringbuf_raw, RINGBUFFER_SIZE);
@ -402,7 +388,7 @@ void test_ringbuffer_pow2_put_get_thread_isr(void)
*
* @details
* Test Objective:
* - define and initialize a ring buffer by macro RING_BUF_ITEM_DECLARE_SIZE,
* - define and initialize a ring buffer by macro RING_BUF_ITEM_DECLARE,
* then passing data by thread and isr to verify the ringbuffer
* if it works to be placed in any user-controlled memory.
*
@ -412,7 +398,7 @@ void test_ringbuffer_pow2_put_get_thread_isr(void)
* - Structural test coverage(entry points,statements,branches)
*
* Prerequisite Conditions:
* - Define and initialize a ringbuffer by RING_BUF_ITEM_DECLARE_SIZE
* - Define and initialize a ringbuffer by RING_BUF_ITEM_DECLARE
* - Define a pointer of ring buffer type.
*
* Input Specifications: