Commit 3075a7d9 authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Benjamin Cabé
Browse files

ring_buffer: factorize almost identical code

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

Signed-off-by: default avatarNicolas Pitre <npitre@baylibre.com>
parent 83279d15
Loading
Loading
Loading
Loading
+50 −27
Changes for include/zephyr/sys/ring_buffer.h: 50 added lines, 27 removed lines.
Original line number Diff line number Diff line
@@ -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,
static inline uint32_t ring_buf_put_claim(struct ring_buf *buf,
					  uint8_t **data,
			    uint32_t size);
					  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,
static inline uint32_t ring_buf_get_claim(struct ring_buf *buf,
					  uint8_t **data,
			    uint32_t size);
					  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.
+18 −64
Changes for lib/utils/ring_buffer.c: 18 added lines, 64 removed lines.
Original line number Diff line number Diff line
@@ -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;