From 3df15584d6663b330c344068dce7d36c6f27cf4b Mon Sep 17 00:00:00 2001 From: Anton Kling Date: Thu, 25 Apr 2024 21:46:31 +0200 Subject: Kernel: Add a ringbuffer This will be used later --- kernel/lib/ringbuffer.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel/lib/ringbuffer.h | 16 +++++++++ 2 files changed, 110 insertions(+) create mode 100644 kernel/lib/ringbuffer.c create mode 100644 kernel/lib/ringbuffer.h (limited to 'kernel/lib') diff --git a/kernel/lib/ringbuffer.c b/kernel/lib/ringbuffer.c new file mode 100644 index 0000000..425971d --- /dev/null +++ b/kernel/lib/ringbuffer.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include + +int ringbuffer_init(struct ringbuffer *rb, u32 buffer_size) { + rb->buffer_size = 0; + rb->read_ptr = 0; + rb->write_ptr = 0; + rb->buffer = kmalloc(buffer_size); + if (!rb->buffer) { + return 0; + } + rb->buffer_size = buffer_size; + return 1; +} + +u32 ringbuffer_write(struct ringbuffer *rb, const u8 *buffer, u32 len) { + const u32 orig_len = len; + for (; len > 0;) { + u32 buffer_left; + if (rb->write_ptr >= rb->read_ptr) { + buffer_left = rb->buffer_size - rb->write_ptr; + if (0 == rb->read_ptr && buffer_left > 0) { + buffer_left--; + } + } else { + buffer_left = (rb->read_ptr - rb->write_ptr - 1); + } + + if (0 == buffer_left) { + break; + } + + u32 write_len = min(len, buffer_left); + write_len = min(write_len, rb->buffer_size - rb->write_ptr); + memcpy(rb->buffer + rb->write_ptr, buffer, write_len); + buffer += write_len; + len -= write_len; + rb->write_ptr = (rb->write_ptr + write_len) % rb->buffer_size; + } + return orig_len - len; +} + +u32 ringbuffer_read(struct ringbuffer *rb, u8 *buffer, u32 len) { + const u32 orig_len = len; + for (; len > 0;) { + if (rb->read_ptr == rb->write_ptr) { + break; + } + u32 read_len; + if (rb->read_ptr >= rb->write_ptr) { + read_len = rb->buffer_size - rb->read_ptr; + } else if (rb->read_ptr < rb->write_ptr) { + read_len = rb->write_ptr - rb->read_ptr; + } + read_len = min(len, read_len); + + memcpy(buffer, rb->buffer + rb->read_ptr, read_len); + len -= read_len; + buffer += read_len; + rb->read_ptr = (rb->read_ptr + read_len) % rb->buffer_size; + } + return orig_len - len; +} + +void ringbuffer_free(struct ringbuffer *rb) { + kfree(rb->buffer); + rb->buffer = NULL; + rb->buffer_size = 0; + rb->write_ptr = 0; + rb->read_ptr = 0; +} + +#ifdef KERNEL_TEST +void ringbuffer_test(void) { + char buffer[4096]; + struct ringbuffer rb; + assert(ringbuffer_init(&rb, 6)); + assert(2 == ringbuffer_write(&rb, "ab", 2)); + assert(2 == ringbuffer_write(&rb, "cd", 2)); + assert(1 == ringbuffer_write(&rb, "ef", 2)); + assert(0 == ringbuffer_write(&rb, "gh", 2)); + assert(2 == ringbuffer_read(&rb, buffer, 2)); + assert(0 == memcmp(buffer, "ab", 2)); + assert(2 == ringbuffer_read(&rb, buffer, 2)); + assert(0 == memcmp(buffer, "cd", 2)); + assert(1 == ringbuffer_read(&rb, buffer, 2)); + assert(0 == memcmp(buffer, "e", 1)); + assert(0 == ringbuffer_read(&rb, buffer, 2)); + ringbuffer_free(&rb); +} +#endif // KERNEL_TEST diff --git a/kernel/lib/ringbuffer.h b/kernel/lib/ringbuffer.h new file mode 100644 index 0000000..c329af3 --- /dev/null +++ b/kernel/lib/ringbuffer.h @@ -0,0 +1,16 @@ +#include + +struct ringbuffer { + u8 *buffer; + u32 buffer_size; + u32 read_ptr; + u32 write_ptr; +}; + +int ringbuffer_init(struct ringbuffer *rb, u32 buffer_size); +u32 ringbuffer_write(struct ringbuffer *rb, const u8 *buffer, u32 len); +u32 ringbuffer_read(struct ringbuffer *rb, u8 *buffer, u32 len); +void ringbuffer_free(struct ringbuffer *rb); +#ifdef KERNEL_TEST +void ringbuffer_test(void); +#endif // KERNEL_TEST -- cgit v1.2.3