Ruby 4.1.0dev (2026-11-10 revision c65a8e03f14ed911e519028419ba3b2b9fbad6d3)
vm_map.h
1#ifndef INTERNAL_VM_MAP_H
2#define INTERNAL_VM_MAP_H
11#include "ruby/internal/config.h"
12#include <stddef.h> /* for size_t */
13#include "ruby/internal/stdbool.h" /* for bool */
14
15#ifdef HAVE_SYS_MMAN_H
16# include <sys/mman.h>
17#endif
18#ifdef HAVE_ERRNO_H
19# include <errno.h> /* for errno, EAGAIN */
20#endif
21
22// On Solaris, madvise() is NOT declared for SUS (XPG4v2) or later,
23// but MADV_* macros are defined when __EXTENSIONS__ is defined.
24#ifdef NEED_MADVICE_PROTOTYPE_USING_CADDR_T
25#include <sys/types.h>
26extern int madvise(caddr_t, size_t, int);
27#endif
28
29/* zeroed_out (optional) reports whether the range now reads as all zero. That needs an
30 * advice which discards the pages outright -- only Linux's MADV_DONTNEED, and only on a
31 * private anonymous mapping, which the caller must know: a private file mapping reverts
32 * to the file's contents instead. MADV_FREE may or may not drop the old contents, and
33 * MADV_FREE_REUSABLE, the BSD MADV_DONTNEED and MEM_RESET keep them, so those all report
34 * false, as does a failed call. */
35
36// Reduces RSS lazily if possible, otherwise does it immediately. Keeps the mapping.
37static inline void
38rb_vm_map_reusable_lazy(void *addr, size_t len, int advice, bool *zeroed_out)
39{
40 if (zeroed_out) *zeroed_out = false;
41#ifdef __wasi__
42 /* WebAssembly doesn't support madvise. */
43#elif defined(VM_CHECK_MODE) && VM_CHECK_MODE > 0 && defined(MADV_DONTNEED)
44 if (!advice) advice = MADV_DONTNEED;
45 int err = madvise(addr, len, advice);
46# ifdef __linux__
47 if (zeroed_out) *zeroed_out = (err == 0 && advice == MADV_DONTNEED);
48# else
49 (void)err;
50# endif
51#elif defined(MADV_FREE_REUSABLE)
52 /* Darwin / macOS / iOS. Drops phys_footprint; pages stay in resident_size
53 * until the kernel reclaims them. Retry on EAGAIN. */
54 if (!advice) advice = MADV_FREE_REUSABLE;
55 while (madvise(addr, len, advice) == -1 && errno == EAGAIN);
56#elif defined(MADV_FREE)
57 /* Recent Linux. */
58 if (!advice) advice = MADV_FREE;
59 madvise(addr, len, advice);
60#elif defined(MADV_DONTNEED)
61 /* Old Linux. */
62 if (!advice) advice = MADV_DONTNEED;
63 madvise(addr, len, advice);
64#elif defined(POSIX_MADV_DONTNEED)
65 /* Solaris. */
66 if (!advice) advice = POSIX_MADV_DONTNEED;
67 posix_madvise(addr, len, advice);
68#elif defined(_WIN32)
69 VirtualAlloc(addr, len, MEM_RESET, PAGE_READWRITE);
70#endif
71}
72
73// Reduces RSS immediately if possible, otherwise does it lazily. Keeps the mapping.
74// See rb_vm_map_reusable_lazy for zeroed_out.
75static inline void
76rb_vm_map_reusable_immediate(void *addr, size_t len, int advice, bool *zeroed_out)
77{
78 if (zeroed_out) *zeroed_out = false;
79#ifdef __wasi__
80 /* WebAssembly doesn't support madvise. */
81#elif defined(MADV_FREE_REUSABLE)
82 /* The most aggressive option is MADV_FREE_REUSABLE — same as _lazy. It drops
83 * phys_footprint immediately. Retry on EAGAIN. */
84 if (!advice) advice = MADV_FREE_REUSABLE;
85 while (madvise(addr, len, advice) == -1 && errno == EAGAIN);
86#elif defined(MADV_DONTNEED)
87 /* Linux: kernel discards physical pages immediately; next touch
88 * zero-faults and RSS drops at once. */
89 if (!advice) advice = MADV_DONTNEED;
90 int err = madvise(addr, len, advice);
91# ifdef __linux__
92 if (zeroed_out) *zeroed_out = (err == 0 && advice == MADV_DONTNEED);
93# else
94 (void)err;
95# endif
96#elif defined(POSIX_MADV_DONTNEED)
97 if (!advice) advice = POSIX_MADV_DONTNEED;
98 posix_madvise(addr, len, advice);
99#elif defined(_WIN32)
100 // Does not reduce working set immediately. We would need 2 system calls to do this.
101 VirtualAlloc(addr, len, MEM_RESET, PAGE_READWRITE);
102#endif
103}
104
105/* Re-acquire pages previously given back. Only needed for certain platforms. */
106static inline void
107rb_vm_map_reuse(void *addr, size_t len)
108{
109#if defined(MADV_FREE_REUSE)
110 /* Darwin: mandatory handshake with MADV_FREE_REUSABLE. Retry on EAGAIN. */
111 while (madvise(addr, len, MADV_FREE_REUSE) == -1 && errno == EAGAIN);
112#endif
113 /* Linux/Windows/wasi: no-op (fault re-materializes zero-filled pages). */
114}
115
116#endif /* INTERNAL_VM_MAP_H */
int len
Length of the buffer.
Definition io.h:8
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
C99 shim for <stdbool.h>