blob: 35d56eb99e7f7bb778be9e37aadad2e592c71d6f [file] [log] [blame]
Jason Evansb49a3342015-07-28 11:28:19 -04001#define JEMALLOC_PAGES_C_
2#include "jemalloc/internal/jemalloc_internal.h"
3
Jason Evansc2f970c2016-05-05 17:45:02 -07004#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)
14static int mmap_flags;
15#endif
Alex Naidis78897ab2016-10-04 14:08:33 +020016#if !defined(__ANDROID__)
Jason Evansc2f970c2016-05-05 17:45:02 -070017static bool os_overcommits;
Alex Naidis78897ab2016-10-04 14:08:33 +020018#else
19static const bool os_overcommits = true;
20#endif
Jason Evansc2f970c2016-05-05 17:45:02 -070021
Jason Evansb49a3342015-07-28 11:28:19 -040022/******************************************************************************/
Christopher Ferris6f50cbc2015-09-09 12:17:01 -070023/* Defines/includes needed for special android code. */
24
25#if defined(__ANDROID__)
26#include <sys/prctl.h>
27
28/* Definitions of prctl arguments to set a vma name in Android kernels. */
29#define ANDROID_PR_SET_VMA 0x53564d41
30#define ANDROID_PR_SET_VMA_ANON_NAME 0
31#endif
32
33/******************************************************************************/
Jason Evansb49a3342015-07-28 11:28:19 -040034
35void *
Jason Evansc2f970c2016-05-05 17:45:02 -070036pages_map(void *addr, size_t size, bool *commit)
Jason Evansb49a3342015-07-28 11:28:19 -040037{
38 void *ret;
39
40 assert(size != 0);
41
Jason Evansc2f970c2016-05-05 17:45:02 -070042 if (os_overcommits)
43 *commit = true;
44
Jason Evansb49a3342015-07-28 11:28:19 -040045#ifdef _WIN32
46 /*
47 * If VirtualAlloc can't allocate at the given address when one is
48 * given, it fails and returns NULL.
49 */
Jason Evansc2f970c2016-05-05 17:45:02 -070050 ret = VirtualAlloc(addr, size, MEM_RESERVE | (*commit ? MEM_COMMIT : 0),
Jason Evansb49a3342015-07-28 11:28:19 -040051 PAGE_READWRITE);
52#else
53 /*
54 * We don't use MAP_FIXED here, because it can cause the *replacement*
55 * of existing mappings, and we only want to create new mappings.
56 */
Jason Evansc2f970c2016-05-05 17:45:02 -070057 {
58 int prot = *commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT;
59
60 ret = mmap(addr, size, prot, mmap_flags, -1, 0);
61 }
Jason Evansb49a3342015-07-28 11:28:19 -040062 assert(ret != NULL);
63
64 if (ret == MAP_FAILED)
65 ret = NULL;
66 else if (addr != NULL && ret != addr) {
67 /*
68 * We succeeded in mapping memory, but not in the right place.
69 */
70 pages_unmap(ret, size);
71 ret = NULL;
72 }
73#endif
Christopher Ferris6f50cbc2015-09-09 12:17:01 -070074#if defined(__ANDROID__)
75 if (ret != NULL) {
76 /* Name this memory as being used by libc */
77 prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, ret,
78 size, "libc_malloc");
79 }
80#endif
Jason Evansb49a3342015-07-28 11:28:19 -040081 assert(ret == NULL || (addr == NULL && ret != addr)
82 || (addr != NULL && ret == addr));
83 return (ret);
84}
85
86void
87pages_unmap(void *addr, size_t size)
88{
89
90#ifdef _WIN32
91 if (VirtualFree(addr, 0, MEM_RELEASE) == 0)
92#else
93 if (munmap(addr, size) == -1)
94#endif
95 {
96 char buf[BUFERROR_BUF];
97
98 buferror(get_errno(), buf, sizeof(buf));
99 malloc_printf("<jemalloc>: Error in "
100#ifdef _WIN32
101 "VirtualFree"
102#else
103 "munmap"
104#endif
105 "(): %s\n", buf);
106 if (opt_abort)
107 abort();
108 }
109}
110
111void *
Jason Evansc2f970c2016-05-05 17:45:02 -0700112pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size,
113 bool *commit)
Jason Evansb49a3342015-07-28 11:28:19 -0400114{
115 void *ret = (void *)((uintptr_t)addr + leadsize);
116
117 assert(alloc_size >= leadsize + size);
118#ifdef _WIN32
119 {
120 void *new_addr;
121
122 pages_unmap(addr, alloc_size);
Jason Evansc2f970c2016-05-05 17:45:02 -0700123 new_addr = pages_map(ret, size, commit);
Jason Evansb49a3342015-07-28 11:28:19 -0400124 if (new_addr == ret)
125 return (ret);
126 if (new_addr)
127 pages_unmap(new_addr, size);
128 return (NULL);
129 }
130#else
131 {
132 size_t trailsize = alloc_size - leadsize - size;
133
134 if (leadsize != 0)
135 pages_unmap(addr, leadsize);
136 if (trailsize != 0)
137 pages_unmap((void *)((uintptr_t)ret + size), trailsize);
138 return (ret);
139 }
140#endif
141}
142
143static bool
144pages_commit_impl(void *addr, size_t size, bool commit)
145{
146
Jason Evansc2f970c2016-05-05 17:45:02 -0700147 if (os_overcommits)
148 return (true);
149
150#ifdef _WIN32
151 return (commit ? (addr != VirtualAlloc(addr, size, MEM_COMMIT,
152 PAGE_READWRITE)) : (!VirtualFree(addr, size, MEM_DECOMMIT)));
153#else
154 {
155 int prot = commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT;
156 void *result = mmap(addr, size, prot, mmap_flags | MAP_FIXED,
157 -1, 0);
Jason Evansb49a3342015-07-28 11:28:19 -0400158 if (result == MAP_FAILED)
159 return (true);
160 if (result != addr) {
161 /*
162 * We succeeded in mapping memory, but not in the right
163 * place.
164 */
165 pages_unmap(result, size);
166 return (true);
167 }
168 return (false);
169 }
170#endif
Jason Evansb49a3342015-07-28 11:28:19 -0400171}
172
173bool
174pages_commit(void *addr, size_t size)
175{
176
177 return (pages_commit_impl(addr, size, true));
178}
179
180bool
181pages_decommit(void *addr, size_t size)
182{
183
184 return (pages_commit_impl(addr, size, false));
185}
186
187bool
188pages_purge(void *addr, size_t size)
189{
190 bool unzeroed;
191
192#ifdef _WIN32
193 VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE);
194 unzeroed = true;
Jason Evanse98a6202016-11-17 13:36:17 -0800195#elif (defined(JEMALLOC_PURGE_MADVISE_FREE) || \
Jason Evans34a7e372016-12-03 16:06:19 -0800196 defined(JEMALLOC_PURGE_MADVISE_DONTNEED))
Jason Evans62f2d842016-11-17 10:24:51 -0800197# if defined(JEMALLOC_PURGE_MADVISE_FREE)
Jason Evansb49a3342015-07-28 11:28:19 -0400198# define JEMALLOC_MADV_PURGE MADV_FREE
199# define JEMALLOC_MADV_ZEROS false
Jason Evans62f2d842016-11-17 10:24:51 -0800200# elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED)
201# define JEMALLOC_MADV_PURGE MADV_DONTNEED
202# define JEMALLOC_MADV_ZEROS true
Jason Evansb49a3342015-07-28 11:28:19 -0400203# else
Jason Evans62f2d842016-11-17 10:24:51 -0800204# error No madvise(2) flag defined for purging unused dirty pages
Jason Evansb49a3342015-07-28 11:28:19 -0400205# endif
206 int err = madvise(addr, size, JEMALLOC_MADV_PURGE);
207 unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0);
208# undef JEMALLOC_MADV_PURGE
209# undef JEMALLOC_MADV_ZEROS
210#else
211 /* Last resort no-op. */
212 unzeroed = true;
213#endif
214 return (unzeroed);
215}
216
Jason Evanse98a6202016-11-17 13:36:17 -0800217bool
218pages_huge(void *addr, size_t size)
219{
220
221 assert(PAGE_ADDR2BASE(addr) == addr);
222 assert(PAGE_CEILING(size) == size);
223
224#ifdef JEMALLOC_THP
225 return (madvise(addr, size, MADV_HUGEPAGE) != 0);
226#else
227 return (false);
228#endif
229}
230
231bool
232pages_nohuge(void *addr, size_t size)
233{
234
235 assert(PAGE_ADDR2BASE(addr) == addr);
236 assert(PAGE_CEILING(size) == size);
237
238#ifdef JEMALLOC_THP
239 return (madvise(addr, size, MADV_NOHUGEPAGE) != 0);
240#else
241 return (false);
242#endif
243}
244
Jason Evansc2f970c2016-05-05 17:45:02 -0700245#ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
246static bool
247os_overcommits_sysctl(void)
248{
249 int vm_overcommit;
250 size_t sz;
251
252 sz = sizeof(vm_overcommit);
253 if (sysctlbyname("vm.overcommit", &vm_overcommit, &sz, NULL, 0) != 0)
254 return (false); /* Error. */
255
256 return ((vm_overcommit & 0x3) == 0);
257}
258#endif
259
260#ifdef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY
Jason Evansc443b672016-10-29 22:41:04 -0700261/*
262 * Use syscall(2) rather than {open,read,close}(2) when possible to avoid
263 * reentry during bootstrapping if another library has interposed system call
264 * wrappers.
265 */
Jason Evansc2f970c2016-05-05 17:45:02 -0700266static bool
267os_overcommits_proc(void)
268{
269 int fd;
270 char buf[1];
271 ssize_t nread;
272
Jason Evans145f3cd2016-12-03 16:47:36 -0800273#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
Jason Evansc443b672016-10-29 22:41:04 -0700274 fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY);
275#else
Jason Evansc2f970c2016-05-05 17:45:02 -0700276 fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY);
Jason Evansc443b672016-10-29 22:41:04 -0700277#endif
Jason Evansc2f970c2016-05-05 17:45:02 -0700278 if (fd == -1)
279 return (false); /* Error. */
280
Jason Evans145f3cd2016-12-03 16:47:36 -0800281#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read)
Jason Evansc443b672016-10-29 22:41:04 -0700282 nread = (ssize_t)syscall(SYS_read, fd, &buf, sizeof(buf));
283#else
Jason Evansc2f970c2016-05-05 17:45:02 -0700284 nread = read(fd, &buf, sizeof(buf));
Jason Evansc443b672016-10-29 22:41:04 -0700285#endif
286
Jason Evans145f3cd2016-12-03 16:47:36 -0800287#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
Jason Evansc443b672016-10-29 22:41:04 -0700288 syscall(SYS_close, fd);
289#else
Brian Carlstrom93ea0f52016-08-30 22:03:50 -0700290 close(fd);
Jason Evansc443b672016-10-29 22:41:04 -0700291#endif
292
Jason Evansc2f970c2016-05-05 17:45:02 -0700293 if (nread < 1)
294 return (false); /* Error. */
295 /*
296 * /proc/sys/vm/overcommit_memory meanings:
297 * 0: Heuristic overcommit.
298 * 1: Always overcommit.
299 * 2: Never overcommit.
300 */
301 return (buf[0] == '0' || buf[0] == '1');
302}
303#endif
304
305void
306pages_boot(void)
307{
Jason Evansc2f970c2016-05-05 17:45:02 -0700308#ifndef _WIN32
309 mmap_flags = MAP_PRIVATE | MAP_ANON;
310#endif
311
Alex Naidis78897ab2016-10-04 14:08:33 +0200312#if !defined(__ANDROID__)
Jason Evansc2f970c2016-05-05 17:45:02 -0700313#ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
314 os_overcommits = os_overcommits_sysctl();
315#elif defined(JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY)
316 os_overcommits = os_overcommits_proc();
317# ifdef MAP_NORESERVE
318 if (os_overcommits)
319 mmap_flags |= MAP_NORESERVE;
320# endif
321#else
322 os_overcommits = false;
323#endif
Alex Naidis78897ab2016-10-04 14:08:33 +0200324#endif
Jason Evansc2f970c2016-05-05 17:45:02 -0700325}