From 1bf2d8e308121ae03d065837ccdaf66ab05da512 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sat, 29 Jun 2024 17:12:25 -0700 Subject: [PATCH] Further improve mmap() locking story The way to use double linked lists, is to remove all the things you want to work on, insert them into a new list on the stack. Then once you have all the work items, you release the lock, do your work, and then lock it again, to add the shelled out items back to a global freelist. --- ctl/BUILD.mk | 1 + libc/intrin/maps.h | 1 - libc/intrin/mmap.c | 145 ++++++++++++++++++++------------------ libc/intrin/randaddr.c | 25 ------- libc/intrin/reservefd.c | 6 +- libc/runtime/zipos-open.c | 2 +- test/ctl/BUILD.mk | 1 + tool/cosmocc/package.sh | 4 +- 8 files changed, 84 insertions(+), 101 deletions(-) delete mode 100644 libc/intrin/randaddr.c diff --git a/ctl/BUILD.mk b/ctl/BUILD.mk index f30a3c8bc..73cf29766 100644 --- a/ctl/BUILD.mk +++ b/ctl/BUILD.mk @@ -18,6 +18,7 @@ CTL_A_CHECKS = \ CTL_A_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_MEM \ + LIBC_NEXGEN32E \ LIBC_STDIO \ LIBC_STR \ THIRD_PARTY_GDTOA \ diff --git a/libc/intrin/maps.h b/libc/intrin/maps.h index ca0d013ff..97d160fbd 100644 --- a/libc/intrin/maps.h +++ b/libc/intrin/maps.h @@ -39,7 +39,6 @@ struct AddrSize { extern struct Maps __maps; -void *randaddr(void); void __maps_init(void); void __maps_lock(void); void __maps_check(void); diff --git a/libc/intrin/mmap.c b/libc/intrin/mmap.c index 1f9befd7f..e71fb2b1e 100644 --- a/libc/intrin/mmap.c +++ b/libc/intrin/mmap.c @@ -21,6 +21,7 @@ #include "libc/calls/blockcancel.internal.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/sigset.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" @@ -187,10 +188,10 @@ int __munmap(char *addr, size_t size, bool untrack_only) { !size || (uintptr_t)addr + size < size) return einval(); - // untrack and delete mapping + // untrack mappings int rc = 0; + struct Dll *delete = 0; __maps_lock(); -StartOver:; struct Map *map = __maps.maps; struct Map **prev = &__maps.maps; while (map) { @@ -202,30 +203,10 @@ StartOver:; if (addr <= map_addr && addr + PGUP(size) >= map_addr + PGUP(map_size)) { // remove mapping completely dll_remove(&__maps.used, &map->elem); + dll_make_first(&delete, &map->elem); *prev = next; __maps.pages -= (map_size + pagesz - 1) / pagesz; __maps.count -= 1; - if (untrack_only) { - __maps_free(map); - __maps_check(); - } else { - __maps_unlock(); - if (!IsWindows()) { - ASSERT(addr <= map_addr); - ASSERT(map_addr + PGUP(map_size) <= addr + PGUP(size)); - if (sys_munmap(map_addr, map_size)) - rc = -1; - } else { - if (!UnmapViewOfFile(map_addr)) - rc = -1; - if (!CloseHandle(map->h)) - rc = -1; - } - __maps_lock(); - __maps_free(map); - __maps_check(); - goto StartOver; - } map = next; continue; } else if (IsWindows()) { @@ -240,35 +221,34 @@ StartOver:; size_t right = map_size - left; ASSERT(right > 0); ASSERT(left > 0); - map->addr += left; - map->size = right; - if (!(map->flags & MAP_ANONYMOUS)) - map->off += left; - __maps.pages -= (left + pagesz - 1) / pagesz; - __maps_check(); - if (!untrack_only) { - __maps_unlock(); - ASSERT(addr <= map_addr); - ASSERT(map_addr + PGUP(left) <= addr + PGUP(size)); - if (sys_munmap(map_addr, left) == -1) - rc = -1; - __maps_lock(); - goto StartOver; + struct Map *leftmap; + if ((leftmap = __maps_alloc())) { + map->addr += left; + map->size = right; + 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); + } else { + rc = -1; } } else if (addr + PGUP(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; - map->size = left; - __maps.pages -= (right + pagesz - 1) / pagesz; - __maps_check(); - if (!untrack_only) { - __maps_unlock(); - ASSERT(PGUP(right) <= PGUP(size)); - if (sys_munmap(addr, right) == -1) - rc = -1; - __maps_lock(); - goto StartOver; + struct Map *rightmap; + 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); + } else { + rc = -1; } } else { // punch hole in mapping @@ -277,27 +257,28 @@ StartOver:; size_t right = map_size - middle - left; struct Map *leftmap; if ((leftmap = __maps_alloc())) { - leftmap->next = map; - leftmap->addr = map_addr; - leftmap->size = left; - leftmap->off = map->off; - leftmap->prot = map->prot; - leftmap->flags = map->flags; - map->addr += left + middle; - map->size = right; - 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(); - if (!untrack_only) { - __maps_unlock(); - if (sys_munmap(addr, size) == -1) - rc = -1; - __maps_lock(); - goto StartOver; + struct Map *middlemap; + if ((middlemap = __maps_alloc())) { + leftmap->next = map; + leftmap->addr = map_addr; + leftmap->size = left; + leftmap->off = map->off; + leftmap->prot = map->prot; + leftmap->flags = map->flags; + map->addr += left + middle; + map->size = right; + 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); + } else { + rc = -1; } } else { rc = -1; @@ -309,6 +290,34 @@ StartOver:; } __maps_unlock(); + // delete mappings + for (struct Dll *e = dll_first(delete); e; e = dll_next(delete, e)) { + map = MAP_CONTAINER(e); + if (!untrack_only) { + if (!IsWindows()) { + if (sys_munmap(map->addr, map->size)) + rc = -1; + } else { + if (!UnmapViewOfFile(map->addr)) + rc = -1; + if (!CloseHandle(map->h)) + rc = -1; + } + } + } + + // free mappings + if (!dll_is_empty(delete)) { + __maps_lock(); + struct Dll *e; + while ((e = dll_first(delete))) { + dll_remove(&delete, e); + __maps_free(MAP_CONTAINER(e)); + } + __maps_check(); + __maps_unlock(); + } + return rc; } diff --git a/libc/intrin/randaddr.c b/libc/intrin/randaddr.c deleted file mode 100644 index 5be079696..000000000 --- a/libc/intrin/randaddr.c +++ /dev/null @@ -1,25 +0,0 @@ -/*-*- 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 2024 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. │ -╚─────────────────────────────────────────────────────────────────────────────*/ - -void *randaddr(void) { - static unsigned long lcg = 1; - lcg *= 6364136223846793005; - lcg += 1442695040888963407; - return (void *)(lcg >> 48 << 28); -} diff --git a/libc/intrin/reservefd.c b/libc/intrin/reservefd.c index 1be7e4b4f..a8d47a477 100644 --- a/libc/intrin/reservefd.c +++ b/libc/intrin/reservefd.c @@ -64,11 +64,9 @@ int __reservefd_unlocked(int start) { int fd, f1, f2; for (;;) { f1 = atomic_load_explicit(&g_fds.f, memory_order_acquire); - for (fd = MAX(start, f1); fd < g_fds.n; ++fd) { - if (!g_fds.p[fd].kind) { + for (fd = MAX(start, f1); fd < g_fds.n; ++fd) + if (!g_fds.p[fd].kind) break; - } - } fd = __ensurefds_unlocked(fd); bzero(g_fds.p + fd, sizeof(*g_fds.p)); if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) { diff --git a/libc/runtime/zipos-open.c b/libc/runtime/zipos-open.c index 37ace7fb3..1bd8e568a 100644 --- a/libc/runtime/zipos-open.c +++ b/libc/runtime/zipos-open.c @@ -58,7 +58,7 @@ static struct ZiposHandle *__zipos_alloc(struct Zipos *zipos, size_t size) { granularity = __granularity(); mapsize = sizeof(struct ZiposHandle) + size; mapsize = (mapsize + granularity - 1) & -granularity; - if ((h = __mmap(randaddr(), mapsize, PROT_READ | PROT_WRITE, + if ((h = __mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { h->size = size; h->zipos = zipos; diff --git a/test/ctl/BUILD.mk b/test/ctl/BUILD.mk index f644eb2cb..97562343e 100644 --- a/test/ctl/BUILD.mk +++ b/test/ctl/BUILD.mk @@ -17,6 +17,7 @@ TEST_CTL_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_LOG \ LIBC_MEM \ + LIBC_NEXGEN32E \ LIBC_STDIO \ LIBC_STDIO \ LIBC_THREAD \ diff --git a/tool/cosmocc/package.sh b/tool/cosmocc/package.sh index 8abb3132e..70e76328c 100755 --- a/tool/cosmocc/package.sh +++ b/tool/cosmocc/package.sh @@ -90,10 +90,10 @@ fetch() { OLD=$PWD cd "$OUTDIR/" if [ ! -x bin/x86_64-linux-cosmo-gcc ]; then - fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.44/aarch64-gcc.zip + fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.45/aarch64-gcc.zip unzip aarch64-gcc.zip rm -f aarch64-gcc.zip - fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.44/x86_64-gcc.zip + fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.45/x86_64-gcc.zip unzip x86_64-gcc.zip rm -f x86_64-gcc.zip fi