From f8f5d9102eed6de69c05649ece6ac12e82769ed4 Mon Sep 17 00:00:00 2001 From: Avril Date: Fri, 9 Jul 2021 19:54:46 +0100 Subject: [PATCH] mmap() API facade. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mmap() API anon test passes. Fortune for naka's current commit: Future small blessing − 末小吉 --- include/map.h | 44 ++++++++++++++++++++++++++++++++++ src/map.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/map.c | 19 +++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 include/map.h create mode 100644 src/map.c create mode 100644 src/tests/map.c diff --git a/include/map.h b/include/map.h new file mode 100644 index 0000000..ecbcee3 --- /dev/null +++ b/include/map.h @@ -0,0 +1,44 @@ +//! Memory mapping abstraction +#ifndef _MAP_H +#define _MAP_H + +#include +#include "ints.h" + +typedef enum mm_err { + MAP_ERR_UNKNOWN = 0, + MAP_SUCCESS = 1, + + MAP_ERR_MMAP, + MAP_ERR_UNMAP, + MAP_ERR_OPEN, + MAP_ERR_CLOSE, +} map_result_t; + +typedef union memory_map { + // Common + struct { + void* origin; + usize len; + }; + // Specific to anon / file + struct mm_file { + void* origin; + usize len; + + off_t fd_offset; + int fd; + } file; + struct mm_anon { + void* origin; + usize len; + } anon; + +} map_t; + +map_result_t map_fd(int fd, bool write, usize size, off_t offset, map_t *pOUT map); +map_result_t map_file(const char* file, bool write, usize size, off_t offset, map_t *pOUT map); +map_result_t map_anon(void* ptr, usize len, map_t *pOUT map); +map_result_t map_free(map_t map); + +#endif /* _MAP_H */ diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..3750c4c --- /dev/null +++ b/src/map.c @@ -0,0 +1,63 @@ + +#include +#include +#include +#include +#include + +#include +#include + +// Set all bytes to 0xff (ints i.e. fd will be -1) +static inline void _map_init(map_t *pOUT map) +{ + memset(map, 0xff, sizeof(map_t)); +} + +static inline bool _map_is_file(const map_t* map) +{ + return map->file.fd > 0; +} + +map_result_t map_fd(int fd, bool write, usize size, off_t offset, map_t *pOUT map) +{ + void* ptr = mmap(NULL, size, PROT_READ | (write ? PROT_WRITE : 0), MAP_SHARED, fd, offset); + if(ptr == MAP_FAILED) return MAP_ERR_MMAP; + map->file = (struct mm_file){ + .origin = ptr, + .len = size, + .fd = fd, + .fd_offset = offset, + }; + return MAP_SUCCESS; +} + +map_result_t map_file(const char* file, bool write, usize size, off_t offset, map_t *pOUT map) +{ + int fd = open(file, write ? O_RDWR : O_RDONLY); + if(fd < 0) return MAP_ERR_OPEN; + return map_fd(fd, write, size, offset, map); +} + +map_result_t map_anon(void* ptr, usize len, map_t *pOUT map) +{ + ptr = mmap(ptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | (ptr ? MAP_FIXED : 0), -1, 0); + if(ptr==MAP_FAILED) return MAP_ERR_MMAP; + + // Make sure .file.fd is -1, so we can tell this is anon in `map_free()`. + _map_init(map); + map->anon = (struct mm_anon) { + .origin = ptr, + .len = len, + }; + return MAP_SUCCESS; +} + +map_result_t map_free(map_t map) +{ + if( munmap(map.anon.origin, map.anon.len) != 0) return MAP_ERR_UNMAP; + if( _map_is_file(&map) ) { + if( close(map.file.fd) != 0 ) return MAP_ERR_CLOSE; + } + return MAP_SUCCESS; +} diff --git a/src/tests/map.c b/src/tests/map.c new file mode 100644 index 0000000..f0038b7 --- /dev/null +++ b/src/tests/map.c @@ -0,0 +1,19 @@ + +#include + +#include +#include + +DEFTEST(map_anon) +{ + map_t map; + TEST_ASSERT(map_anon(NULL, 1024, &map) == MAP_SUCCESS); + + memset(map.origin, 0xab, map.len); + TEST_ASSERT( ((u8*)map.origin)[10] == 0xab ); + + TEST_ASSERT(map_free(map) == MAP_SUCCESS); + + return TEST_OK; +} +RUNTEST_DEBUG(map_anon)