Skip to content

Commit

Permalink
sys: add thread-safe ringbuffer implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
kaspar030 committed Sep 25, 2015
1 parent 187e318 commit 185f63f
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 0 deletions.
154 changes: 154 additions & 0 deletions sys/include/tsrb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <[email protected]>
*
* 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 <[email protected]>
*/

#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 change: 1 addition & 0 deletions sys/tsrb/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
71 changes: 71 additions & 0 deletions sys/tsrb/tsrb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <[email protected]>
*
* 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 <[email protected]>
*
* @}
*/

#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);
}

0 comments on commit 185f63f

Please sign in to comment.