summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-10-22 23:22:32 +0200
committerAnton Kling <anton@kling.gg>2023-10-22 23:22:32 +0200
commit9efad5f8d3ebbecdf8221d871f43bcbd15f1ac7d (patch)
treea7313186ea8dd331672dbd4c042f83731d2a1f7e
parent056216a800098ba98211ede122d974bf94a4e319 (diff)
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.
-rw-r--r--userland/libc/include/stdio.h3
-rw-r--r--userland/libc/stdio/fopen.c4
-rw-r--r--userland/libc/stdio/stdin.c33
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 <fcntl.h>
-#include <sys/stat.h>
#include <stdint.h>
#include <stdio.h>
+#include <sys/stat.h>
// 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;