Files
rosetta/lib/libc/io/stdio/ringbuf.c
T

272 lines
5.0 KiB
C

#include "file.h"
#include <errno.h>
#include <mango/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define DEFAULT_BUFFER_SIZE 4096
static int ringbuf_init(struct ringbuf *buf)
{
if (buf->buf_ptr) {
return SUCCESS;
}
if (!buf->buf_max) {
buf->buf_max = DEFAULT_BUFFER_SIZE;
}
buf->buf_ptr = malloc(buf->buf_max);
if (!buf->buf_ptr) {
return ENOMEM;
}
memset(buf->buf_ptr, 0x0, buf->buf_max);
return SUCCESS;
}
int __libc_ringbuf_get_read_buffer(
struct ringbuf *buf,
const char **out_bufp,
size_t *out_len)
{
int r = ringbuf_init(buf);
if (r != SUCCESS) {
return r;
}
size_t contiguous_capacity = 0;
if (buf->buf_readp > buf->buf_writep) {
contiguous_capacity = buf->buf_max - buf->buf_readp;
} else {
contiguous_capacity = buf->buf_writep - buf->buf_readp;
}
kern_tracef(
"OPEN READ: readp=%zu, writep=%zu, max=%zu -> %p cap=%zu",
buf->buf_readp,
buf->buf_writep,
buf->buf_max,
buf->buf_ptr + buf->buf_readp,
contiguous_capacity);
*out_len = contiguous_capacity;
if (contiguous_capacity == 0) {
*out_bufp = NULL;
} else {
*out_bufp = buf->buf_ptr + buf->buf_readp;
}
return SUCCESS;
}
void __libc_ringbuf_put_read_buffer(
struct ringbuf *buf,
const char **bufp,
size_t *len)
{
buf->buf_readp += *len;
if (buf->buf_readp == buf->buf_writep) {
buf->buf_readp = buf->buf_writep = 0;
}
kern_tracef("CLOSE READ: %p r=%zu", *bufp, *len);
*bufp = NULL;
*len = 0;
}
int __libc_ringbuf_get_write_buffer(
struct ringbuf *buf,
char **out_bufp,
size_t *out_len)
{
int r = ringbuf_init(buf);
if (r != SUCCESS) {
return r;
}
size_t contiguous_capacity = 0;
if (buf->buf_writep >= buf->buf_readp) {
contiguous_capacity = buf->buf_max - buf->buf_writep - 1;
if (buf->buf_readp > 0) {
contiguous_capacity++;
}
} else {
contiguous_capacity = buf->buf_readp - buf->buf_writep - 1;
}
kern_tracef(
"OPEN WRITE: readp=%zu, writep=%zu, max=%zu -> %p cap=%zu",
buf->buf_readp,
buf->buf_writep,
buf->buf_max,
buf->buf_ptr + buf->buf_readp,
contiguous_capacity);
*out_len = contiguous_capacity;
if (contiguous_capacity == 0) {
*out_bufp = NULL;
} else {
*out_bufp = buf->buf_ptr + buf->buf_writep;
}
return SUCCESS;
}
void __libc_ringbuf_put_write_buffer(
struct ringbuf *buf,
char **bufp,
size_t *len)
{
buf->buf_writep += *len;
if (buf->buf_readp == buf->buf_writep) {
buf->buf_readp = buf->buf_writep = 0;
}
kern_tracef(
"CLOSE WRITE: %p r=%zu (%c)",
*bufp,
*len,
*(char *)(*bufp));
*bufp = NULL;
*len = 0;
}
long __libc_ringbuf_read(struct ringbuf *buf, void *p, size_t count)
{
size_t nr_read = 0;
long r = 0;
while (nr_read < count) {
const char *src = NULL;
size_t available = 0;
r = __libc_ringbuf_get_read_buffer(buf, &src, &available);
if (r < 0) {
break;
}
char *dest = p + nr_read;
size_t to_copy = count - nr_read;
if (available == 0) {
__libc_ringbuf_put_read_buffer(buf, &src, &available);
break;
}
if (to_copy > available) {
to_copy = available;
}
memcpy(dest, src, to_copy);
nr_read += available;
__libc_ringbuf_put_read_buffer(buf, &src, &to_copy);
}
if (r < 0) {
return r;
}
return nr_read;
}
long __libc_ringbuf_write(struct ringbuf *buf, const void *p, size_t count)
{
size_t nr_written = 0;
long r = 0;
while (nr_written < count) {
char *dest = NULL;
size_t available = 0;
r = __libc_ringbuf_get_write_buffer(buf, &dest, &available);
if (r < 0) {
break;
}
const char *src = p + nr_written;
size_t to_copy = count - nr_written;
if (available == 0) {
__libc_ringbuf_put_write_buffer(buf, &dest, &available);
break;
}
if (to_copy > available) {
to_copy = available;
}
memcpy(dest, src, to_copy);
nr_written += available;
__libc_ringbuf_put_write_buffer(buf, &dest, &to_copy);
}
if (r < 0) {
return r;
}
return nr_written;
}
int __libc_ringbuf_clear(struct ringbuf *buf)
{
buf->buf_readp = buf->buf_writep = 0;
return 0;
}
int __libc_ringbuf_resize(struct ringbuf *buf, size_t max)
{
if (!(buf->buf_flags & RINGBUF_STATIC)) {
free(buf->buf_ptr);
buf->buf_ptr = NULL;
}
buf->buf_readp = buf->buf_writep = 0;
buf->buf_flags &= ~RINGBUF_STATIC;
buf->buf_max = max;
return 0;
}
int __libc_ringbuf_resize_static(struct ringbuf *buf, void *p, size_t max)
{
if (!(buf->buf_flags & RINGBUF_STATIC)) {
free(buf->buf_ptr);
buf->buf_ptr = NULL;
}
buf->buf_readp = buf->buf_writep = 0;
buf->buf_flags |= RINGBUF_STATIC;
buf->buf_ptr = p;
buf->buf_max = max;
return 0;
}
size_t __libc_ringbuf_available(const struct ringbuf *buf)
{
if (buf->buf_readp < buf->buf_writep) {
return buf->buf_writep - buf->buf_readp;
} else if (buf->buf_readp > buf->buf_writep) {
return buf->buf_max - buf->buf_readp + buf->buf_writep;
} else {
return 0;
}
}
size_t __libc_ringbuf_capacity(const struct ringbuf *buf)
{
if (buf->buf_readp > buf->buf_writep) {
return buf->buf_readp - buf->buf_writep - 1;
} else {
return buf->buf_max - buf->buf_writep + buf->buf_readp - 1;
}
}