wingo pushed a commit to branch wip-whippet
in repository guile.

commit 6a6f5b09e3fbe2ea0dd5f24117c55a6c068526be
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Sat Nov 23 09:13:57 2024 +0100

    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);
 

Reply via email to