ring_buffer: factorize almost identical code

Factorize almost identical code. May even improve performance due to
CPU cache locality.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2025-01-15 17:26:05 -05:00 committed by Benjamin Cabé
parent 83279d1524
commit 3075a7d906
2 changed files with 70 additions and 93 deletions

View File

@ -14,16 +14,6 @@
extern "C" {
#endif
/** @cond INTERNAL_HIDDEN */
/* 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"
/** @endcond */
/**
* @file
* @defgroup ring_buffer_apis Ring Buffer APIs
@ -34,22 +24,38 @@ extern "C" {
* @{
*/
/** @cond INTERNAL_HIDDEN */
/* 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"
struct ring_buf_index { int32_t head, tail, base; };
/** @endcond */
/**
* @brief A structure to represent a ring buffer
*/
struct ring_buf {
/** @cond INTERNAL_HIDDEN */
uint8_t *buffer;
int32_t put_head;
int32_t put_tail;
int32_t put_base;
int32_t get_head;
int32_t get_tail;
int32_t get_base;
struct ring_buf_index put;
struct ring_buf_index get;
uint32_t size;
/** @endcond */
};
/** @cond INTERNAL_HIDDEN */
uint32_t ring_buf_area_claim(struct ring_buf *buf, struct ring_buf_index *ring,
uint8_t **data, uint32_t size);
int ring_buf_area_finish(struct ring_buf *buf, struct ring_buf_index *ring,
uint32_t size);
/**
* @brief Function to force ring_buf internal states to given value
*
@ -57,15 +63,18 @@ struct ring_buf {
*/
static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
{
buf->put_head = buf->put_tail = buf->put_base = value;
buf->get_head = buf->get_tail = buf->get_base = value;
buf->put.head = buf->put.tail = buf->put.base = value;
buf->get.head = buf->get.tail = buf->get.base = value;
}
/** @endcond */
#define RING_BUF_INIT(buf, size8) \
{ \
.buffer = buf, \
.size = size8, \
}
/**
* @brief Define and initialize a ring buffer for byte data.
*
@ -196,7 +205,7 @@ static inline void ring_buf_item_init(struct ring_buf *buf,
*/
static inline bool ring_buf_is_empty(struct ring_buf *buf)
{
return buf->get_head == buf->put_tail;
return buf->get.head == buf->put.tail;
}
/**
@ -218,7 +227,7 @@ 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);
return buf->size - (buf->put.head - buf->get.tail);
}
/**
@ -254,7 +263,7 @@ static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf)
*/
static inline uint32_t ring_buf_size_get(struct ring_buf *buf)
{
return buf->put_tail - buf->get_head;
return buf->put.tail - buf->get.head;
}
/**
@ -281,9 +290,13 @@ static inline uint32_t ring_buf_size_get(struct ring_buf *buf)
* @return Size of allocated buffer which can be smaller than requested if
* there is not enough free space or buffer wraps.
*/
uint32_t ring_buf_put_claim(struct ring_buf *buf,
uint8_t **data,
uint32_t size);
static inline uint32_t ring_buf_put_claim(struct ring_buf *buf,
uint8_t **data,
uint32_t size)
{
return ring_buf_area_claim(buf, &buf->put, data,
MIN(size, ring_buf_space_get(buf)));
}
/**
* @brief Indicate number of bytes written to allocated buffers.
@ -307,7 +320,10 @@ uint32_t ring_buf_put_claim(struct ring_buf *buf,
* @retval 0 Successful operation.
* @retval -EINVAL Provided @a size exceeds free space in the ring buffer.
*/
int ring_buf_put_finish(struct ring_buf *buf, uint32_t size);
static inline int ring_buf_put_finish(struct ring_buf *buf, uint32_t size)
{
return ring_buf_area_finish(buf, &buf->put, size);
}
/**
* @brief Write (copy) data to a ring buffer.
@ -355,9 +371,13 @@ uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size);
* @return Number of valid bytes in the provided buffer which can be smaller
* than requested if there is not enough free space or buffer wraps.
*/
uint32_t ring_buf_get_claim(struct ring_buf *buf,
uint8_t **data,
uint32_t size);
static inline uint32_t ring_buf_get_claim(struct ring_buf *buf,
uint8_t **data,
uint32_t size)
{
return ring_buf_area_claim(buf, &buf->get, data,
MIN(size, ring_buf_size_get(buf)));
}
/**
* @brief Indicate number of bytes read from claimed buffer.
@ -381,7 +401,10 @@ uint32_t ring_buf_get_claim(struct ring_buf *buf,
* @retval 0 Successful operation.
* @retval -EINVAL Provided @a size exceeds valid bytes in the ring buffer.
*/
int ring_buf_get_finish(struct ring_buf *buf, uint32_t size);
static inline int ring_buf_get_finish(struct ring_buf *buf, uint32_t size)
{
return ring_buf_area_finish(buf, &buf->get, size);
}
/**
* @brief Read data from a ring buffer.

View File

@ -9,46 +9,45 @@
#include <zephyr/sys/ring_buffer.h>
#include <string.h>
uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
uint32_t ring_buf_area_claim(struct ring_buf *buf, struct ring_buf_index *ring,
uint8_t **data, uint32_t size)
{
uint32_t free_space, wrap_size;
uint32_t wrap_size;
int32_t base;
base = buf->put_base;
wrap_size = buf->put_head - base;
base = ring->base;
wrap_size = ring->head - base;
if (unlikely(wrap_size >= buf->size)) {
/* put_base is not yet adjusted */
/* ring->base is not yet adjusted */
wrap_size -= buf->size;
base += buf->size;
}
wrap_size = buf->size - wrap_size;
free_space = ring_buf_space_get(buf);
size = MIN(size, free_space);
size = MIN(size, wrap_size);
*data = &buf->buffer[buf->put_head - base];
buf->put_head += size;
*data = &buf->buffer[ring->head - base];
ring->head += size;
return size;
}
int ring_buf_put_finish(struct ring_buf *buf, uint32_t size)
int ring_buf_area_finish(struct ring_buf *buf, struct ring_buf_index *ring,
uint32_t size)
{
uint32_t finish_space, wrap_size;
uint32_t claimed_size, wrap_size;
finish_space = buf->put_head - buf->put_tail;
if (unlikely(size > finish_space)) {
claimed_size = ring->head - ring->tail;
if (unlikely(size > claimed_size)) {
return -EINVAL;
}
buf->put_tail += size;
buf->put_head = buf->put_tail;
ring->tail += size;
ring->head = ring->tail;
wrap_size = buf->put_tail - buf->put_base;
wrap_size = ring->tail - ring->base;
if (unlikely(wrap_size >= buf->size)) {
/* we wrapped: adjust put_base */
buf->put_base += buf->size;
/* we wrapped: adjust ring->base */
ring->base += buf->size;
}
return 0;
@ -79,51 +78,6 @@ uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size)
return total_size;
}
uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
{
uint32_t available_size, wrap_size;
int32_t base;
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;
available_size = ring_buf_size_get(buf);
size = MIN(size, available_size);
size = MIN(size, wrap_size);
*data = &buf->buffer[buf->get_head - base];
buf->get_head += size;
return size;
}
int ring_buf_get_finish(struct ring_buf *buf, uint32_t size)
{
uint32_t finish_space, wrap_size;
finish_space = buf->get_head - buf->get_tail;
if (unlikely(size > finish_space)) {
return -EINVAL;
}
buf->get_tail += size;
buf->get_head = buf->get_tail;
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;
}
uint32_t ring_buf_get(struct ring_buf *buf, uint8_t *data, uint32_t size)
{
uint8_t *src;