mirror of
https://github.com/ish-app/ish.git
synced 2026-01-18 13:57:29 +00:00
85 lines
2.0 KiB
C
85 lines
2.0 KiB
C
#include <string.h>
|
|
#include "util/buffer.h"
|
|
#include "kernel/errno.h"
|
|
|
|
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) {
|
|
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;
|
|
notify(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;
|
|
notify(buf, changed);
|
|
unlock(buf);
|
|
return len;
|
|
}
|
|
|