1 | #define JEMALLOC_PAGES_C_ |
2 | #include "jemalloc/internal/jemalloc_internal.h" |
3 | |
4 | #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT |
5 | #include <sys/sysctl.h> |
6 | #endif |
7 | |
8 | /******************************************************************************/ |
9 | /* Data. */ |
10 | |
11 | #ifndef _WIN32 |
12 | # define PAGES_PROT_COMMIT (PROT_READ | PROT_WRITE) |
13 | # define PAGES_PROT_DECOMMIT (PROT_NONE) |
14 | static int mmap_flags; |
15 | #endif |
16 | static bool os_overcommits; |
17 | |
18 | /******************************************************************************/ |
19 | |
20 | void * |
21 | pages_map(void *addr, size_t size, bool *commit) |
22 | { |
23 | void *ret; |
24 | |
25 | assert(size != 0); |
26 | |
27 | if (os_overcommits) |
28 | *commit = true; |
29 | |
30 | #ifdef _WIN32 |
31 | /* |
32 | * If VirtualAlloc can't allocate at the given address when one is |
33 | * given, it fails and returns NULL. |
34 | */ |
35 | ret = VirtualAlloc(addr, size, MEM_RESERVE | (*commit ? MEM_COMMIT : 0), |
36 | PAGE_READWRITE); |
37 | #else |
38 | /* |
39 | * We don't use MAP_FIXED here, because it can cause the *replacement* |
40 | * of existing mappings, and we only want to create new mappings. |
41 | */ |
42 | { |
43 | int prot = *commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT; |
44 | |
45 | ret = mmap(addr, size, prot, mmap_flags, -1, 0); |
46 | } |
47 | assert(ret != NULL); |
48 | |
49 | if (ret == MAP_FAILED) |
50 | ret = NULL; |
51 | else if (addr != NULL && ret != addr) { |
52 | /* |
53 | * We succeeded in mapping memory, but not in the right place. |
54 | */ |
55 | pages_unmap(ret, size); |
56 | ret = NULL; |
57 | } |
58 | #endif |
59 | assert(ret == NULL || (addr == NULL && ret != addr) |
60 | || (addr != NULL && ret == addr)); |
61 | return (ret); |
62 | } |
63 | |
64 | void |
65 | pages_unmap(void *addr, size_t size) |
66 | { |
67 | |
68 | #ifdef _WIN32 |
69 | if (VirtualFree(addr, 0, MEM_RELEASE) == 0) |
70 | #else |
71 | if (munmap(addr, size) == -1) |
72 | #endif |
73 | { |
74 | char buf[BUFERROR_BUF]; |
75 | |
76 | buferror(get_errno(), buf, sizeof(buf)); |
77 | malloc_printf("<jemalloc>: Error in " |
78 | #ifdef _WIN32 |
79 | "VirtualFree" |
80 | #else |
81 | "munmap" |
82 | #endif |
83 | "(): %s\n" , buf); |
84 | if (opt_abort) |
85 | abort(); |
86 | } |
87 | } |
88 | |
89 | void * |
90 | pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, |
91 | bool *commit) |
92 | { |
93 | void *ret = (void *)((uintptr_t)addr + leadsize); |
94 | |
95 | assert(alloc_size >= leadsize + size); |
96 | #ifdef _WIN32 |
97 | { |
98 | void *new_addr; |
99 | |
100 | pages_unmap(addr, alloc_size); |
101 | new_addr = pages_map(ret, size, commit); |
102 | if (new_addr == ret) |
103 | return (ret); |
104 | if (new_addr) |
105 | pages_unmap(new_addr, size); |
106 | return (NULL); |
107 | } |
108 | #else |
109 | { |
110 | size_t trailsize = alloc_size - leadsize - size; |
111 | |
112 | if (leadsize != 0) |
113 | pages_unmap(addr, leadsize); |
114 | if (trailsize != 0) |
115 | pages_unmap((void *)((uintptr_t)ret + size), trailsize); |
116 | return (ret); |
117 | } |
118 | #endif |
119 | } |
120 | |
121 | static bool |
122 | pages_commit_impl(void *addr, size_t size, bool commit) |
123 | { |
124 | |
125 | if (os_overcommits) |
126 | return (true); |
127 | |
128 | #ifdef _WIN32 |
129 | return (commit ? (addr != VirtualAlloc(addr, size, MEM_COMMIT, |
130 | PAGE_READWRITE)) : (!VirtualFree(addr, size, MEM_DECOMMIT))); |
131 | #else |
132 | { |
133 | int prot = commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT; |
134 | void *result = mmap(addr, size, prot, mmap_flags | MAP_FIXED, |
135 | -1, 0); |
136 | if (result == MAP_FAILED) |
137 | return (true); |
138 | if (result != addr) { |
139 | /* |
140 | * We succeeded in mapping memory, but not in the right |
141 | * place. |
142 | */ |
143 | pages_unmap(result, size); |
144 | return (true); |
145 | } |
146 | return (false); |
147 | } |
148 | #endif |
149 | } |
150 | |
151 | bool |
152 | pages_commit(void *addr, size_t size) |
153 | { |
154 | |
155 | return (pages_commit_impl(addr, size, true)); |
156 | } |
157 | |
158 | bool |
159 | pages_decommit(void *addr, size_t size) |
160 | { |
161 | |
162 | return (pages_commit_impl(addr, size, false)); |
163 | } |
164 | |
165 | bool |
166 | pages_purge(void *addr, size_t size) |
167 | { |
168 | bool unzeroed; |
169 | |
170 | #ifdef _WIN32 |
171 | VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); |
172 | unzeroed = true; |
173 | #elif defined(JEMALLOC_HAVE_MADVISE) |
174 | # ifdef JEMALLOC_PURGE_MADVISE_DONTNEED |
175 | # define JEMALLOC_MADV_PURGE MADV_DONTNEED |
176 | # define JEMALLOC_MADV_ZEROS true |
177 | # elif defined(JEMALLOC_PURGE_MADVISE_FREE) |
178 | # define JEMALLOC_MADV_PURGE MADV_FREE |
179 | # define JEMALLOC_MADV_ZEROS false |
180 | # else |
181 | # error "No madvise(2) flag defined for purging unused dirty pages." |
182 | # endif |
183 | int err = madvise(addr, size, JEMALLOC_MADV_PURGE); |
184 | unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0); |
185 | # undef JEMALLOC_MADV_PURGE |
186 | # undef JEMALLOC_MADV_ZEROS |
187 | #else |
188 | /* Last resort no-op. */ |
189 | unzeroed = true; |
190 | #endif |
191 | return (unzeroed); |
192 | } |
193 | |
194 | #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT |
195 | static bool |
196 | os_overcommits_sysctl(void) |
197 | { |
198 | int vm_overcommit; |
199 | size_t sz; |
200 | |
201 | sz = sizeof(vm_overcommit); |
202 | if (sysctlbyname("vm.overcommit" , &vm_overcommit, &sz, NULL, 0) != 0) |
203 | return (false); /* Error. */ |
204 | |
205 | return ((vm_overcommit & 0x3) == 0); |
206 | } |
207 | #endif |
208 | |
209 | #ifdef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY |
210 | static bool |
211 | os_overcommits_proc(void) |
212 | { |
213 | int fd; |
214 | char buf[1]; |
215 | ssize_t nread; |
216 | |
217 | fd = open("/proc/sys/vm/overcommit_memory" , O_RDONLY); |
218 | if (fd == -1) |
219 | return (false); /* Error. */ |
220 | |
221 | nread = read(fd, &buf, sizeof(buf)); |
222 | if (nread < 1) |
223 | return (false); /* Error. */ |
224 | /* |
225 | * /proc/sys/vm/overcommit_memory meanings: |
226 | * 0: Heuristic overcommit. |
227 | * 1: Always overcommit. |
228 | * 2: Never overcommit. |
229 | */ |
230 | return (buf[0] == '0' || buf[0] == '1'); |
231 | } |
232 | #endif |
233 | |
234 | void |
235 | pages_boot(void) |
236 | { |
237 | |
238 | #ifndef _WIN32 |
239 | mmap_flags = MAP_PRIVATE | MAP_ANON; |
240 | #endif |
241 | |
242 | #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT |
243 | os_overcommits = os_overcommits_sysctl(); |
244 | #elif defined(JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY) |
245 | os_overcommits = os_overcommits_proc(); |
246 | # ifdef MAP_NORESERVE |
247 | if (os_overcommits) |
248 | mmap_flags |= MAP_NORESERVE; |
249 | # endif |
250 | #else |
251 | os_overcommits = false; |
252 | #endif |
253 | } |
254 | |