ring_buffer: shrink size of struct ring_buf

Make struct ring_buf 12 bytes smaller by default. This comes with a 32KB
buffer size limit which covers almost all cases. The previous limit of
2GB can be restored with CONFIG_RING_BUFFER_LARGE=y.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2025-02-06 17:08:44 -05:00 committed by Benjamin Cabé
parent b97f11a752
commit e1eead3925
4 changed files with 35 additions and 18 deletions

View File

@ -29,11 +29,17 @@ extern "C" {
/* The limit is used by algorithm for distinguishing between empty and full
* state.
*/
#define RING_BUFFER_MAX_SIZE 0x80000000U
#define RING_BUFFER_SIZE_ASSERT_MSG \
"Size too big"
#ifdef CONFIG_RING_BUFFER_LARGE
typedef uint32_t ring_buf_idx_t;
#define RING_BUFFER_MAX_SIZE (UINT32_MAX / 2)
#else
typedef uint16_t ring_buf_idx_t;
#define RING_BUFFER_MAX_SIZE (UINT16_MAX / 2)
#endif
struct ring_buf_index { int32_t head, tail, base; };
#define RING_BUFFER_SIZE_ASSERT_MSG "Size too big"
struct ring_buf_index { ring_buf_idx_t head, tail, base; };
/** @endcond */
@ -61,7 +67,7 @@ int ring_buf_area_finish(struct ring_buf *buf, struct ring_buf_index *ring,
*
* Any value other than 0 makes sense only in validation testing context.
*/
static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
static inline void ring_buf_internal_reset(struct ring_buf *buf, ring_buf_idx_t value)
{
buf->put.head = buf->put.tail = buf->put.base = value;
buf->get.head = buf->get.tail = buf->get.base = value;
@ -90,7 +96,7 @@ static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
* @param size8 Size of ring buffer (in bytes).
*/
#define RING_BUF_DECLARE(name, size8) \
BUILD_ASSERT(size8 < RING_BUFFER_MAX_SIZE,\
BUILD_ASSERT(size8 <= RING_BUFFER_MAX_SIZE,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint8_t __noinit _ring_buffer_data_##name[size8]; \
struct ring_buf name = RING_BUF_INIT(_ring_buffer_data_##name, size8)
@ -111,7 +117,7 @@ static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
* @param size32 Size of ring buffer (in 32-bit words).
*/
#define RING_BUF_ITEM_DECLARE(name, size32) \
BUILD_ASSERT((size32) < RING_BUFFER_MAX_SIZE / 4,\
BUILD_ASSERT((size32) <= RING_BUFFER_MAX_SIZE / 4, \
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint32_t __noinit _ring_buffer_data_##name[size32]; \
struct ring_buf name = { \
@ -168,7 +174,7 @@ static inline void ring_buf_init(struct ring_buf *buf,
uint32_t size,
uint8_t *data)
{
__ASSERT(size < RING_BUFFER_MAX_SIZE, RING_BUFFER_SIZE_ASSERT_MSG);
__ASSERT(size <= RING_BUFFER_MAX_SIZE, RING_BUFFER_SIZE_ASSERT_MSG);
buf->size = size;
buf->buffer = data;
@ -192,7 +198,7 @@ static inline void ring_buf_item_init(struct ring_buf *buf,
uint32_t size,
uint32_t *data)
{
__ASSERT(size < RING_BUFFER_MAX_SIZE / 4, RING_BUFFER_SIZE_ASSERT_MSG);
__ASSERT(size <= RING_BUFFER_MAX_SIZE / 4, RING_BUFFER_SIZE_ASSERT_MSG);
ring_buf_init(buf, 4 * size, (uint8_t *)data);
}
@ -227,7 +233,9 @@ static inline void ring_buf_reset(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);
ring_buf_idx_t allocated = buf->put.head - buf->get.tail;
return buf->size - allocated;
}
/**
@ -255,15 +263,17 @@ static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf)
}
/**
* @brief Determine used space in a ring buffer.
* @brief Determine size of available data in a ring buffer.
*
* @param buf Address of ring buffer.
*
* @return Ring buffer space used (in bytes).
* @return Ring buffer data size (in bytes).
*/
static inline uint32_t ring_buf_size_get(struct ring_buf *buf)
{
return buf->put.tail - buf->get.head;
ring_buf_idx_t available = buf->put.tail - buf->get.head;
return available;
}
/**

View File

@ -16,6 +16,13 @@ config RING_BUFFER
Some facilities such as kernel pipes are built on top of this.
May be used directly e.g. when the pipe overhead is unnecessary.
config RING_BUFFER_LARGE
bool "Allow large ring buffer sizes"
depends on RING_BUFFER
help
Increase maximum buffer size from 32KB to 2GB. When this is enabled,
all struct ring_buf instances become 12 bytes bigger.
config NOTIFY
bool "Asynchronous Notifications"
help

View File

@ -12,7 +12,7 @@
uint32_t ring_buf_area_claim(struct ring_buf *buf, struct ring_buf_index *ring,
uint8_t **data, uint32_t size)
{
uint32_t head_offset, wrap_size;
ring_buf_idx_t head_offset, wrap_size;
head_offset = ring->head - ring->base;
if (unlikely(head_offset >= buf->size)) {
@ -31,7 +31,7 @@ uint32_t ring_buf_area_claim(struct ring_buf *buf, struct ring_buf_index *ring,
int ring_buf_area_finish(struct ring_buf *buf, struct ring_buf_index *ring,
uint32_t size)
{
uint32_t claimed_size, tail_offset;
ring_buf_idx_t claimed_size, tail_offset;
claimed_size = ring->head - ring->tail;
if (unlikely(size > claimed_size)) {

View File

@ -262,7 +262,7 @@ static void test_ztress(ztress_handler high_handler,
uint32_t buf32[32];
} buf;
k_timeout_t timeout;
int32_t offset;
uint32_t offset;
if (item_mode) {
ring_buf_item_init(&ringbuf, ARRAY_SIZE(buf.buf32), buf.buf32);
@ -270,8 +270,8 @@ static void test_ztress(ztress_handler high_handler,
ring_buf_init(&ringbuf, ARRAY_SIZE(buf.buf8), buf.buf8);
}
/* force internal 32-bit index roll-over */
offset = INT32_MAX - ring_buf_capacity_get(&ringbuf)/2;
/* force internal index roll-over */
offset = (ring_buf_idx_t)-1 - ring_buf_capacity_get(&ringbuf)/2;
ring_buf_internal_reset(&ringbuf, offset);
/* Timeout after 5 seconds. */