Skip to content

Instantly share code, notes, and snippets.

@cornedriesprong
Created May 18, 2024 09:29
Show Gist options
  • Save cornedriesprong/46589f2eaaf90b4b90346dfafcf956cb to your computer and use it in GitHub Desktop.
Save cornedriesprong/46589f2eaaf90b4b90346dfafcf956cb to your computer and use it in GitHub Desktop.
a simple, thread-safe, single producer-single consumer ring buffer in plain c
#include <assert.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
void *data;
atomic_int head, tail, num_entries, size;
} ring_buffer;
void init_ring_buffer(ring_buffer *rb, int size) {
rb->size = size;
rb->data = (char *)malloc(size * sizeof(char));
atomic_init(&rb->head, 0);
atomic_init(&rb->tail, 0);
atomic_init(&rb->num_entries, 0);
}
bool is_empty(ring_buffer *rb) { return atomic_load(&rb->num_entries) == 0; }
bool is_full(ring_buffer *rb) {
return atomic_load(&rb->num_entries) == rb->size;
}
void destroy_ring_buffer(ring_buffer *rb) { free(rb->data); }
void clear_buffer(ring_buffer *rb) {
atomic_store(&rb->head, 0);
atomic_store(&rb->tail, 0);
atomic_store(&rb->num_entries, 0);
memset(rb->data, 0, rb->size);
}
void enqueue(ring_buffer *rb, const void *src, uint32_t len) {
assert(!is_full(rb));
void *ptr = (char *)rb->data + atomic_load(&rb->tail);
memcpy(ptr, src, len);
atomic_fetch_add(&rb->num_entries, len);
atomic_store(&rb->tail, (atomic_load(&rb->tail) + len) % rb->size);
}
void *dequeue(ring_buffer *rb, uint32_t len) {
assert(!is_empty(rb));
void *ptr = (char *)rb->data + atomic_load(&rb->head);
atomic_store(&rb->head, (atomic_load(&rb->head) + len) % rb->size);
atomic_fetch_sub(&rb->num_entries, len);
return ptr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment