rcx

library of miscellaneous bits of C code
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

commit 55dac6463872529b706115661516cca7a15e7e9e
parent f184ebe57ae8798cdc9e0d8f7df935c708c14e53
Author: Robert Russell <robertrussell.72001@gmail.com>
Date:   Tue, 14 Mar 2023 16:32:42 -0700

Add vmem module

Basically, these functions are wrappers around mmap.

There's no documentation yet.

Diffstat:
MMakefile | 4+++-
Ainc/vmem.h | 9+++++++++
Asrc/vmem.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile @@ -12,7 +12,8 @@ SRC =\ src/str.c\ src/unicode.c\ src/unix.c\ - src/utf8.c + src/utf8.c\ + src/vmem.c # src/opt.c needs work librcx.a: $(SRC:.c=.o) @@ -32,6 +33,7 @@ src/str.o: src/str.c inc/alloc.h inc/debug.h inc/def.h inc/log.h inc/rcx.h inc/s src/unicode.o: src/unicode.c inc/def.h inc/rcx.h gen/ucattab.inc config.mk src/unix.o: src/unix.c inc/debug.h inc/def.h inc/rcx.h inc/unix.h config.mk src/utf8.o: src/utf8.c inc/def.h inc/rcx.h inc/utf8.h config.mk +src/vmem.o: src/vmem.c inc/debug.h inc/def.h inc/log.h inc/rcx.h inc/vmem.h config.mk gen/ucattab.inc: gen tool/ucattab gen/UnicodeData.txt tool/ucattab gen/UnicodeData.txt > $@ diff --git a/inc/vmem.h b/inc/vmem.h @@ -0,0 +1,9 @@ +#pragma once + +#include "def.h" + +usize vmem_page_size(void); +void *vmem_alloc(void *p, usize size); +void *vmem_reserve(void *p, usize size, bool swap); +void *vmem_open(usize *len, void *p, char *path, char *opt); +void vmem_free(void *p, usize size); diff --git a/src/vmem.c b/src/vmem.c @@ -0,0 +1,100 @@ +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "debug.h" +#include "log.h" +#include "rcx.h" +#include "vmem.h" + +usize +vmem_page_size(void) { + long ps = sysconf(_SC_PAGE_SIZE); + require(ps > 0, + "vmem_page_size: unable to determine page size"); + require((ps & (ps - 1)) == 0, + "vmem_page_size: page size not a power of 2"); + return ps; +} + +void * +vmem_alloc(void *p, usize size) { + assert(((uptr)p & (uptr)(vmem_page_size() - 1)) == 0, + "vmem_alloc: misaligned pointer"); + int flags = MAP_PRIVATE | MAP_ANONYMOUS + | (p ? MAP_FIXED : 0); + void *q = mmap(p, size, PROT_READ | PROT_WRITE, flags, -1, 0); + if (q == MAP_FAILED) return 0; + return q; +} + +void * +vmem_reserve(void *p, usize size, bool swap) { + assert(((uptr)p & (uptr)(vmem_page_size() - 1)) == 0, + "vmem_reserve: misaligned pointer"); + int flags = MAP_PRIVATE | MAP_ANONYMOUS + | (p ? MAP_FIXED : 0) + | (!swap ? MAP_NORESERVE : 0); + void *q = mmap(p, size, PROT_NONE, flags, -1, 0); + if (q == MAP_FAILED) return 0; + return q; +} + +void * +vmem_open(usize *len, void *p, char *path, char *opt) { + assert(((uptr)p & (uptr)(vmem_page_size() - 1)) == 0, + "vmem_open: misaligned pointer"); + assert(strspn(opt, "crstwx") == strlen(opt), + "vmem_open: invalid option"); + + bool c = !!strchr(opt, 'c'); + bool r = !!strchr(opt, 'r'); + bool s = !!strchr(opt, 's'); + bool t = !!strchr(opt, 't'); + bool w = !!strchr(opt, 'w'); + bool x = !!strchr(opt, 'x'); + + struct stat sb; + if (stat(path, &sb) < 0) return 0; + bool grow = *len > sb.st_size; + + int oflags = O_CLOEXEC + | (c || x ? O_CREAT : 0) + | (t ? O_TRUNC : 0) + | (x ? O_EXCL : 0) + | ((w && s) || t || grow ? O_RDWR : O_RDONLY); + int prot = r || w + ? (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) + : PROT_NONE; + int mflags = (s ? MAP_SHARED : MAP_PRIVATE) + | (p ? MAP_FIXED : 0); + + int fd = open(path, oflags, 0666); + if (fd < 0) return 0; + + if (grow) { + if (ftruncate(fd, *len) < 0) { + close(fd); + return 0; + } + } + + void *q = mmap(p, *len == 0 ? sb.st_size : *len, prot, mflags, fd, 0); + close(fd); + if (q == MAP_FAILED) return 0; + + if (*len == 0) *len = sb.st_size; + return q; +} + +void +vmem_free(void *p, usize size) { + assert(((uptr)p & (uptr)(vmem_page_size() - 1)) == 0, + "vmem_free: misaligned pointer"); + int ret = munmap(p, size); + /* munmap should never fail. */ + if (ret < 0) r_errorf("vmem_free: munmap: %s", strerror(errno)); +}