Created
August 4, 2017 02:57
-
-
Save tbodt/cc7b9169a5bb2cc95dc7e90dda32103b to your computer and use it in GitHub Desktop.
circular buffer
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
#include <pthread.h> | |
#include <string.h> | |
#include <errno.h> | |
#include "buffer.h" | |
#define lock(thing) pthread_mutex_lock(&(thing)->lock) | |
#define unlock(thing) pthread_mutex_unlock(&(thing)->lock) | |
#define wait_for(thing, what) pthread_cond_wait(&(thing)->what, &(thing)->lock) | |
#define signal(thing, what) pthread_cond_broadcast(&(thing)->what) | |
int buf_init(struct buffer *buf, size_t capacity) { | |
buf->data = malloc(capacity); | |
if (buf->data == NULL) | |
return ENOMEM; | |
buf->capacity = capacity; | |
buf->start = buf->unread = 0; | |
pthread_mutex_init(&buf->lock, NULL); | |
pthread_cond_init(&buf->changed, NULL); | |
return 0; | |
} | |
void buf_free(struct buffer *buf, size_t capacity) { | |
free(buf->data); | |
} | |
size_t buf_unread(struct buffer *buf) { | |
lock(buf); | |
size_t unread = buf->unread; | |
unlock(buf); | |
return unread; | |
} | |
size_t buf_remaining(struct buffer *buf) { | |
lock(buf); | |
size_t remaining = buf->capacity - buf->unread; | |
unlock(buf); | |
return remaining; | |
} | |
size_t buf_read(struct buffer *buf, char *str, size_t len, int flags) { | |
lock(buf); | |
while (len > buf_unread(buf)) { | |
if (flags & BUF_BLOCK) | |
wait_for(buf, changed); | |
else | |
return 0; | |
} | |
// read up to the end of the buffer | |
size_t len1 = len; | |
if (buf->start + len > buf->capacity) | |
len1 = buf->capacity - buf->start; | |
memcpy(str, buf->data + buf->start, len1); | |
// wrap around if necessary | |
memcpy(str + len1, buf->data, len - len1); | |
buf->start += len; | |
if (buf->start >= buf->capacity) | |
buf->start -= buf->capacity; | |
buf->unread -= len; | |
signal(buf, changed); | |
unlock(buf); | |
return len; | |
} | |
size_t buf_write(struct buffer *buf, char *str, size_t len, int flags) { | |
lock(buf); | |
while (len > buf_remaining(buf)) { | |
if (flags & BUF_BLOCK) | |
wait_for(buf, changed); | |
else | |
return 0; | |
} | |
size_t end = buf->start + buf->unread; | |
// copy data up to the end of the buffer | |
size_t len1 = len; | |
if (end + len > buf->capacity) | |
len1 = buf->capacity - end; | |
memcpy(buf->data + end, str, len1); | |
// if we have to wrap around, do so | |
memcpy(buf->data, str + len1, len - len1); | |
buf->unread += len; | |
signal(buf, changed); | |
unlock(buf); | |
return len; | |
} |
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
#ifndef BUFFER_H | |
#define BUFFER_H | |
#include <pthread.h> | |
// A circular buffer. | |
struct buffer { | |
char *data; | |
size_t capacity; | |
size_t start; // first byte of data | |
size_t unread; | |
pthread_mutex_t lock; | |
pthread_cond_t changed; | |
}; | |
int buf_init(struct buffer *buf, size_t size); | |
void buf_free(struct buffer *buf, size_t capacity); | |
// Returns how many bytes of data are currently in the buffer. | |
size_t buf_unread(struct buffer *buf); | |
// Returns how much more room there is in the buffer. | |
size_t buf_remaining(struct buffer *buf); | |
// If flags is specified as BUF_BLOCK, will block if there's not enough data or | |
// not enough space. Otherwise, just return 0. | |
#define BUF_BLOCK 1 | |
size_t buf_read(struct buffer *buf, char *str, size_t len, int flags); | |
size_t buf_write(struct buffer *buf, char *str, size_t len, int flags); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment