From 6a6f5b09e3fbe2ea0dd5f24117c55a6c068526be Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Sat, 23 Nov 2024 09:13:57 +0100 Subject: [PATCH] Use PROT_NONE to reserve memory, then remap within that memory Should play better with the kernel's overcommit heuristics. --- src/gc-platform-gnu-linux.c | 43 +++++++++++++++++++++++++++++++------ src/gc-platform.h | 15 +++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/gc-platform-gnu-linux.c b/src/gc-platform-gnu-linux.c index 0b267032a..3ace1890d 100644 --- a/src/gc-platform-gnu-linux.c +++ b/src/gc-platform-gnu-linux.c @@ -128,17 +128,18 @@ size_t gc_platform_page_size(void) { return getpagesize(); } -void* gc_platform_acquire_memory(size_t size, size_t alignment) { +struct gc_reservation gc_platform_reserve_memory(size_t size, + size_t alignment) { GC_ASSERT_EQ(size, align_down(size, getpagesize())); GC_ASSERT_EQ(alignment & (alignment - 1), 0); GC_ASSERT_EQ(alignment, align_down(alignment, getpagesize())); size_t extent = size + alignment; - char *mem = mmap(NULL, extent, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + void *mem = mmap(NULL, extent, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (mem == MAP_FAILED) { - perror("mmap failed"); - return NULL; + perror("failed to reserve address space"); + GC_CRASH(); } uintptr_t base = (uintptr_t) mem; @@ -151,7 +152,37 @@ void* gc_platform_acquire_memory(size_t size, size_t alignment) { if (end - aligned_end) munmap((void*)aligned_end, end - aligned_end); - return (void*) aligned_base; + return (struct gc_reservation){aligned_base, size}; +} + +void* +gc_platform_acquire_memory_from_reservation(struct gc_reservation reservation, + size_t offset, size_t size) { + GC_ASSERT_EQ(size, align_down(size, getpagesize())); + GC_ASSERT(size <= reservation.size); + GC_ASSERT(offset <= reservation.size - size); + + void *mem = mmap((void*)(reservation.base + offset), size, + PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (mem == MAP_FAILED) { + perror("mmap failed"); + return NULL; + } + + return mem; +} + +void +gc_platform_release_reservation(struct gc_reservation reservation) { + if (munmap((void*)reservation.base, reservation.size) != 0) + perror("failed to unmap memory"); +} + +void* +gc_platform_acquire_memory(size_t size, size_t alignment) { + struct gc_reservation reservation = + gc_platform_reserve_memory(size, alignment); + return gc_platform_acquire_memory_from_reservation(reservation, 0, size); } void gc_platform_release_memory(void *ptr, size_t size) { diff --git a/src/gc-platform.h b/src/gc-platform.h index ddedbb984..b642e8157 100644 --- a/src/gc-platform.h +++ b/src/gc-platform.h @@ -24,6 +24,21 @@ GC_INTERNAL int gc_platform_processor_count(void); GC_INTERNAL uint64_t gc_platform_monotonic_nanoseconds(void); GC_INTERNAL size_t gc_platform_page_size(void); + +struct gc_reservation { + uintptr_t base; + size_t size; +}; + +GC_INTERNAL +struct gc_reservation gc_platform_reserve_memory(size_t size, size_t alignment); +GC_INTERNAL +void* +gc_platform_acquire_memory_from_reservation(struct gc_reservation reservation, + size_t offset, size_t size); +GC_INTERNAL +void gc_platform_release_reservation(struct gc_reservation reservation); + GC_INTERNAL void* gc_platform_acquire_memory(size_t size, size_t alignment); GC_INTERNAL void gc_platform_release_memory(void *base, size_t size);