lib: os: ring_buffer: Allow using full buffer capacity

Previously, ring buffer had capacity of provided buffer size - 1. This
trick was used to distinguish between empty and full states. It had one
drawback: ring buffer could not be used as a pool of equal sized buffers
(using ring_buf_put_claim and ring_buf_get_claim).
Reworked internals to use non wrapping head and tail. Since they are
non wrapping, there is no issue with distinguishing between empty and
full. Since this appraoch would be vulnerable to wrapping on 32 bit
boundary, added a mechanism which periodically reduces all indexes to
avoid 32 bit wrapping.

After this rework, buffer has one byte more capacity. Simple test shows
slight performance improvement.

Updated tests to reflect increased capacity and added test to check if
it is possible to continuesly allocated 2 buffers of half ring buffer
size.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2020-07-27 11:00:23 +02:00 committed by Carles Cufí
parent c380142920
commit 1e46bb3bb5
5 changed files with 258 additions and 93 deletions

View file

@ -103,9 +103,6 @@ shouldn't be needed.
Internal Operation Internal Operation
================== ==================
The ring buffer always maintains an empty 32-bit word (byte in bytes mode) in
its data buffer to allow it to distinguish between empty and full states.
If the size of the data buffer is a power of two, the ring buffer If the size of the data buffer is a power of two, the ring buffer
uses efficient masking operations instead of expensive modulo operations uses efficient masking operations instead of expensive modulo operations
when enqueuing and dequeuing data items. This option is applicable only for when enqueuing and dequeuing data items. This option is applicable only for

View file

@ -21,6 +21,13 @@ extern "C" {
#define SIZE32_OF(x) (sizeof((x))/sizeof(uint32_t)) #define SIZE32_OF(x) (sizeof((x))/sizeof(uint32_t))
/* The limit is used by algorithm for distinguishing between empty and full
* state.
*/
#define RING_BUFFER_MAX_SIZE 0x80000000
#define RING_BUFFER_SIZE_ASSERT_MSG \
"Size too big, if it is the ring buffer test check custom max size"
/** /**
* @brief A structure to represent a ring buffer * @brief A structure to represent a ring buffer
*/ */
@ -46,6 +53,8 @@ struct ring_buf {
uint8_t *buf8; uint8_t *buf8;
} buf; } buf;
uint32_t mask; /**< Modulo mask if size is a power of 2 */ uint32_t mask; /**< Modulo mask if size is a power of 2 */
struct k_spinlock lock;
}; };
/** /**
@ -71,6 +80,8 @@ struct ring_buf {
* @param pow Ring buffer size exponent. * @param pow Ring buffer size exponent.
*/ */
#define RING_BUF_ITEM_DECLARE_POW2(name, pow) \ #define RING_BUF_ITEM_DECLARE_POW2(name, pow) \
BUILD_ASSERT((1 << pow) < RING_BUFFER_MAX_SIZE,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint32_t _ring_buffer_data_##name[BIT(pow)]; \ static uint32_t _ring_buffer_data_##name[BIT(pow)]; \
struct ring_buf name = { \ struct ring_buf name = { \
.size = (BIT(pow)), \ .size = (BIT(pow)), \
@ -93,6 +104,8 @@ struct ring_buf {
* @param size32 Size of ring buffer (in 32-bit words). * @param size32 Size of ring buffer (in 32-bit words).
*/ */
#define RING_BUF_ITEM_DECLARE_SIZE(name, size32) \ #define RING_BUF_ITEM_DECLARE_SIZE(name, size32) \
BUILD_ASSERT(size32 < RING_BUFFER_MAX_SIZE,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint32_t _ring_buffer_data_##name[size32]; \ static uint32_t _ring_buffer_data_##name[size32]; \
struct ring_buf name = { \ struct ring_buf name = { \
.size = size32, \ .size = size32, \
@ -113,6 +126,8 @@ struct ring_buf {
* @param size8 Size of ring buffer (in bytes). * @param size8 Size of ring buffer (in bytes).
*/ */
#define RING_BUF_DECLARE(name, size8) \ #define RING_BUF_DECLARE(name, size8) \
BUILD_ASSERT(size8 < RING_BUFFER_MAX_SIZE,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint8_t _ring_buffer_data_##name[size8]; \ static uint8_t _ring_buffer_data_##name[size8]; \
struct ring_buf name = { \ struct ring_buf name = { \
.size = size8, \ .size = size8, \
@ -138,6 +153,8 @@ struct ring_buf {
*/ */
static inline void ring_buf_init(struct ring_buf *buf, uint32_t size, void *data) static inline void ring_buf_init(struct ring_buf *buf, uint32_t size, void *data)
{ {
__ASSERT(size < RING_BUFFER_MAX_SIZE, RING_BUFFER_SIZE_ASSERT_MSG);
memset(buf, 0, sizeof(struct ring_buf)); memset(buf, 0, sizeof(struct ring_buf));
buf->size = size; buf->size = size;
buf->buf.buf32 = (uint32_t *)data; buf->buf.buf32 = (uint32_t *)data;
@ -148,27 +165,6 @@ static inline void ring_buf_init(struct ring_buf *buf, uint32_t size, void *data
} }
} }
/** @brief Determine free space based on ring buffer parameters.
*
* @note Function for internal use.
*
* @param size Ring buffer size.
* @param head Ring buffer head.
* @param tail Ring buffer tail.
*
* @return Ring buffer free space (in 32-bit words or bytes).
*/
static inline uint32_t z_ring_buf_custom_space_get(uint32_t size, uint32_t head,
uint32_t tail)
{
if (tail < head) {
return head - tail - 1U;
}
/* buf->tail > buf->head */
return (size - tail) + head - 1U;
}
/** /**
* @brief Determine if a ring buffer is empty. * @brief Determine if a ring buffer is empty.
* *
@ -202,7 +198,7 @@ static inline void ring_buf_reset(struct ring_buf *buf)
*/ */
static inline uint32_t ring_buf_space_get(struct ring_buf *buf) static inline uint32_t ring_buf_space_get(struct ring_buf *buf)
{ {
return z_ring_buf_custom_space_get(buf->size, buf->head, buf->tail); return buf->size - (buf->tail - buf->head);
} }
/** /**
@ -214,8 +210,7 @@ static inline uint32_t ring_buf_space_get(struct ring_buf *buf)
*/ */
static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf) static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf)
{ {
/* One element is used to distinguish between empty and full state. */ return buf->size;
return buf->size - 1;
} }
/** /**

View file

@ -9,6 +9,14 @@
#include <sys/ring_buffer.h> #include <sys/ring_buffer.h>
#include <string.h> #include <string.h>
/* 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;
}
/** /**
* Internal data structure for a buffer header. * Internal data structure for a buffer header.
* *
@ -21,6 +29,57 @@ struct ring_element {
uint32_t value :8; /**< Room for small integral values */ 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;
}
/* Check if indexes did not progress too far (too close to 32-bit wrapping).
* If so, then reduce all indexes by an arbitrary value.
*/
static void item_indexes_rewind(struct ring_buf *buf)
{
uint32_t rewind;
uint32_t threshold = ring_buf_get_rewind_threshold();
if (buf->head < threshold) {
return;
}
rewind = buf->size * (threshold / buf->size);
k_spinlock_key_t key = k_spin_lock(&buf->lock);
buf->tail -= rewind;
buf->head -= rewind;
k_spin_unlock(&buf->lock, key);
}
/* Check if indexes did not progresses too far (too close to 32-bit wrapping).
* If so, then rewind all indexes by an arbitrary value. For byte mode temporary
* indexes must also be reduced.
*/
static void byte_indexes_rewind(struct ring_buf *buf)
{
uint32_t rewind;
uint32_t threshold = ring_buf_get_rewind_threshold();
/* Checking head since it is the smallest index. */
if (buf->head < threshold) {
return;
}
rewind = buf->size * (threshold / buf->size);
k_spinlock_key_t key = k_spin_lock(&buf->lock);
buf->tail -= rewind;
buf->head -= rewind;
buf->misc.byte_mode.tmp_head -= rewind;
buf->misc.byte_mode.tmp_tail -= rewind;
k_spin_unlock(&buf->lock, key);
}
int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value, int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value,
uint32_t *data, uint8_t size32) uint32_t *data, uint8_t size32)
{ {
@ -29,7 +88,8 @@ int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value,
space = ring_buf_space_get(buf); space = ring_buf_space_get(buf);
if (space >= (size32 + 1)) { if (space >= (size32 + 1)) {
struct ring_element *header = struct ring_element *header =
(struct ring_element *)&buf->buf.buf32[buf->tail]; (struct ring_element *)&buf->buf.buf32[mod(buf, buf->tail)];
header->type = type; header->type = type;
header->length = size32; header->length = size32;
header->value = value; header->value = value;
@ -39,14 +99,14 @@ int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value,
index = (i + buf->tail + 1) & buf->mask; index = (i + buf->tail + 1) & buf->mask;
buf->buf.buf32[index] = data[i]; buf->buf.buf32[index] = data[i];
} }
buf->tail = (buf->tail + size32 + 1) & buf->mask;
} else { } else {
for (i = 0U; i < size32; ++i) { for (i = 0U; i < size32; ++i) {
index = (i + buf->tail + 1) % buf->size; index = (i + buf->tail + 1) % buf->size;
buf->buf.buf32[index] = data[i]; buf->buf.buf32[index] = data[i];
} }
buf->tail = (buf->tail + size32 + 1) % buf->size;
} }
buf->tail = buf->tail + size32 + 1;
rc = 0U; rc = 0U;
} else { } else {
buf->misc.item_mode.dropped_put_count++; buf->misc.item_mode.dropped_put_count++;
@ -66,7 +126,7 @@ int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value,
return -EAGAIN; return -EAGAIN;
} }
header = (struct ring_element *) &buf->buf.buf32[buf->head]; header = (struct ring_element *) &buf->buf.buf32[mod(buf, buf->head)];
if (header->length > *size32) { if (header->length > *size32) {
*size32 = header->length; *size32 = header->length;
@ -82,15 +142,17 @@ int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value,
index = (i + buf->head + 1) & buf->mask; index = (i + buf->head + 1) & buf->mask;
data[i] = buf->buf.buf32[index]; data[i] = buf->buf.buf32[index];
} }
buf->head = (buf->head + header->length + 1) & buf->mask;
} else { } else {
for (i = 0U; i < header->length; ++i) { for (i = 0U; i < header->length; ++i) {
index = (i + buf->head + 1) % buf->size; index = (i + buf->head + 1) % buf->size;
data[i] = buf->buf.buf32[index]; data[i] = buf->buf.buf32[index];
} }
buf->head = (buf->head + header->length + 1) % buf->size;
} }
buf->head = buf->head + header->length + 1;
item_indexes_rewind(buf);
return 0; return 0;
} }
@ -108,32 +170,34 @@ static inline uint32_t wrap(uint32_t val, uint32_t max)
uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size) uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
{ {
uint32_t space, trail_size, allocated; uint32_t space, trail_size, allocated, tmp_trail_mod;
space = z_ring_buf_custom_space_get(buf->size, buf->head, tmp_trail_mod = mod(buf, buf->misc.byte_mode.tmp_tail);
buf->misc.byte_mode.tmp_tail); space = (buf->head + buf->size) - buf->misc.byte_mode.tmp_tail;
trail_size = buf->size - tmp_trail_mod;
/* Limit requested size to available size. */ /* Limit requested size to available size. */
size = MIN(size, space); size = MIN(size, space);
trail_size = buf->size - buf->misc.byte_mode.tmp_tail;
trail_size = buf->size - (tmp_trail_mod);
/* Limit allocated size to trail size. */ /* Limit allocated size to trail size. */
allocated = MIN(trail_size, size); allocated = MIN(trail_size, size);
*data = &buf->buf.buf8[tmp_trail_mod];
*data = &buf->buf.buf8[buf->misc.byte_mode.tmp_tail];
buf->misc.byte_mode.tmp_tail = buf->misc.byte_mode.tmp_tail =
wrap(buf->misc.byte_mode.tmp_tail + allocated, buf->size); buf->misc.byte_mode.tmp_tail + allocated;
return allocated; return allocated;
} }
int ring_buf_put_finish(struct ring_buf *buf, uint32_t size) int ring_buf_put_finish(struct ring_buf *buf, uint32_t size)
{ {
if (size > ring_buf_space_get(buf)) { if ((buf->tail + size) > (buf->head + buf->size)) {
return -EINVAL; return -EINVAL;
} }
buf->tail = wrap(buf->tail + size, buf->size); buf->tail += size;
buf->misc.byte_mode.tmp_tail = buf->tail; buf->misc.byte_mode.tmp_tail = buf->tail;
return 0; return 0;
@ -162,13 +226,11 @@ 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 ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
{ {
uint32_t space, granted_size, trail_size; uint32_t space, granted_size, trail_size, tmp_head_mod;
space = (buf->size - 1) - tmp_head_mod = mod(buf, buf->misc.byte_mode.tmp_head);
z_ring_buf_custom_space_get(buf->size, space = buf->tail - buf->misc.byte_mode.tmp_head;
buf->misc.byte_mode.tmp_head, trail_size = buf->size - tmp_head_mod;
buf->tail);
trail_size = buf->size - buf->misc.byte_mode.tmp_head;
/* Limit requested size to available size. */ /* Limit requested size to available size. */
granted_size = MIN(size, space); granted_size = MIN(size, space);
@ -176,24 +238,23 @@ uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
/* Limit allocated size to trail size. */ /* Limit allocated size to trail size. */
granted_size = MIN(trail_size, granted_size); granted_size = MIN(trail_size, granted_size);
*data = &buf->buf.buf8[buf->misc.byte_mode.tmp_head]; *data = &buf->buf.buf8[tmp_head_mod];
buf->misc.byte_mode.tmp_head = buf->misc.byte_mode.tmp_head += granted_size;
wrap(buf->misc.byte_mode.tmp_head + granted_size, buf->size);
return granted_size; return granted_size;
} }
int ring_buf_get_finish(struct ring_buf *buf, uint32_t size) int ring_buf_get_finish(struct ring_buf *buf, uint32_t size)
{ {
uint32_t allocated = (buf->size - 1) - ring_buf_space_get(buf); if ((buf->head + size) > buf->tail) {
if (size > allocated) {
return -EINVAL; return -EINVAL;
} }
buf->head = wrap(buf->head + size, buf->size); buf->head += size;
buf->misc.byte_mode.tmp_head = buf->head; buf->misc.byte_mode.tmp_head = buf->head;
byte_indexes_rewind(buf);
return 0; return 0;
} }

View file

@ -0,0 +1,8 @@
# Copyright (c) 2020 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
config RING_BUFFER_TEST
bool
default y
source "Kconfig.zephyr"

View file

@ -21,6 +21,17 @@
#include <logging/log.h> #include <logging/log.h>
LOG_MODULE_REGISTER(test); LOG_MODULE_REGISTER(test);
/* Max size is used internally in algorithm. Value is decreased in the test to
* trigger rewind algorithm.
*/
#undef RING_BUFFER_MAX_SIZE
#define RING_BUFFER_MAX_SIZE 0x00000200
uint32_t ring_buf_get_rewind_threshold(void)
{
return RING_BUFFER_MAX_SIZE;
}
/** /**
* @defgroup lib_ringbuffer_tests Ringbuffer * @defgroup lib_ringbuffer_tests Ringbuffer
* @ingroup all_tests * @ingroup all_tests
@ -204,19 +215,19 @@ void test_ringbuffer_init(void)
/**TESTPOINT: init via ring_buf_init*/ /**TESTPOINT: init via ring_buf_init*/
ring_buf_init(&ringbuf, RINGBUFFER_SIZE, buffer); ring_buf_init(&ringbuf, RINGBUFFER_SIZE, buffer);
zassert_true(ring_buf_is_empty(&ringbuf), NULL); zassert_true(ring_buf_is_empty(&ringbuf), NULL);
zassert_equal(ring_buf_space_get(&ringbuf), RINGBUFFER_SIZE - 1, NULL); zassert_equal(ring_buf_space_get(&ringbuf), RINGBUFFER_SIZE, NULL);
} }
void test_ringbuffer_declare_pow2(void) void test_ringbuffer_declare_pow2(void)
{ {
zassert_true(ring_buf_is_empty(&ringbuf_pow2), NULL); zassert_true(ring_buf_is_empty(&ringbuf_pow2), NULL);
zassert_equal(ring_buf_space_get(&ringbuf_pow2), (1 << POW) - 1, NULL); zassert_equal(ring_buf_space_get(&ringbuf_pow2), (1 << POW), NULL);
} }
void test_ringbuffer_declare_size(void) void test_ringbuffer_declare_size(void)
{ {
zassert_true(ring_buf_is_empty(&ringbuf_size), NULL); zassert_true(ring_buf_is_empty(&ringbuf_size), NULL);
zassert_equal(ring_buf_space_get(&ringbuf_size), RINGBUFFER_SIZE - 1, zassert_equal(ring_buf_space_get(&ringbuf_size), RINGBUFFER_SIZE,
NULL); NULL);
} }
@ -263,14 +274,16 @@ void test_ringbuffer_declare_size(void)
void test_ringbuffer_put_get_thread(void) void test_ringbuffer_put_get_thread(void)
{ {
pbuf = &ringbuf; pbuf = &ringbuf;
tringbuf_put((const void *)0); for (int i = 0; i < 1000; i++) {
tringbuf_put((const void *)1); tringbuf_put((const void *)0);
tringbuf_get((const void *)0); tringbuf_put((const void *)1);
tringbuf_get((const void *)1); tringbuf_get((const void *)0);
tringbuf_put((const void *)2); tringbuf_get((const void *)1);
zassert_false(ring_buf_is_empty(pbuf), NULL); tringbuf_put((const void *)2);
tringbuf_get((const void *)2); zassert_false(ring_buf_is_empty(pbuf), NULL);
zassert_true(ring_buf_is_empty(pbuf), NULL); tringbuf_get((const void *)2);
zassert_true(ring_buf_is_empty(pbuf), NULL);
}
} }
void test_ringbuffer_put_get_isr(void) void test_ringbuffer_put_get_isr(void)
@ -478,7 +491,7 @@ void test_ringbuffer_raw(void)
memset(outbuf, 0, sizeof(outbuf)); memset(outbuf, 0, sizeof(outbuf));
in_size = ring_buf_put(&ringbuf_raw, inbuf, in_size = ring_buf_put(&ringbuf_raw, inbuf,
RINGBUFFER_SIZE); RINGBUFFER_SIZE);
zassert_equal(in_size, RINGBUFFER_SIZE - 1, NULL); zassert_equal(in_size, RINGBUFFER_SIZE, NULL);
in_size = ring_buf_put(&ringbuf_raw, inbuf, in_size = ring_buf_put(&ringbuf_raw, inbuf,
1); 1);
@ -487,7 +500,7 @@ void test_ringbuffer_raw(void)
out_size = ring_buf_get(&ringbuf_raw, outbuf, out_size = ring_buf_get(&ringbuf_raw, outbuf,
RINGBUFFER_SIZE); RINGBUFFER_SIZE);
zassert_true(out_size == RINGBUFFER_SIZE - 1, NULL); zassert_true(out_size == RINGBUFFER_SIZE, NULL);
out_size = ring_buf_get(&ringbuf_raw, outbuf, out_size = ring_buf_get(&ringbuf_raw, outbuf,
RINGBUFFER_SIZE + 1); RINGBUFFER_SIZE + 1);
@ -514,21 +527,21 @@ void test_ringbuffer_alloc_put(void)
allocated = ring_buf_put_claim(&ringbuf_raw, &data, allocated = ring_buf_put_claim(&ringbuf_raw, &data,
RINGBUFFER_SIZE - 1); RINGBUFFER_SIZE - 1);
sum_allocated += allocated; sum_allocated += allocated;
zassert_true(allocated == RINGBUFFER_SIZE - 2, NULL); zassert_true(allocated == RINGBUFFER_SIZE - 1, NULL);
/* Putting too much returns error */ /* Putting too much returns error */
err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE); err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE + 1);
zassert_true(err != 0, NULL); zassert_true(err != 0, NULL);
err = ring_buf_put_finish(&ringbuf_raw, 1); err = ring_buf_put_finish(&ringbuf_raw, 1);
zassert_true(err == 0, NULL); zassert_true(err == 0, NULL);
err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE - 2); err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE - 1);
zassert_true(err == 0, NULL); zassert_true(err == 0, NULL);
read_size = ring_buf_get(&ringbuf_raw, outputbuf, read_size = ring_buf_get(&ringbuf_raw, outputbuf,
RINGBUFFER_SIZE - 1); RINGBUFFER_SIZE);
zassert_true(read_size == (RINGBUFFER_SIZE - 1), NULL); zassert_true(read_size == RINGBUFFER_SIZE, NULL);
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
allocated = ring_buf_put_claim(&ringbuf_raw, &data, 2); allocated = ring_buf_put_claim(&ringbuf_raw, &data, 2);
@ -619,7 +632,7 @@ void test_capacity(void)
* 1 byte is used for distinguishing between full and empty state. * 1 byte is used for distinguishing between full and empty state.
*/ */
capacity = ring_buf_capacity_get(&ringbuf_raw); capacity = ring_buf_capacity_get(&ringbuf_raw);
zassert_equal(RINGBUFFER_SIZE - 1, capacity, zassert_equal(RINGBUFFER_SIZE, capacity,
"Unexpected capacity"); "Unexpected capacity");
} }
@ -643,18 +656,18 @@ void test_reset(void)
zassert_equal(out_len, len, NULL); zassert_equal(out_len, len, NULL);
space = ring_buf_space_get(&ringbuf_raw); space = ring_buf_space_get(&ringbuf_raw);
zassert_equal(space, RINGBUFFER_SIZE - 1, NULL); zassert_equal(space, RINGBUFFER_SIZE, NULL);
/* Even though ringbuffer is empty, full buffer cannot be allocated /* Even though ringbuffer is empty, full buffer cannot be allocated
* because internal pointers are not at the beginning. * because internal pointers are not at the beginning.
*/ */
granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE); granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE);
zassert_false(granted == RINGBUFFER_SIZE - 1, NULL); zassert_false(granted == RINGBUFFER_SIZE, NULL);
/* After reset full buffer can be allocated. */ /* After reset full buffer can be allocated. */
ring_buf_reset(&ringbuf_raw); ring_buf_reset(&ringbuf_raw);
granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE); granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE);
zassert_true(granted == RINGBUFFER_SIZE - 1, NULL); zassert_true(granted == RINGBUFFER_SIZE, NULL);
} }
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
@ -739,27 +752,118 @@ void test_ringbuffer_array_perf(void)
zassert_equal(sizeof(tp), sizeof(ringbuf_stored[0]), NULL); zassert_equal(sizeof(tp), sizeof(ringbuf_stored[0]), NULL);
} }
void test_ringbuffer_partial_putting(void)
{
uint8_t indata[RINGBUFFER_SIZE];
uint8_t outdata[RINGBUFFER_SIZE];
uint32_t len;
uint32_t len2;
uint32_t req_len;
uint8_t *ptr;
ring_buf_reset(&ringbuf_raw);
for (int i = 0; i < 100; i++) {
req_len = (i % RINGBUFFER_SIZE) + 1;
len = ring_buf_put(&ringbuf_raw, indata, req_len);
zassert_equal(req_len, len, NULL);
len = ring_buf_get(&ringbuf_raw, outdata, req_len);
zassert_equal(req_len, len, NULL);
req_len = 2;
len = ring_buf_put_claim(&ringbuf_raw, &ptr, 2);
zassert_equal(len, 2, NULL);
len = ring_buf_put_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
len2 = ring_buf_put_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
zassert_equal(len + len2, RINGBUFFER_SIZE - 2, NULL);
ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE);
req_len = RINGBUFFER_SIZE;
len = ring_buf_get(&ringbuf_raw, indata, req_len);
zassert_equal(len, req_len, NULL);
}
}
void test_ringbuffer_partial_getting(void)
{
uint8_t indata[RINGBUFFER_SIZE];
uint8_t outdata[RINGBUFFER_SIZE];
uint32_t len;
uint32_t len2;
uint32_t req_len;
uint8_t *ptr;
ring_buf_reset(&ringbuf_raw);
for (int i = 0; i < 100; i++) {
req_len = (i % RINGBUFFER_SIZE) + 1;
len = ring_buf_put(&ringbuf_raw, indata, req_len);
zassert_equal(req_len, len, NULL);
len = ring_buf_get(&ringbuf_raw, outdata, req_len);
zassert_equal(req_len, len, NULL);
req_len = sizeof(indata);
len = ring_buf_put(&ringbuf_raw, indata, req_len);
zassert_equal(req_len, len, NULL);
len = ring_buf_get_claim(&ringbuf_raw, &ptr, 2);
zassert_equal(len, 2, NULL);
len = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
len2 = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
zassert_equal(len + len2, RINGBUFFER_SIZE - 2, NULL);
ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE);
}
}
void test_ringbuffer_equal_bufs(void)
{
struct ring_buf buf_ii;
uint8_t *data;
uint32_t claimed;
uint8_t buf[8];
size_t halfsize = sizeof(buf)/2;
ring_buf_init(&buf_ii, sizeof(buf), buf);
for (int i = 0; i < 100; i++) {
claimed = ring_buf_put_claim(&buf_ii, &data, halfsize);
zassert_equal(claimed, halfsize, NULL);
ring_buf_put_finish(&buf_ii, claimed);
claimed = ring_buf_get_claim(&buf_ii, &data, halfsize);
zassert_equal(claimed, halfsize, NULL);
ring_buf_get_finish(&buf_ii, claimed);
}
}
/*test case main entry*/ /*test case main entry*/
void test_main(void) void test_main(void)
{ {
ztest_test_suite(test_ringbuffer_api, ztest_test_suite(test_ringbuffer_api,
ztest_unit_test(test_ringbuffer_init),/*keep init first!*/ ztest_unit_test(test_ringbuffer_init),/*keep init first!*/
ztest_unit_test(test_ringbuffer_declare_pow2), ztest_unit_test(test_ringbuffer_declare_pow2),
ztest_unit_test(test_ringbuffer_declare_size), ztest_unit_test(test_ringbuffer_declare_size),
ztest_unit_test(test_ringbuffer_put_get_thread), ztest_unit_test(test_ringbuffer_put_get_thread),
ztest_unit_test(test_ringbuffer_put_get_isr), ztest_unit_test(test_ringbuffer_put_get_isr),
ztest_unit_test(test_ringbuffer_put_get_thread_isr), ztest_unit_test(test_ringbuffer_put_get_thread_isr),
ztest_unit_test(test_ringbuffer_pow2_put_get_thread_isr), ztest_unit_test(test_ringbuffer_pow2_put_get_thread_isr),
ztest_unit_test(test_ringbuffer_size_put_get_thread_isr), ztest_unit_test(test_ringbuffer_size_put_get_thread_isr),
ztest_unit_test(test_ringbuffer_array_perf), ztest_unit_test(test_ringbuffer_array_perf),
ztest_unit_test(test_ring_buffer_main), ztest_unit_test(test_ringbuffer_partial_putting),
ztest_unit_test(test_ringbuffer_raw), ztest_unit_test(test_ringbuffer_partial_getting),
ztest_unit_test(test_ringbuffer_alloc_put), ztest_unit_test(test_ring_buffer_main),
ztest_unit_test(test_byte_put_free), ztest_unit_test(test_ringbuffer_raw),
ztest_unit_test(test_byte_put_free), ztest_unit_test(test_ringbuffer_alloc_put),
ztest_unit_test(test_capacity), ztest_unit_test(test_byte_put_free),
ztest_unit_test(test_reset) ztest_unit_test(test_ringbuffer_equal_bufs),
); ztest_unit_test(test_capacity),
ztest_unit_test(test_reset)
);
ztest_run_test_suite(test_ringbuffer_api); ztest_run_test_suite(test_ringbuffer_api);
} }