forked from RIOT-OS/RIOT
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sys: add thread-safe ringbuffer implementation
- Loading branch information
Showing
3 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include $(RIOTBASE)/Makefile.base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |