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:
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));
+}