mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-08 20:28:30 +00:00
Simplify memory manager
This commit is contained in:
parent
5a9a08d1cf
commit
01587de761
40 changed files with 451 additions and 311 deletions
|
@ -16,8 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/getauxval.internal.h"
|
||||
#include "libc/nt/struct/systeminfo.h"
|
||||
#include "libc/nt/systeminfo.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
|
@ -35,11 +38,17 @@ unsigned long getauxval(unsigned long key) {
|
|||
x = __getauxval(key);
|
||||
if (key == AT_PAGESZ) {
|
||||
if (!x.isfound) {
|
||||
if (!IsWindows()) {
|
||||
#ifdef __aarch64__
|
||||
x.value = 16384;
|
||||
x.value = 16384;
|
||||
#else
|
||||
x.value = 4096;
|
||||
x.value = 4096;
|
||||
#endif
|
||||
} else {
|
||||
struct NtSystemInfo si;
|
||||
GetSystemInfo(&si);
|
||||
x.value = si.dwPageSize;
|
||||
}
|
||||
}
|
||||
x.isfound = true;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ static size_t __get_stack_size(int pagesz, uintptr_t start, uintptr_t top) {
|
|||
* This function works on every OS except Windows.
|
||||
*/
|
||||
struct AddrSize __get_main_stack(void) {
|
||||
int pagesz = getauxval(AT_PAGESZ);
|
||||
int pagesz = getpagesize();
|
||||
uintptr_t start = (uintptr_t)__argv;
|
||||
uintptr_t top = __get_main_top(pagesz);
|
||||
uintptr_t bot = top - __get_stack_size(pagesz, start, top);
|
||||
|
|
28
libc/intrin/getpagesize.c
Normal file
28
libc/intrin/getpagesize.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
/**
|
||||
* Returns granularity of memory manager.
|
||||
* @see sysconf(_SC_PAGE_SIZE) which is portable
|
||||
*/
|
||||
int getpagesize(void) {
|
||||
return getauxval(AT_PAGESZ);
|
||||
}
|
|
@ -17,14 +17,21 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/struct/systeminfo.h"
|
||||
#include "libc/nt/systeminfo.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
int __granularity(void) {
|
||||
if (IsWindows())
|
||||
return 65536;
|
||||
static int res;
|
||||
if (!res)
|
||||
res = getauxval(AT_PAGESZ);
|
||||
if (!res) {
|
||||
if (!IsWindows()) {
|
||||
res = getpagesize();
|
||||
} else {
|
||||
struct NtSystemInfo si;
|
||||
GetSystemInfo(&si);
|
||||
res = si.dwAllocationGranularity;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -155,17 +155,20 @@ __funline bool kischarmisaligned(const char *p, signed char t) {
|
|||
}
|
||||
|
||||
privileged static bool32 kisdangerous_unlocked(const char *addr) {
|
||||
struct Dll *e, *e2;
|
||||
for (e = dll_first(__maps.used); e; e = e2) {
|
||||
e2 = dll_next(__maps.used, e);
|
||||
struct Map *map = MAP_CONTAINER(e);
|
||||
if (map->addr <= addr && addr < map->addr + map->size) {
|
||||
dll_remove(&__maps.used, e);
|
||||
dll_make_first(&__maps.used, e);
|
||||
return !(map->prot & PROT_READ);
|
||||
}
|
||||
struct Dll *e;
|
||||
if ((e = dll_first(__maps.used))) {
|
||||
do {
|
||||
struct Map *map = MAP_CONTAINER(e);
|
||||
if (map->addr <= addr && addr < map->addr + map->size) {
|
||||
dll_remove(&__maps.used, e);
|
||||
dll_make_first(&__maps.used, e);
|
||||
return !(map->prot & PROT_READ);
|
||||
}
|
||||
} while ((e = dll_next(__maps.used, e)));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
privileged bool32 kisdangerous(const void *addr) {
|
||||
|
|
|
@ -34,8 +34,6 @@ struct Maps __maps;
|
|||
void __maps_add(struct Map *map) {
|
||||
dll_init(&map->elem);
|
||||
dll_make_first(&__maps.used, &map->elem);
|
||||
map->next = __maps.maps;
|
||||
__maps.maps = map;
|
||||
++__maps.count;
|
||||
}
|
||||
|
||||
|
@ -44,23 +42,31 @@ static void __maps_adder(struct Map *map, int pagesz) {
|
|||
__maps_add(map);
|
||||
}
|
||||
|
||||
void __maps_stack(void *stackaddr, int pagesz, size_t stacksize, int stackprot,
|
||||
intptr_t stackhand) {
|
||||
__maps.stack.addr = stackaddr;
|
||||
__maps.stack.size = stacksize;
|
||||
void __maps_stack(char *stackaddr, int pagesz, int guardsize, size_t stacksize,
|
||||
int stackprot, intptr_t stackhand) {
|
||||
__maps.stack.addr = stackaddr + guardsize;
|
||||
__maps.stack.size = stacksize - guardsize;
|
||||
__maps.stack.prot = stackprot;
|
||||
__maps.stack.h = stackhand;
|
||||
__maps.stack.hand = -1;
|
||||
__maps_adder(&__maps.stack, pagesz);
|
||||
if (guardsize) {
|
||||
__maps.guard.addr = stackaddr;
|
||||
__maps.guard.size = guardsize;
|
||||
__maps.guard.prot = PROT_NONE;
|
||||
__maps.guard.hand = stackhand;
|
||||
__maps_adder(&__maps.guard, pagesz);
|
||||
}
|
||||
}
|
||||
|
||||
void __maps_init(void) {
|
||||
int pagesz = getauxval(AT_PAGESZ);
|
||||
int pagesz = getpagesize();
|
||||
|
||||
// record _start() stack mapping
|
||||
if (!IsWindows()) {
|
||||
struct AddrSize stack;
|
||||
stack = __get_main_stack();
|
||||
__maps_stack(stack.addr, pagesz, stack.size, (uintptr_t)ape_stack_prot, 0);
|
||||
__maps_stack(stack.addr, pagesz, 0, stack.size, (uintptr_t)ape_stack_prot,
|
||||
0);
|
||||
}
|
||||
|
||||
// record .text and .data mappings
|
||||
|
@ -78,15 +84,15 @@ void __maps_init(void) {
|
|||
__maps_adder(&text, pagesz);
|
||||
}
|
||||
|
||||
privileged void __maps_lock(void) {
|
||||
privileged bool __maps_lock(void) {
|
||||
struct CosmoTib *tib;
|
||||
if (!__threaded)
|
||||
return;
|
||||
return false;
|
||||
if (!__tls_enabled)
|
||||
return;
|
||||
return false;
|
||||
tib = __get_tls_privileged();
|
||||
if (tib->tib_relock_maps++)
|
||||
return;
|
||||
return true;
|
||||
while (atomic_exchange_explicit(&__maps.lock, 1, memory_order_acquire)) {
|
||||
#if defined(__GNUC__) && defined(__aarch64__)
|
||||
__asm__ volatile("yield");
|
||||
|
@ -94,6 +100,7 @@ privileged void __maps_lock(void) {
|
|||
__asm__ volatile("pause");
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
privileged void __maps_unlock(void) {
|
||||
|
|
|
@ -8,7 +8,6 @@ COSMOPOLITAN_C_START_
|
|||
#define MAP_CONTAINER(e) DLL_CONTAINER(struct Map, elem, e)
|
||||
|
||||
struct Map {
|
||||
struct Map *next; /* for __maps.maps */
|
||||
char *addr; /* granule aligned */
|
||||
size_t size; /* must be nonzero */
|
||||
struct Dll elem; /* for __maps.free */
|
||||
|
@ -18,18 +17,20 @@ struct Map {
|
|||
bool iscow; /* windows nt only */
|
||||
bool readonlyfile; /* windows nt only */
|
||||
unsigned visited; /* used for checks */
|
||||
intptr_t h; /* windows nt only */
|
||||
intptr_t hand; /* windows nt only */
|
||||
};
|
||||
|
||||
struct Maps {
|
||||
unsigned mono;
|
||||
atomic_int lock;
|
||||
struct Map *maps;
|
||||
struct Dll *free;
|
||||
struct Map stack;
|
||||
struct Dll *used;
|
||||
size_t count;
|
||||
size_t pages;
|
||||
struct Map stack;
|
||||
struct Map guard;
|
||||
bool once;
|
||||
atomic_ulong rollo;
|
||||
};
|
||||
|
||||
struct AddrSize {
|
||||
|
@ -40,16 +41,15 @@ struct AddrSize {
|
|||
extern struct Maps __maps;
|
||||
|
||||
void __maps_init(void);
|
||||
void __maps_lock(void);
|
||||
bool __maps_lock(void);
|
||||
void __maps_check(void);
|
||||
void __maps_unlock(void);
|
||||
void __maps_add(struct Map *);
|
||||
struct Map *__maps_alloc(void);
|
||||
void __maps_free(struct Map *);
|
||||
void __maps_insert(struct Map *);
|
||||
int __munmap(char *, size_t, bool);
|
||||
void *__mmap(char *, size_t, int, int, int, int64_t);
|
||||
void __maps_stack(void *, int, size_t, int, intptr_t);
|
||||
void __maps_stack(char *, int, int, size_t, int, intptr_t);
|
||||
struct AddrSize __get_main_stack(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
|
@ -54,9 +55,9 @@
|
|||
|
||||
#define MAP_FIXED_NOREPLACE_linux 0x100000
|
||||
|
||||
#define PGUP(x) (((x) + granularity - 1) & -granularity)
|
||||
#define PGUP(x) (((x) + pagesz - 1) & -pagesz)
|
||||
|
||||
#if MMDEBUG
|
||||
#if !MMDEBUG
|
||||
#define ASSERT(x) (void)0
|
||||
#else
|
||||
#define ASSERT(x) \
|
||||
|
@ -72,14 +73,14 @@
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
static atomic_ulong rollo;
|
||||
|
||||
static bool overlaps_existing_map(const char *addr, size_t size) {
|
||||
int granularity = __granularity();
|
||||
for (struct Map *map = __maps.maps; map; map = map->next)
|
||||
static bool overlaps_existing_map(const char *addr, size_t size, int pagesz) {
|
||||
for (struct Dll *e = dll_first(__maps.used); e;
|
||||
e = dll_next(__maps.used, e)) {
|
||||
struct Map *map = MAP_CONTAINER(e);
|
||||
if (MAX(addr, map->addr) <
|
||||
MIN(addr + PGUP(size), map->addr + PGUP(map->size)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -87,43 +88,44 @@ void __maps_check(void) {
|
|||
#if MMDEBUG
|
||||
size_t maps = 0;
|
||||
size_t pages = 0;
|
||||
int granularity = getauxval(AT_PAGESZ);
|
||||
unsigned id = __maps.mono++;
|
||||
for (struct Map *map = __maps.maps; map; map = map->next) {
|
||||
int pagesz = getpagesize();
|
||||
unsigned id = ++__maps.mono;
|
||||
for (struct Dll *e = dll_first(__maps.used); e;
|
||||
e = dll_next(__maps.used, e)) {
|
||||
struct Map *map = MAP_CONTAINER(e);
|
||||
ASSERT(map->addr != MAP_FAILED);
|
||||
ASSERT(map->visited != id);
|
||||
ASSERT(map->size);
|
||||
map->visited = id;
|
||||
pages += PGUP(map->size) / granularity;
|
||||
pages += (map->size + getpagesize() - 1) / getpagesize();
|
||||
maps += 1;
|
||||
}
|
||||
ASSERT(maps = __maps.count);
|
||||
ASSERT(pages == __maps.pages);
|
||||
for (struct Dll *e = dll_first(__maps.used); e;
|
||||
e = dll_next(__maps.used, e)) {
|
||||
ASSERT(MAP_CONTAINER(e)->visited == id);
|
||||
--maps;
|
||||
}
|
||||
ASSERT(maps == 0);
|
||||
for (struct Map *m1 = __maps.maps; m1; m1 = m1->next)
|
||||
for (struct Map *m2 = m1->next; m2; m2 = m2->next)
|
||||
struct Map *m1 = MAP_CONTAINER(e);
|
||||
for (struct Dll *f = dll_next(__maps.used, e); f;
|
||||
f = dll_next(__maps.used, f)) {
|
||||
struct Map *m2 = MAP_CONTAINER(f);
|
||||
ASSERT(MAX(m1->addr, m2->addr) >=
|
||||
MIN(m1->addr + PGUP(m1->size), m2->addr + PGUP(m2->size)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void __maps_free(struct Map *map) {
|
||||
map->next = 0;
|
||||
map->size = 0;
|
||||
map->addr = MAP_FAILED;
|
||||
ASSERT(dll_is_alone(&map->elem));
|
||||
dll_make_last(&__maps.free, &map->elem);
|
||||
}
|
||||
|
||||
void __maps_insert(struct Map *map) {
|
||||
struct Map *last = __maps.maps;
|
||||
int granularity = getauxval(AT_PAGESZ);
|
||||
__maps.pages += PGUP(map->size) / granularity;
|
||||
static void __maps_insert(struct Map *map) {
|
||||
struct Dll *e = dll_first(__maps.used);
|
||||
struct Map *last = e ? MAP_CONTAINER(e) : 0;
|
||||
__maps.pages += (map->size + getpagesize() - 1) / getpagesize();
|
||||
if (last && !IsWindows() && //
|
||||
map->addr == last->addr + last->size && //
|
||||
(map->flags & MAP_ANONYMOUS) && //
|
||||
|
@ -155,7 +157,6 @@ struct Map *__maps_alloc(void) {
|
|||
if ((e = dll_first(__maps.free))) {
|
||||
dll_remove(&__maps.free, e);
|
||||
map = MAP_CONTAINER(e);
|
||||
map->next = 0;
|
||||
return map;
|
||||
}
|
||||
int granularity = __granularity();
|
||||
|
@ -172,40 +173,43 @@ struct Map *__maps_alloc(void) {
|
|||
dll_init(&map[i].elem);
|
||||
__maps_free(map + i);
|
||||
}
|
||||
map->next = 0;
|
||||
return map;
|
||||
}
|
||||
|
||||
int __munmap(char *addr, size_t size, bool untrack_only) {
|
||||
|
||||
// validate arguments
|
||||
int pagesz = getauxval(AT_PAGESZ);
|
||||
int pagesz = getpagesize();
|
||||
int granularity = __granularity();
|
||||
if (((uintptr_t)addr & (granularity - 1)) || //
|
||||
!size || (uintptr_t)addr + size < size)
|
||||
return einval();
|
||||
|
||||
// normalize size
|
||||
size = (size + granularity - 1) & -granularity;
|
||||
|
||||
// untrack mappings
|
||||
int rc = 0;
|
||||
struct Dll *cur;
|
||||
struct Dll *next;
|
||||
struct Dll *delete = 0;
|
||||
__maps_lock();
|
||||
struct Map *map = __maps.maps;
|
||||
struct Map **prev = &__maps.maps;
|
||||
while (map) {
|
||||
if (__maps_lock()) {
|
||||
__maps_unlock();
|
||||
return edeadlk();
|
||||
}
|
||||
for (cur = dll_first(__maps.used); cur; cur = next) {
|
||||
next = dll_next(__maps.used, cur);
|
||||
struct Map *map = MAP_CONTAINER(cur);
|
||||
char *map_addr = map->addr;
|
||||
size_t map_size = map->size;
|
||||
struct Map *next = map->next;
|
||||
if (MAX(addr, map_addr) <
|
||||
MIN(addr + PGUP(size), map_addr + PGUP(map_size))) {
|
||||
if (addr <= map_addr && addr + PGUP(size) >= map_addr + PGUP(map_size)) {
|
||||
if (MAX(addr, map_addr) < MIN(addr + size, map_addr + PGUP(map_size))) {
|
||||
if (addr <= map_addr && addr + size >= map_addr + PGUP(map_size)) {
|
||||
// remove mapping completely
|
||||
dll_remove(&__maps.used, &map->elem);
|
||||
dll_make_first(&delete, &map->elem);
|
||||
*prev = next;
|
||||
dll_remove(&__maps.used, cur);
|
||||
dll_make_first(&delete, cur);
|
||||
__maps.pages -= (map_size + pagesz - 1) / pagesz;
|
||||
__maps.count -= 1;
|
||||
map = next;
|
||||
continue;
|
||||
__maps_check();
|
||||
} else if (IsWindows()) {
|
||||
// you can't carve up memory maps on windows. our mmap() makes
|
||||
// this not a problem (for non-enormous memory maps) by making
|
||||
|
@ -225,14 +229,14 @@ int __munmap(char *addr, size_t size, bool untrack_only) {
|
|||
if (!(map->flags & MAP_ANONYMOUS))
|
||||
map->off += left;
|
||||
__maps.pages -= (left + pagesz - 1) / pagesz;
|
||||
__maps_check();
|
||||
leftmap->addr = map_addr;
|
||||
leftmap->size = left;
|
||||
dll_make_first(&delete, &leftmap->elem);
|
||||
__maps_check();
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else if (addr + PGUP(size) >= map_addr + PGUP(map_size)) {
|
||||
} else if (addr + size >= map_addr + PGUP(map_size)) {
|
||||
// shave off righthand side of mapping
|
||||
size_t left = addr - map_addr;
|
||||
size_t right = map_addr + map_size - addr;
|
||||
|
@ -240,23 +244,22 @@ int __munmap(char *addr, size_t size, bool untrack_only) {
|
|||
if ((rightmap = __maps_alloc())) {
|
||||
map->size = left;
|
||||
__maps.pages -= (right + pagesz - 1) / pagesz;
|
||||
__maps_check();
|
||||
rightmap->addr = addr;
|
||||
rightmap->size = right;
|
||||
dll_make_first(&delete, &rightmap->elem);
|
||||
__maps_check();
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
// punch hole in mapping
|
||||
size_t left = addr - map_addr;
|
||||
size_t middle = PGUP(size);
|
||||
size_t middle = size;
|
||||
size_t right = map_size - middle - left;
|
||||
struct Map *leftmap;
|
||||
if ((leftmap = __maps_alloc())) {
|
||||
struct Map *middlemap;
|
||||
if ((middlemap = __maps_alloc())) {
|
||||
leftmap->next = map;
|
||||
leftmap->addr = map_addr;
|
||||
leftmap->size = left;
|
||||
leftmap->off = map->off;
|
||||
|
@ -267,13 +270,12 @@ int __munmap(char *addr, size_t size, bool untrack_only) {
|
|||
if (!(map->flags & MAP_ANONYMOUS))
|
||||
map->off += left + middle;
|
||||
dll_make_first(&__maps.used, &leftmap->elem);
|
||||
*prev = leftmap;
|
||||
__maps.pages -= (middle + pagesz - 1) / pagesz;
|
||||
__maps.count += 1;
|
||||
__maps_check();
|
||||
middlemap->addr = addr;
|
||||
middlemap->size = size;
|
||||
dll_make_first(&delete, &middlemap->elem);
|
||||
__maps_check();
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
|
@ -282,22 +284,21 @@ int __munmap(char *addr, size_t size, bool untrack_only) {
|
|||
}
|
||||
}
|
||||
}
|
||||
prev = &map->next;
|
||||
map = next;
|
||||
}
|
||||
__maps_unlock();
|
||||
|
||||
// delete mappings
|
||||
for (struct Dll *e = dll_first(delete); e; e = dll_next(delete, e)) {
|
||||
map = MAP_CONTAINER(e);
|
||||
struct Map *map = MAP_CONTAINER(e);
|
||||
if (!untrack_only) {
|
||||
if (!IsWindows()) {
|
||||
if (sys_munmap(map->addr, map->size))
|
||||
rc = -1;
|
||||
} else {
|
||||
} else if (map->hand != -1) {
|
||||
ASSERT(!((uintptr_t)map->addr & (granularity - 1)));
|
||||
if (!UnmapViewOfFile(map->addr))
|
||||
rc = -1;
|
||||
if (!CloseHandle(map->h))
|
||||
if (!CloseHandle(map->hand))
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
|
@ -319,7 +320,7 @@ int __munmap(char *addr, size_t size, bool untrack_only) {
|
|||
}
|
||||
|
||||
static void *__mmap_chunk(void *addr, size_t size, int prot, int flags, int fd,
|
||||
int64_t off, int granularity) {
|
||||
int64_t off, int pagesz, int granularity) {
|
||||
|
||||
// polyfill nuances of fixed mappings
|
||||
int sysflags = flags;
|
||||
|
@ -334,7 +335,7 @@ static void *__mmap_chunk(void *addr, size_t size, int prot, int flags, int fd,
|
|||
sysflags |= MAP_FIXED_NOREPLACE_linux;
|
||||
} else if (IsFreebsd() || IsNetbsd()) {
|
||||
sysflags |= MAP_FIXED;
|
||||
if (overlaps_existing_map(addr, size))
|
||||
if (overlaps_existing_map(addr, size, pagesz))
|
||||
return (void *)eexist();
|
||||
} else {
|
||||
noreplace = true;
|
||||
|
@ -345,7 +346,10 @@ static void *__mmap_chunk(void *addr, size_t size, int prot, int flags, int fd,
|
|||
|
||||
// allocate Map object
|
||||
struct Map *map;
|
||||
__maps_lock();
|
||||
if (__maps_lock()) {
|
||||
__maps_unlock();
|
||||
return (void *)edeadlk();
|
||||
}
|
||||
map = __maps_alloc();
|
||||
__maps_unlock();
|
||||
if (!map)
|
||||
|
@ -405,7 +409,7 @@ TryAgain:
|
|||
map->off = off;
|
||||
map->prot = prot;
|
||||
map->flags = flags;
|
||||
map->h = res.maphandle;
|
||||
map->hand = res.maphandle;
|
||||
if (IsWindows()) {
|
||||
map->iscow = (flags & MAP_TYPE) != MAP_SHARED && fd != -1;
|
||||
map->readonlyfile = (flags & MAP_TYPE) == MAP_SHARED && fd != -1 &&
|
||||
|
@ -419,10 +423,10 @@ TryAgain:
|
|||
}
|
||||
|
||||
static void *__mmap_impl(char *addr, size_t size, int prot, int flags, int fd,
|
||||
int64_t off, int granularity) {
|
||||
int64_t off, int pagesz, int granularity) {
|
||||
|
||||
// validate file map args
|
||||
if (fd != -1) {
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
if (off & (granularity - 1))
|
||||
return (void *)einval();
|
||||
if (IsWindows()) {
|
||||
|
@ -435,19 +439,21 @@ static void *__mmap_impl(char *addr, size_t size, int prot, int flags, int fd,
|
|||
|
||||
// mmap works fine on unix
|
||||
if (!IsWindows())
|
||||
return __mmap_chunk(addr, size, prot, flags, fd, off, granularity);
|
||||
return __mmap_chunk(addr, size, prot, flags, fd, off, pagesz, granularity);
|
||||
|
||||
// if the concept of granularity wasn't exciting enough
|
||||
if (!addr && !(flags & (MAP_FIXED | MAP_FIXED_NOREPLACE)))
|
||||
addr = (char *)(WINBASE + atomic_fetch_add(&rollo, PGUP(size)) % WINMAXX);
|
||||
// if the concept of pagesz wasn't exciting enough
|
||||
if (!addr && !(flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))) {
|
||||
size_t slab = (size + granularity - 1) & -granularity;
|
||||
addr = (char *)(WINBASE + atomic_fetch_add(&__maps.rollo, slab) % WINMAXX);
|
||||
}
|
||||
|
||||
// windows forbids unmapping a subset of a map once it's made
|
||||
if (size <= granularity || size > 100 * 1024 * 1024)
|
||||
return __mmap_chunk(addr, size, prot, flags, fd, off, granularity);
|
||||
return __mmap_chunk(addr, size, prot, flags, fd, off, pagesz, granularity);
|
||||
|
||||
// so we create a separate map for each granule in the mapping
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
while (overlaps_existing_map(addr, size)) {
|
||||
while (overlaps_existing_map(addr, size, pagesz)) {
|
||||
if (flags & MAP_FIXED_NOREPLACE)
|
||||
return (void *)eexist();
|
||||
addr += granularity;
|
||||
|
@ -457,7 +463,7 @@ static void *__mmap_impl(char *addr, size_t size, int prot, int flags, int fd,
|
|||
while (size) {
|
||||
char *got;
|
||||
size_t amt = MIN(size, granularity);
|
||||
got = __mmap_chunk(addr, amt, prot, flags, fd, off, granularity);
|
||||
got = __mmap_chunk(addr, amt, prot, flags, fd, off, pagesz, granularity);
|
||||
if (got != addr) {
|
||||
if (got != MAP_FAILED)
|
||||
__munmap(got, amt, false);
|
||||
|
@ -476,6 +482,7 @@ static void *__mmap_impl(char *addr, size_t size, int prot, int flags, int fd,
|
|||
void *__mmap(char *addr, size_t size, int prot, int flags, int fd,
|
||||
int64_t off) {
|
||||
char *res;
|
||||
int pagesz = getpagesize();
|
||||
int granularity = __granularity();
|
||||
|
||||
// validate arguments
|
||||
|
@ -484,17 +491,12 @@ void *__mmap(char *addr, size_t size, int prot, int flags, int fd,
|
|||
return (void *)einval();
|
||||
if (size > 0x100000000000)
|
||||
return (void *)enomem();
|
||||
|
||||
// normalize arguments
|
||||
if (flags & MAP_ANONYMOUS) {
|
||||
fd = -1;
|
||||
off = 0;
|
||||
size = PGUP(size);
|
||||
}
|
||||
if (__maps.count * pagesz + size > __virtualmax)
|
||||
return (void *)enomem();
|
||||
|
||||
// create memory mappping
|
||||
if (!__isfdkind(fd, kFdZip)) {
|
||||
res = __mmap_impl(addr, size, prot, flags, fd, off, granularity);
|
||||
res = __mmap_impl(addr, size, prot, flags, fd, off, pagesz, granularity);
|
||||
} else {
|
||||
res = _weaken(__zipos_mmap)(
|
||||
addr, size, prot, flags,
|
||||
|
@ -505,24 +507,14 @@ void *__mmap(char *addr, size_t size, int prot, int flags, int fd,
|
|||
}
|
||||
|
||||
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
|
||||
void *res;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
res = __mmap(addr, size, prot, flags, fd, off);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
void *res = __mmap(addr, size, prot, flags, fd, off);
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m", addr, size,
|
||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int munmap(void *addr, size_t size) {
|
||||
int rc;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
rc = __munmap(addr, size, false);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
int rc = __munmap(addr, size, false);
|
||||
STRACE("munmap(%p, %'zu) → %d% m", addr, size, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -59,56 +59,57 @@ int __mprotect(char *addr, size_t size, int prot) {
|
|||
return 0;
|
||||
|
||||
// unix checks prot before checking size
|
||||
int pagesz = getauxval(AT_PAGESZ);
|
||||
if ((intptr_t)addr & (pagesz - 1))
|
||||
int pagesz = getpagesize();
|
||||
if (((intptr_t)addr & (pagesz - 1)) || (uintptr_t)addr + size < size)
|
||||
return einval();
|
||||
|
||||
// normalize size
|
||||
size = (size + pagesz - 1) & -pagesz;
|
||||
|
||||
// change mappings
|
||||
int rc = 0;
|
||||
__maps_lock();
|
||||
struct Dll *cur;
|
||||
bool found = false;
|
||||
struct Map *map = __maps.maps;
|
||||
struct Map **prev = &__maps.maps;
|
||||
while (map) {
|
||||
if (__maps_lock()) {
|
||||
__maps_unlock();
|
||||
return edeadlk();
|
||||
}
|
||||
for (cur = dll_first(__maps.used); cur; cur = dll_next(__maps.used, cur)) {
|
||||
struct Map *map = MAP_CONTAINER(cur);
|
||||
char *map_addr = map->addr;
|
||||
size_t map_size = map->size;
|
||||
struct Map *next = map->next;
|
||||
char *beg = MAX(addr, map_addr);
|
||||
char *end = MIN(addr + PGUP(size), map_addr + PGUP(map_size));
|
||||
char *end = MIN(addr + size, map_addr + PGUP(map_size));
|
||||
if (beg < end) {
|
||||
found = true;
|
||||
if (addr <= map_addr && addr + PGUP(size) >= map_addr + PGUP(map_size)) {
|
||||
if (addr <= map_addr && addr + size >= map_addr + PGUP(map_size)) {
|
||||
// change protection of entire mapping
|
||||
if (!__mprotect_chunk(map_addr, map_size, prot, map->iscow)) {
|
||||
map->prot = prot;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else if (IsWindows()) {
|
||||
// windows does allow changing protection at 4096 byte chunks
|
||||
// however we currently don't have data structures that track
|
||||
// this within the 64 kb map granules that can't be broken up
|
||||
if (__mprotect_chunk(beg, end - beg, prot, map->iscow) == -1)
|
||||
rc = -1;
|
||||
} else if (addr <= map_addr) {
|
||||
// cleave lefthand side of mapping
|
||||
// change lefthand side of mapping
|
||||
size_t left = PGUP(addr + size - map_addr);
|
||||
size_t right = map_size - left;
|
||||
struct Map *leftmap;
|
||||
if ((leftmap = __maps_alloc())) {
|
||||
if (!__mprotect_chunk(map_addr, left, prot, false)) {
|
||||
leftmap->next = map;
|
||||
leftmap->addr = map_addr;
|
||||
leftmap->size = left;
|
||||
leftmap->prot = prot;
|
||||
leftmap->off = map->off;
|
||||
leftmap->flags = map->flags;
|
||||
leftmap->iscow = map->iscow;
|
||||
leftmap->readonlyfile = map->readonlyfile;
|
||||
leftmap->hand = map->hand;
|
||||
map->addr += left;
|
||||
map->size = right;
|
||||
map->hand = -1;
|
||||
if (!(map->flags & MAP_ANONYMOUS))
|
||||
map->off += left;
|
||||
dll_make_first(&__maps.used, &leftmap->elem);
|
||||
*prev = leftmap;
|
||||
__maps.count += 1;
|
||||
__maps_check();
|
||||
} else {
|
||||
|
@ -118,26 +119,28 @@ int __mprotect(char *addr, size_t size, int prot) {
|
|||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else if (addr + PGUP(size) >= map_addr + PGUP(map_size)) {
|
||||
// cleave righthand side of mapping
|
||||
} else if (addr + size >= map_addr + PGUP(map_size)) {
|
||||
// change righthand side of mapping
|
||||
size_t left = addr - map_addr;
|
||||
size_t right = map_addr + map_size - addr;
|
||||
struct Map *leftmap;
|
||||
if ((leftmap = __maps_alloc())) {
|
||||
if (!__mprotect_chunk(map_addr + left, right, prot, false)) {
|
||||
leftmap->next = map;
|
||||
leftmap->addr = map_addr;
|
||||
leftmap->size = left;
|
||||
leftmap->off = map->off;
|
||||
leftmap->prot = map->prot;
|
||||
leftmap->flags = map->flags;
|
||||
leftmap->iscow = map->iscow;
|
||||
leftmap->readonlyfile = map->readonlyfile;
|
||||
leftmap->hand = map->hand;
|
||||
map->addr += left;
|
||||
map->size = right;
|
||||
map->prot = prot;
|
||||
map->hand = -1;
|
||||
if (!(map->flags & MAP_ANONYMOUS))
|
||||
map->off += left;
|
||||
dll_make_first(&__maps.used, &leftmap->elem);
|
||||
*prev = leftmap;
|
||||
__maps.count += 1;
|
||||
__maps_check();
|
||||
} else {
|
||||
|
@ -148,34 +151,36 @@ int __mprotect(char *addr, size_t size, int prot) {
|
|||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
// punch hole in mapping
|
||||
// change middle of mapping
|
||||
size_t left = addr - map_addr;
|
||||
size_t middle = PGUP(size);
|
||||
size_t middle = size;
|
||||
size_t right = map_size - middle - left;
|
||||
struct Map *leftmap;
|
||||
if ((leftmap = __maps_alloc())) {
|
||||
struct Map *midlmap;
|
||||
if ((midlmap = __maps_alloc())) {
|
||||
if (!__mprotect_chunk(map_addr + left, middle, prot, false)) {
|
||||
leftmap->next = midlmap;
|
||||
leftmap->addr = map_addr;
|
||||
leftmap->size = left;
|
||||
leftmap->off = map->off;
|
||||
leftmap->prot = map->prot;
|
||||
leftmap->flags = map->flags;
|
||||
midlmap->next = map;
|
||||
leftmap->iscow = map->iscow;
|
||||
leftmap->readonlyfile = map->readonlyfile;
|
||||
leftmap->hand = map->hand;
|
||||
midlmap->addr = map_addr + left;
|
||||
midlmap->size = middle;
|
||||
midlmap->off = (map->flags & MAP_ANONYMOUS) ? 0 : map->off + left;
|
||||
midlmap->prot = prot;
|
||||
midlmap->flags = map->flags;
|
||||
midlmap->hand = -1;
|
||||
map->addr += left + middle;
|
||||
map->size = right;
|
||||
map->hand = -1;
|
||||
if (!(map->flags & MAP_ANONYMOUS))
|
||||
map->off += left + middle;
|
||||
dll_make_first(&__maps.used, &leftmap->elem);
|
||||
dll_make_first(&__maps.used, &midlmap->elem);
|
||||
*prev = leftmap;
|
||||
dll_make_first(&__maps.used, &leftmap->elem);
|
||||
__maps.count += 2;
|
||||
__maps_check();
|
||||
} else {
|
||||
|
@ -192,8 +197,6 @@ int __mprotect(char *addr, size_t size, int prot) {
|
|||
}
|
||||
}
|
||||
}
|
||||
prev = &map->next;
|
||||
map = next;
|
||||
}
|
||||
|
||||
// allow user to change mappings unknown to cosmo runtime
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
||||
|
||||
int pagesz = getauxval(AT_PAGESZ);
|
||||
int pagesz = getpagesize();
|
||||
size = (size + pagesz - 1) & -pagesz;
|
||||
|
||||
if ((uintptr_t)addr & (pagesz - 1))
|
||||
|
@ -35,7 +35,9 @@ textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
|||
|
||||
int rc = 0;
|
||||
__maps_lock();
|
||||
for (struct Map *map = __maps.maps; map; map = map->next) {
|
||||
for (struct Dll *e = dll_first(__maps.used); e;
|
||||
e = dll_next(__maps.used, e)) {
|
||||
struct Map *map = MAP_CONTAINER(e);
|
||||
char *beg = MAX(addr, map->addr);
|
||||
char *end = MIN(addr + size, map->addr + map->size);
|
||||
if (beg < end)
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
* Prints memory mappings.
|
||||
*/
|
||||
void __print_maps(void) {
|
||||
int limit = 13;
|
||||
int limit = 15;
|
||||
long maptally = 0;
|
||||
char mappingbuf[8], sb[16];
|
||||
__maps_lock();
|
||||
|
@ -43,8 +43,8 @@ void __print_maps(void) {
|
|||
(DescribeMapping)(mappingbuf, map->prot, map->flags));
|
||||
sizefmt(sb, map->size, 1024);
|
||||
kprintf(" %!sb", sb);
|
||||
if (map->h && map->h != -1)
|
||||
kprintf(" h=%ld", map->h);
|
||||
if (map->hand && map->hand != -1)
|
||||
kprintf(" hand=%ld", map->hand);
|
||||
if (map->iscow)
|
||||
kprintf(" cow");
|
||||
if (map->readonlyfile)
|
||||
|
@ -53,7 +53,7 @@ void __print_maps(void) {
|
|||
if (!--limit)
|
||||
break;
|
||||
}
|
||||
kprintf("# %'zu bytes in %'zu mappings\n",
|
||||
__maps.pages * getauxval(AT_PAGESZ), __maps.count);
|
||||
kprintf("# %'zu bytes in %'zu mappings\n", __maps.pages * getpagesize(),
|
||||
__maps.count);
|
||||
__maps_unlock();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#define SYSDEBUG 0
|
||||
#endif
|
||||
|
||||
#define _NTTRACE 1 /* not configurable w/ flag yet */
|
||||
#define _NTTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
||||
#define _LOCKTRACE 0 /* not configurable w/ flag yet */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue