diff --git a/include/zephyr/sys/ring_buffer.h b/include/zephyr/sys/ring_buffer.h index e104fd5443e..dbcd099d46e 100644 --- a/include/zephyr/sys/ring_buffer.h +++ b/include/zephyr/sys/ring_buffer.h @@ -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; } /** diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig index 4fb6a3248e6..9aaf8a4d20c 100644 --- a/lib/utils/Kconfig +++ b/lib/utils/Kconfig @@ -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 diff --git a/lib/utils/ring_buffer.c b/lib/utils/ring_buffer.c index c08d876128c..652b53b758f 100644 --- a/lib/utils/ring_buffer.c +++ b/lib/utils/ring_buffer.c @@ -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)) { diff --git a/tests/lib/ringbuffer/src/concurrent.c b/tests/lib/ringbuffer/src/concurrent.c index 60e9aa1c263..913109aa60f 100644 --- a/tests/lib/ringbuffer/src/concurrent.c +++ b/tests/lib/ringbuffer/src/concurrent.c @@ -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. */