just wondered if any more-experienced-than-i devs might comment on
this. written in c for c (obviously). i realize it's not portable
outside of GNU GCC (regarding the GCC atomic builtin funcs
__sync_***). meant for a single reader thread and a single writer
thread. comments regarding thread safety very much welcome. thanks in
advance.
james.
#include "rng_buf.h" /* only prototypes the public functions and
typedefs the struct */
#include <stdlib.h>
#include <string.h>
#include "debug.h"
struct _RingBuffer
{
size_t count;
void** buf;
void** bufend;
void** volatile w;
void** volatile r;
};
RngBuf* rng_buf_new(size_t count)
{
size_t sz = 1;
RngBuf* mb = malloc(sizeof(RngBuf));
if (!mb)
{
return 0;
}
for (sz = 1; sz < count; sz <<= 1)
;
mb->buf = calloc(sz, sizeof(void*));
if (!mb->buf)
{
free(mb);
return 0;
}
mb->count = sz;
mb->bufend = mb->buf + mb->count - 1;
mb->w = mb->buf;
mb->r = mb->buf;
return mb;
}
void rng_buf_free(RngBuf* mb)
{
free(mb->buf);
free(mb);
}
size_t rng_buf_write(RngBuf* mb, const void* data)
{
if (__sync_bool_compare_and_swap(mb->w, 0, data))
{
if (!(__sync_bool_compare_and_swap(&mb->w, mb->bufend, mb->buf)))
__sync_add_and_fetch(&mb->w, sizeof(void*));
return (size_t)1;
}
return (size_t)0;
}
void* rng_buf_read(RngBuf* mb)
{
void* data;
if ((data = __sync_fetch_and_and(mb->r, 0)))
{
if (!__sync_bool_compare_and_swap(&mb->r, mb->bufend, mb->buf))
__sync_add_and_fetch(&mb->r, sizeof(void*));
return data;
}
return NULL;
}
void rng_buf_reset(RngBuf* mb)
{ /* needs work */
mb->r = mb->w = mb->buf;
}