Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Source/bmalloc/bmalloc/BSyscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,18 @@
#pragma once

#include <errno.h>
#include <unistd.h>

/* Retry syscalls on EAGAIN with 1ms backoff to avoid busy-spinning.
madvise(MADV_DONTDUMP) can return EAGAIN under kernel mmap_write_lock
contention, causing 100% CPU usage with concurrent GC threads.
Cap retries at 100 (100ms total) as a safety net — madvise failures
here are advisory, not fatal. See also: virtual_alloc_with_retry()
in libpas/pas_page_malloc.c for the Windows equivalent. */
#define SYSCALL(x) do { \
while ((x) == -1 && errno == EAGAIN) { } \
int _syscall_tries = 0; \
while ((x) == -1 && errno == EAGAIN) { \
if (++_syscall_tries > 100) break; \
usleep(1000); \
} \
} while (0);
10 changes: 4 additions & 6 deletions Source/bmalloc/bmalloc/VMAllocate.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,9 @@ inline void vmDeallocatePhysicalPages(void* p, size_t vmSize)
SYSCALL(madvise(p, vmSize, MADV_FREE));
#else
SYSCALL(madvise(p, vmSize, MADV_DONTNEED));
#if BOS(LINUX)
SYSCALL(madvise(p, vmSize, MADV_DONTDUMP));
#endif
/* MADV_DONTDUMP removed: it only reduces core dump size but requires
kernel mmap_write_lock, causing severe contention with concurrent
GC threads. MADV_DONTNEED (above) only needs mmap_read_lock. */
#endif
}

Expand All @@ -319,9 +319,7 @@ inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
// Instead the kernel will commit pages as they are touched.
#else
SYSCALL(madvise(p, vmSize, MADV_NORMAL));
#if BOS(LINUX)
SYSCALL(madvise(p, vmSize, MADV_DODUMP));
#endif
/* MADV_DODUMP removed: symmetric with MADV_DONTDUMP removal above. */
#endif
}
#else
Expand Down
9 changes: 6 additions & 3 deletions Source/bmalloc/libpas/src/libpas/pas_page_malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,9 @@ static void commit_impl(void* ptr, size_t size, bool do_mprotect, pas_mmap_capab
#endif
}

#if PAS_OS(LINUX)
PAS_SYSCALL(madvise(ptr, size, MADV_DODUMP));
/* MADV_DODUMP removed: symmetric with MADV_DONTDUMP removal in decommit_impl.
MADV_DONTDUMP only reduces core dump size but requires kernel mmap_write_lock,
causing severe contention with concurrent GC threads. */
#elif PAS_OS(WINDOWS)
/* Sometimes the returned memInfo.RegionSize < size, and VirtualAlloc can't span regions
We loop to make sure we get the full requested range. */
Expand Down Expand Up @@ -415,7 +416,9 @@ static void decommit_impl(void* ptr, size_t size,
PAS_SYSCALL(madvise(ptr, size, MADV_FREE));
#elif PAS_OS(LINUX)
PAS_SYSCALL(madvise(ptr, size, MADV_DONTNEED));
PAS_SYSCALL(madvise(ptr, size, MADV_DONTDUMP));
/* MADV_DONTDUMP removed: it only reduces core dump size but requires
kernel mmap_write_lock, causing severe contention with concurrent
GC threads. MADV_DONTNEED (above) only needs mmap_read_lock. */
#elif PAS_OS(WINDOWS)
// DiscardVirtualMemory returns memory to the OS faster, but fails sometimes on Windows 10
// Fall back to VirtualAlloc in those cases
Expand Down
15 changes: 14 additions & 1 deletion Source/bmalloc/libpas/src/libpas/pas_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
#include <stdint.h>
#include <string.h>

#if !PAS_OS(WINDOWS)
#include <unistd.h>
#endif

#if PAS_OS(WINDOWS)
#include <intrin.h>
#endif
Expand Down Expand Up @@ -1263,8 +1267,17 @@ static inline bool pas_is_divisible_by(unsigned value, uint64_t magic_constant)
enum cpp_initialization_t { cpp_initialization };
#endif

/* Retry syscalls on EAGAIN with 1ms backoff to avoid busy-spinning.
madvise(MADV_DONTDUMP) can return EAGAIN under kernel mmap_write_lock
contention, causing 100% CPU usage with concurrent GC threads.
Cap retries at 100 (100ms total) as a safety net — madvise failures
here are advisory, not fatal. */
#define PAS_SYSCALL(x) do { \
while ((x) == -1 && errno == EAGAIN) { } \
int _pas_syscall_tries = 0; \
while ((x) == -1 && errno == EAGAIN) { \
if (++_pas_syscall_tries > 100) break; \
usleep(1000); \
} \
} while (0)

PAS_END_EXTERN_C;
Expand Down