sys: add thread-safe ringbuffer implementation
This commit is contained in:
parent
187e318da9
commit
185f63f768
154
sys/include/tsrb.h
Normal file
154
sys/include/tsrb.h
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup sys_tsrb Thread safe ringbuffer
|
||||||
|
* @ingroup sys
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Thread-safe ringbuffer implementation
|
||||||
|
*
|
||||||
|
* This ringbuffer implementation can be used without locking if
|
||||||
|
* there's only one producer and one consumer.
|
||||||
|
*
|
||||||
|
* @note Buffer size must be a power of two!
|
||||||
|
*
|
||||||
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TSRB_H
|
||||||
|
#define TSRB_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief thread-safe ringbuffer struct
|
||||||
|
*/
|
||||||
|
typedef struct tsrb {
|
||||||
|
char *buf; /**< Buffer to operate on. */
|
||||||
|
unsigned int size; /**< Size of buf. */
|
||||||
|
volatile unsigned reads; /**< total number of reads */
|
||||||
|
volatile unsigned writes; /**< total number of writes */
|
||||||
|
} tsrb_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static initializer
|
||||||
|
*/
|
||||||
|
#define TSRB_INIT(BUF) { (BUF), sizeof (BUF), 0, 0 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a tsrb.
|
||||||
|
* @param[out] rb Datum to initialize.
|
||||||
|
* @param[in] buffer Buffer to use by tsrb.
|
||||||
|
* @param[in] bufsize `sizeof (buffer)`
|
||||||
|
*/
|
||||||
|
static inline void tsrb_init(tsrb_t *rb, char *buffer, unsigned bufsize)
|
||||||
|
{
|
||||||
|
/* make sure bufsize is a power of two.
|
||||||
|
* http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/
|
||||||
|
*/
|
||||||
|
assert((bufsize != 0) && ((bufsize & (~bufsize + 1)) == bufsize));
|
||||||
|
|
||||||
|
rb->buf = buffer;
|
||||||
|
rb->size = bufsize;
|
||||||
|
rb->reads = 0;
|
||||||
|
rb->writes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test if the tsrb is empty.
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @return 0 if not empty
|
||||||
|
* @return 1 otherwise
|
||||||
|
*/
|
||||||
|
static inline int tsrb_empty(const tsrb_t *rb)
|
||||||
|
{
|
||||||
|
return (rb->reads == rb->writes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get number of bytes available for reading
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @return nr of available bytes
|
||||||
|
*/
|
||||||
|
static inline unsigned int tsrb_avail(const tsrb_t *rb)
|
||||||
|
{
|
||||||
|
return (rb->writes - rb->reads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test if the tsrb is full
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @return 0 if not full
|
||||||
|
* @return 1 otherwise
|
||||||
|
*/
|
||||||
|
static inline int tsrb_full(const tsrb_t *rb)
|
||||||
|
{
|
||||||
|
return (rb->writes - rb->reads) == rb->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get free space in ringbuffer
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @return nr of available bytes
|
||||||
|
*/
|
||||||
|
static inline unsigned int tsrb_free(const tsrb_t *rb)
|
||||||
|
{
|
||||||
|
return (rb->size - rb->writes + rb->reads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a byte from ringbuffer
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @return >=0 byte that has been read
|
||||||
|
* @return -1 if no byte available
|
||||||
|
*/
|
||||||
|
int tsrb_get_one(tsrb_t *rb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get bytes from ringbuffer
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @param[out] dst buffer to write to
|
||||||
|
* @param[in] n max number of bytes to write to @p dst
|
||||||
|
* @return nr of bytes written to @p dst
|
||||||
|
*/
|
||||||
|
int tsrb_get(tsrb_t *rb, char *dst, size_t n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a byte to ringbuffer
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @param[in] c Character to add to ringbuffer
|
||||||
|
* @return 0 on success
|
||||||
|
* @return -1 if no space available
|
||||||
|
*/
|
||||||
|
int tsrb_add_one(tsrb_t *rb, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add bytes to ringbuffer
|
||||||
|
* @param[in] rb Ringbuffer to operate on
|
||||||
|
* @param[in] src buffer to read from
|
||||||
|
* @param[in] n max number of bytes to read from @p src
|
||||||
|
* @return nr of bytes read from @p src
|
||||||
|
*/
|
||||||
|
int tsrb_add(tsrb_t *rb, const char *src, size_t n);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
#endif /* TSRB_H */
|
||||||
1
sys/tsrb/Makefile
Normal file
1
sys/tsrb/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
71
sys/tsrb/tsrb.c
Normal file
71
sys/tsrb/tsrb.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup sys
|
||||||
|
* @{
|
||||||
|
* @file
|
||||||
|
* @brief thread-safe ringbuffer implementation
|
||||||
|
*
|
||||||
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tsrb.h"
|
||||||
|
|
||||||
|
static void _push(tsrb_t *rb, char c)
|
||||||
|
{
|
||||||
|
rb->buf[rb->writes++ & (rb->size - 1)] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char _pop(tsrb_t *rb)
|
||||||
|
{
|
||||||
|
return rb->buf[rb->reads++ & (rb->size - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsrb_get_one(tsrb_t *rb)
|
||||||
|
{
|
||||||
|
if (!tsrb_empty(rb)) {
|
||||||
|
return _pop(rb);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsrb_get(tsrb_t *rb, char *dst, size_t n)
|
||||||
|
{
|
||||||
|
size_t tmp = n;
|
||||||
|
while (tmp && !tsrb_empty(rb)) {
|
||||||
|
*dst++ = _pop(rb);
|
||||||
|
tmp--;
|
||||||
|
}
|
||||||
|
return (n - tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsrb_add_one(tsrb_t *rb, char c)
|
||||||
|
{
|
||||||
|
if (!tsrb_full(rb)) {
|
||||||
|
_push(rb, c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsrb_add(tsrb_t *rb, const char *src, size_t n)
|
||||||
|
{
|
||||||
|
size_t tmp = n;
|
||||||
|
while (tmp && !tsrb_full(rb)) {
|
||||||
|
_push(rb, *src++);
|
||||||
|
tmp--;
|
||||||
|
}
|
||||||
|
return (n - tmp);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user