From 053fbd6f27e38b8b7d095b8a2d84f974b114e762 Mon Sep 17 00:00:00 2001 From: Alcaro Date: Fri, 24 Nov 2017 22:08:03 +0100 Subject: [PATCH] Add mmap-based nbio implementation (which is too fast for the tests but otherwise passes) --- libretro-common/file/nbio/nbio_unixmmap.c | 102 ++++++++++++++++++ libretro-common/include/file/nbio.h | 5 +- libretro-common/samples/file/nbio/nbio_test.c | 4 + 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 libretro-common/file/nbio/nbio_unixmmap.c diff --git a/libretro-common/file/nbio/nbio_unixmmap.c b/libretro-common/file/nbio/nbio_unixmmap.c new file mode 100644 index 0000000000..0decab5aac --- /dev/null +++ b/libretro-common/file/nbio/nbio_unixmmap.c @@ -0,0 +1,102 @@ +#include +#include + +#include + +#include +#include +#include + +struct nbio_t +{ + int fd; + int map_flags; + size_t len; + void* ptr; +}; + +struct nbio_t* nbio_open(const char * filename, unsigned mode) +{ + static const int o_flags[] = { O_RDONLY, O_RDWR|O_CREAT|O_TRUNC, O_RDWR, O_RDONLY, O_RDWR|O_CREAT|O_TRUNC }; + static const int map_flags[] = { PROT_READ, PROT_WRITE|PROT_READ, PROT_WRITE|PROT_READ, PROT_READ, PROT_WRITE|PROT_READ }; + + int fd; + size_t len; + void* ptr; + struct nbio_t* handle; + + fd = open(filename, o_flags[mode]|O_CLOEXEC, 0644); + if (fd < 0) return NULL; + + len = lseek(fd, 0, SEEK_END); + if (len != 0) + { + ptr = mmap(NULL, len, map_flags[mode], MAP_SHARED, fd, 0); + } + else + { + ptr = NULL; + } + if (ptr == MAP_FAILED) + { + close(fd); + return NULL; + } + + handle = malloc(sizeof(struct nbio_t)); + handle->fd = fd; + handle->map_flags = map_flags[mode]; + handle->len = len; + handle->ptr = ptr; + return handle; +} + +void nbio_begin_read(struct nbio_t* handle) +{ + /* not needed */ +} + +void nbio_begin_write(struct nbio_t* handle) +{ + /* not needed */ +} + +bool nbio_iterate(struct nbio_t* handle) +{ + return true; /* not needed */ +} + +void nbio_resize(struct nbio_t* handle, size_t len) +{ + if (ftruncate(handle->fd, len) != 0) + { + puts("ERROR - couldn't resize file (ftruncate)"); + abort(); /* this one returns void and I can't find any other way for it to report failure */ + } + munmap(handle->ptr, handle->len); + handle->ptr = mmap(NULL, len, handle->map_flags, MAP_SHARED, handle->fd, 0); + handle->len = len; + if (handle->ptr == MAP_FAILED) + { + puts("ERROR - couldn't resize file (mmap)"); + abort(); + } +} + +void* nbio_get_ptr(struct nbio_t* handle, size_t* len) +{ + if (len) *len = handle->len; + return handle->ptr; +} + +void nbio_cancel(struct nbio_t* handle) +{ + /* not needed */ +} + +void nbio_free(struct nbio_t* handle) +{ + close(handle->fd); + munmap(handle->ptr, handle->len); + free(handle); +} diff --git a/libretro-common/include/file/nbio.h b/libretro-common/include/file/nbio.h index 011eef55e6..45a3f7d347 100644 --- a/libretro-common/include/file/nbio.h +++ b/libretro-common/include/file/nbio.h @@ -42,6 +42,7 @@ RETRO_BEGIN_DECLS #define NBIO_UPDATE 2 #endif +/* these two are blocking; nbio_iterate always returns true, but that operation (or something earlier) may take arbitrarily long */ #ifndef BIO_READ #define BIO_READ 3 #endif @@ -59,13 +60,13 @@ struct nbio_t* nbio_open(const char * filename, unsigned mode); /* * Starts reading the given file. When done, it will be available in nbio_get_ptr. - * Can not be done if the structure was created with nbio_write. + * Can not be done if the structure was created with {N,}BIO_WRITE. */ void nbio_begin_read(struct nbio_t* handle); /* * Starts writing to the given file. Before this, you should've copied the data to nbio_get_ptr. - * Can not be done if the structure was created with nbio_read. + * Can not be done if the structure was created with {N,}BIO_READ. */ void nbio_begin_write(struct nbio_t* handle); diff --git a/libretro-common/samples/file/nbio/nbio_test.c b/libretro-common/samples/file/nbio/nbio_test.c index 3fadf8f888..c7163536c4 100644 --- a/libretro-common/samples/file/nbio/nbio_test.c +++ b/libretro-common/samples/file/nbio/nbio_test.c @@ -9,6 +9,8 @@ static void nbio_write_test(void) bool looped = false; void* ptr = NULL; struct nbio_t* write = nbio_open("test.bin", NBIO_WRITE); + if (!write) + puts("ERROR: nbio_open failed (1)"); nbio_resize(write, 1024*1024); @@ -33,6 +35,8 @@ static void nbio_read_test(void) bool looped = false; struct nbio_t* read = nbio_open("test.bin", NBIO_READ); void* ptr = nbio_get_ptr(read, &size); + if (!read) + puts("ERROR: nbio_open failed (2)"); if (size != 1024*1024) puts("ERROR: wrong size (2)");