From 9efad5f8d3ebbecdf8221d871f43bcbd15f1ac7d Mon Sep 17 00:00:00 2001 From: Anton Kling Date: Sun, 22 Oct 2023 23:22:32 +0200 Subject: libc: Add a cache to the fread function for reading from files on disk. This helps a ton when using functions such as fscanf that reads from a FILE byte by byte. By creating a cache it avoids a ton of 'read' syscalls that would otherwise be made. --- userland/libc/include/stdio.h | 3 +++ userland/libc/stdio/fopen.c | 4 +++- userland/libc/stdio/stdin.c | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/userland/libc/include/stdio.h b/userland/libc/include/stdio.h index 014e2ac..22afbb2 100644 --- a/userland/libc/include/stdio.h +++ b/userland/libc/include/stdio.h @@ -34,6 +34,9 @@ struct __IO_FILE { uint8_t is_eof; uint8_t has_error; uint64_t file_size; + uint8_t *read_buffer; + uint32_t read_buffer_stored; + uint32_t read_buffer_has_read; void *cookie; }; diff --git a/userland/libc/stdio/fopen.c b/userland/libc/stdio/fopen.c index a29c7ef..6a3f374 100644 --- a/userland/libc/stdio/fopen.c +++ b/userland/libc/stdio/fopen.c @@ -1,7 +1,7 @@ #include -#include #include #include +#include // FIXME: All modes not implemented // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html @@ -53,5 +53,7 @@ FILE *fopen(const char *pathname, const char *mode) { r->file_size = s.st_size; r->cookie = NULL; r->fd = fd; + r->read_buffer = NULL; + r->read_buffer_stored = 0; return r; } diff --git a/userland/libc/stdio/stdin.c b/userland/libc/stdio/stdin.c index ae3ab8d..2e1e50f 100644 --- a/userland/libc/stdio/stdin.c +++ b/userland/libc/stdio/stdin.c @@ -12,7 +12,7 @@ size_t write_fd(FILE *f, const unsigned char *s, size_t l) { return rc; } -size_t read_fd(FILE *f, unsigned char *s, size_t l) { +size_t non_cache_read_fd(FILE *f, unsigned char *s, size_t l) { int rc = pread(f->fd, s, l, f->offset_in_file); if (rc == 0) f->is_eof = 1; @@ -20,11 +20,40 @@ size_t read_fd(FILE *f, unsigned char *s, size_t l) { f->has_error = 1; return 0; } - f->offset_in_file += rc; return rc; } +size_t read_fd(FILE *f, unsigned char *s, size_t l) { + if (0 == l) + return 0; + if (!f->read_buffer) { + f->read_buffer = malloc(4096); + f->read_buffer_stored = 0; + f->read_buffer_has_read = 0; + } + if (f->read_buffer_stored > 0) { + size_t read_len = min(l, f->read_buffer_stored); + f->offset_in_file += read_len; + memcpy(s, f->read_buffer + f->read_buffer_has_read, read_len); + f->read_buffer_stored -= read_len; + f->read_buffer_has_read += read_len; + s += read_len; + l -= read_len; + return read_len + read_fd(f, s, l); + } + if (0 == f->read_buffer_stored) { + f->read_buffer_stored = non_cache_read_fd(f, f->read_buffer, 4096); + f->read_buffer_has_read = 0; + if (0 == f->read_buffer_stored) { + return 0; + } + return read_fd(f, s, l); + } + assert(0); +} + int seek_fd(FILE *stream, long offset, int whence) { + stream->read_buffer_stored = 0; switch (whence) { case SEEK_SET: stream->offset_in_file = offset; -- cgit v1.2.3