xref: /aosp_15_r20/external/jemalloc_new/src/pages.c (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_PAGES_C_
2*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_preamble.h"
3*1208bc7eSAndroid Build Coastguard Worker 
4*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/pages.h"
5*1208bc7eSAndroid Build Coastguard Worker 
6*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_internal_includes.h"
7*1208bc7eSAndroid Build Coastguard Worker 
8*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/assert.h"
9*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/malloc_io.h"
10*1208bc7eSAndroid Build Coastguard Worker 
11*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
12*1208bc7eSAndroid Build Coastguard Worker #include <sys/sysctl.h>
13*1208bc7eSAndroid Build Coastguard Worker #ifdef __FreeBSD__
14*1208bc7eSAndroid Build Coastguard Worker #include <vm/vm_param.h>
15*1208bc7eSAndroid Build Coastguard Worker #endif
16*1208bc7eSAndroid Build Coastguard Worker #endif
17*1208bc7eSAndroid Build Coastguard Worker 
18*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
19*1208bc7eSAndroid Build Coastguard Worker /* Defines/includes needed for special android code. */
20*1208bc7eSAndroid Build Coastguard Worker 
21*1208bc7eSAndroid Build Coastguard Worker #if defined(__ANDROID__)
22*1208bc7eSAndroid Build Coastguard Worker #include <sys/prctl.h>
23*1208bc7eSAndroid Build Coastguard Worker #endif
24*1208bc7eSAndroid Build Coastguard Worker 
25*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
26*1208bc7eSAndroid Build Coastguard Worker /* Data. */
27*1208bc7eSAndroid Build Coastguard Worker 
28*1208bc7eSAndroid Build Coastguard Worker /* Actual operating system page size, detected during bootstrap, <= PAGE. */
29*1208bc7eSAndroid Build Coastguard Worker static size_t	os_page;
30*1208bc7eSAndroid Build Coastguard Worker 
31*1208bc7eSAndroid Build Coastguard Worker #ifndef _WIN32
32*1208bc7eSAndroid Build Coastguard Worker #  define PAGES_PROT_COMMIT (PROT_READ | PROT_WRITE)
33*1208bc7eSAndroid Build Coastguard Worker #  define PAGES_PROT_DECOMMIT (PROT_NONE)
34*1208bc7eSAndroid Build Coastguard Worker static int	mmap_flags;
35*1208bc7eSAndroid Build Coastguard Worker #endif
36*1208bc7eSAndroid Build Coastguard Worker static bool	os_overcommits;
37*1208bc7eSAndroid Build Coastguard Worker 
38*1208bc7eSAndroid Build Coastguard Worker const char *thp_mode_names[] = {
39*1208bc7eSAndroid Build Coastguard Worker 	"default",
40*1208bc7eSAndroid Build Coastguard Worker 	"always",
41*1208bc7eSAndroid Build Coastguard Worker 	"never",
42*1208bc7eSAndroid Build Coastguard Worker 	"not supported"
43*1208bc7eSAndroid Build Coastguard Worker };
44*1208bc7eSAndroid Build Coastguard Worker thp_mode_t opt_thp = THP_MODE_DEFAULT;
45*1208bc7eSAndroid Build Coastguard Worker thp_mode_t init_system_thp_mode;
46*1208bc7eSAndroid Build Coastguard Worker 
47*1208bc7eSAndroid Build Coastguard Worker /* Runtime support for lazy purge. Irrelevant when !pages_can_purge_lazy. */
48*1208bc7eSAndroid Build Coastguard Worker static bool pages_can_purge_lazy_runtime = true;
49*1208bc7eSAndroid Build Coastguard Worker 
50*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
51*1208bc7eSAndroid Build Coastguard Worker /*
52*1208bc7eSAndroid Build Coastguard Worker  * Function prototypes for static functions that are referenced prior to
53*1208bc7eSAndroid Build Coastguard Worker  * definition.
54*1208bc7eSAndroid Build Coastguard Worker  */
55*1208bc7eSAndroid Build Coastguard Worker 
56*1208bc7eSAndroid Build Coastguard Worker static void os_pages_unmap(void *addr, size_t size);
57*1208bc7eSAndroid Build Coastguard Worker 
58*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
59*1208bc7eSAndroid Build Coastguard Worker 
60*1208bc7eSAndroid Build Coastguard Worker static void *
os_pages_map(void * addr,size_t size,size_t alignment,bool * commit)61*1208bc7eSAndroid Build Coastguard Worker os_pages_map(void *addr, size_t size, size_t alignment, bool *commit) {
62*1208bc7eSAndroid Build Coastguard Worker 	assert(ALIGNMENT_ADDR2BASE(addr, os_page) == addr);
63*1208bc7eSAndroid Build Coastguard Worker 	assert(ALIGNMENT_CEILING(size, os_page) == size);
64*1208bc7eSAndroid Build Coastguard Worker 	assert(size != 0);
65*1208bc7eSAndroid Build Coastguard Worker 
66*1208bc7eSAndroid Build Coastguard Worker 	if (os_overcommits) {
67*1208bc7eSAndroid Build Coastguard Worker 		*commit = true;
68*1208bc7eSAndroid Build Coastguard Worker 	}
69*1208bc7eSAndroid Build Coastguard Worker 
70*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
71*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
72*1208bc7eSAndroid Build Coastguard Worker 	/*
73*1208bc7eSAndroid Build Coastguard Worker 	 * If VirtualAlloc can't allocate at the given address when one is
74*1208bc7eSAndroid Build Coastguard Worker 	 * given, it fails and returns NULL.
75*1208bc7eSAndroid Build Coastguard Worker 	 */
76*1208bc7eSAndroid Build Coastguard Worker 	ret = VirtualAlloc(addr, size, MEM_RESERVE | (*commit ? MEM_COMMIT : 0),
77*1208bc7eSAndroid Build Coastguard Worker 	    PAGE_READWRITE);
78*1208bc7eSAndroid Build Coastguard Worker #else
79*1208bc7eSAndroid Build Coastguard Worker 	/*
80*1208bc7eSAndroid Build Coastguard Worker 	 * We don't use MAP_FIXED here, because it can cause the *replacement*
81*1208bc7eSAndroid Build Coastguard Worker 	 * of existing mappings, and we only want to create new mappings.
82*1208bc7eSAndroid Build Coastguard Worker 	 */
83*1208bc7eSAndroid Build Coastguard Worker 	{
84*1208bc7eSAndroid Build Coastguard Worker 		int prot = *commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT;
85*1208bc7eSAndroid Build Coastguard Worker 
86*1208bc7eSAndroid Build Coastguard Worker 		ret = mmap(addr, size, prot, mmap_flags, -1, 0);
87*1208bc7eSAndroid Build Coastguard Worker 	}
88*1208bc7eSAndroid Build Coastguard Worker 	assert(ret != NULL);
89*1208bc7eSAndroid Build Coastguard Worker 
90*1208bc7eSAndroid Build Coastguard Worker 	if (ret == MAP_FAILED) {
91*1208bc7eSAndroid Build Coastguard Worker 		ret = NULL;
92*1208bc7eSAndroid Build Coastguard Worker 	} else if (addr != NULL && ret != addr) {
93*1208bc7eSAndroid Build Coastguard Worker 		/*
94*1208bc7eSAndroid Build Coastguard Worker 		 * We succeeded in mapping memory, but not in the right place.
95*1208bc7eSAndroid Build Coastguard Worker 		 */
96*1208bc7eSAndroid Build Coastguard Worker 		os_pages_unmap(ret, size);
97*1208bc7eSAndroid Build Coastguard Worker 		ret = NULL;
98*1208bc7eSAndroid Build Coastguard Worker 	}
99*1208bc7eSAndroid Build Coastguard Worker #endif
100*1208bc7eSAndroid Build Coastguard Worker #if defined(__ANDROID__)
101*1208bc7eSAndroid Build Coastguard Worker 	if (ret != NULL) {
102*1208bc7eSAndroid Build Coastguard Worker 		/* Name this memory as being used by libc */
103*1208bc7eSAndroid Build Coastguard Worker 		prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ret, size,
104*1208bc7eSAndroid Build Coastguard Worker 		    "libc_malloc");
105*1208bc7eSAndroid Build Coastguard Worker 	}
106*1208bc7eSAndroid Build Coastguard Worker #endif
107*1208bc7eSAndroid Build Coastguard Worker 	assert(ret == NULL || (addr == NULL && ret != addr) || (addr != NULL &&
108*1208bc7eSAndroid Build Coastguard Worker 	    ret == addr));
109*1208bc7eSAndroid Build Coastguard Worker 	return ret;
110*1208bc7eSAndroid Build Coastguard Worker }
111*1208bc7eSAndroid Build Coastguard Worker 
112*1208bc7eSAndroid Build Coastguard Worker static void *
os_pages_trim(void * addr,size_t alloc_size,size_t leadsize,size_t size,bool * commit)113*1208bc7eSAndroid Build Coastguard Worker os_pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size,
114*1208bc7eSAndroid Build Coastguard Worker     bool *commit) {
115*1208bc7eSAndroid Build Coastguard Worker 	void *ret = (void *)((uintptr_t)addr + leadsize);
116*1208bc7eSAndroid Build Coastguard Worker 
117*1208bc7eSAndroid Build Coastguard Worker 	assert(alloc_size >= leadsize + size);
118*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
119*1208bc7eSAndroid Build Coastguard Worker 	os_pages_unmap(addr, alloc_size);
120*1208bc7eSAndroid Build Coastguard Worker 	void *new_addr = os_pages_map(ret, size, PAGE, commit);
121*1208bc7eSAndroid Build Coastguard Worker 	if (new_addr == ret) {
122*1208bc7eSAndroid Build Coastguard Worker 		return ret;
123*1208bc7eSAndroid Build Coastguard Worker 	}
124*1208bc7eSAndroid Build Coastguard Worker 	if (new_addr != NULL) {
125*1208bc7eSAndroid Build Coastguard Worker 		os_pages_unmap(new_addr, size);
126*1208bc7eSAndroid Build Coastguard Worker 	}
127*1208bc7eSAndroid Build Coastguard Worker 	return NULL;
128*1208bc7eSAndroid Build Coastguard Worker #else
129*1208bc7eSAndroid Build Coastguard Worker 	size_t trailsize = alloc_size - leadsize - size;
130*1208bc7eSAndroid Build Coastguard Worker 
131*1208bc7eSAndroid Build Coastguard Worker 	if (leadsize != 0) {
132*1208bc7eSAndroid Build Coastguard Worker 		os_pages_unmap(addr, leadsize);
133*1208bc7eSAndroid Build Coastguard Worker 	}
134*1208bc7eSAndroid Build Coastguard Worker 	if (trailsize != 0) {
135*1208bc7eSAndroid Build Coastguard Worker 		os_pages_unmap((void *)((uintptr_t)ret + size), trailsize);
136*1208bc7eSAndroid Build Coastguard Worker 	}
137*1208bc7eSAndroid Build Coastguard Worker 	return ret;
138*1208bc7eSAndroid Build Coastguard Worker #endif
139*1208bc7eSAndroid Build Coastguard Worker }
140*1208bc7eSAndroid Build Coastguard Worker 
141*1208bc7eSAndroid Build Coastguard Worker static void
os_pages_unmap(void * addr,size_t size)142*1208bc7eSAndroid Build Coastguard Worker os_pages_unmap(void *addr, size_t size) {
143*1208bc7eSAndroid Build Coastguard Worker 	assert(ALIGNMENT_ADDR2BASE(addr, os_page) == addr);
144*1208bc7eSAndroid Build Coastguard Worker 	assert(ALIGNMENT_CEILING(size, os_page) == size);
145*1208bc7eSAndroid Build Coastguard Worker 
146*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
147*1208bc7eSAndroid Build Coastguard Worker 	if (VirtualFree(addr, 0, MEM_RELEASE) == 0)
148*1208bc7eSAndroid Build Coastguard Worker #else
149*1208bc7eSAndroid Build Coastguard Worker 	if (munmap(addr, size) == -1)
150*1208bc7eSAndroid Build Coastguard Worker #endif
151*1208bc7eSAndroid Build Coastguard Worker 	{
152*1208bc7eSAndroid Build Coastguard Worker 		char buf[BUFERROR_BUF];
153*1208bc7eSAndroid Build Coastguard Worker 
154*1208bc7eSAndroid Build Coastguard Worker 		buferror(get_errno(), buf, sizeof(buf));
155*1208bc7eSAndroid Build Coastguard Worker 		malloc_printf("<jemalloc>: Error in "
156*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
157*1208bc7eSAndroid Build Coastguard Worker 		    "VirtualFree"
158*1208bc7eSAndroid Build Coastguard Worker #else
159*1208bc7eSAndroid Build Coastguard Worker 		    "munmap"
160*1208bc7eSAndroid Build Coastguard Worker #endif
161*1208bc7eSAndroid Build Coastguard Worker 		    "(): %s\n", buf);
162*1208bc7eSAndroid Build Coastguard Worker 		if (opt_abort) {
163*1208bc7eSAndroid Build Coastguard Worker 			abort();
164*1208bc7eSAndroid Build Coastguard Worker 		}
165*1208bc7eSAndroid Build Coastguard Worker 	}
166*1208bc7eSAndroid Build Coastguard Worker }
167*1208bc7eSAndroid Build Coastguard Worker 
168*1208bc7eSAndroid Build Coastguard Worker static void *
pages_map_slow(size_t size,size_t alignment,bool * commit)169*1208bc7eSAndroid Build Coastguard Worker pages_map_slow(size_t size, size_t alignment, bool *commit) {
170*1208bc7eSAndroid Build Coastguard Worker 	size_t alloc_size = size + alignment - os_page;
171*1208bc7eSAndroid Build Coastguard Worker 	/* Beware size_t wrap-around. */
172*1208bc7eSAndroid Build Coastguard Worker 	if (alloc_size < size) {
173*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
174*1208bc7eSAndroid Build Coastguard Worker 	}
175*1208bc7eSAndroid Build Coastguard Worker 
176*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
177*1208bc7eSAndroid Build Coastguard Worker 	do {
178*1208bc7eSAndroid Build Coastguard Worker 		void *pages = os_pages_map(NULL, alloc_size, alignment, commit);
179*1208bc7eSAndroid Build Coastguard Worker 		if (pages == NULL) {
180*1208bc7eSAndroid Build Coastguard Worker 			return NULL;
181*1208bc7eSAndroid Build Coastguard Worker 		}
182*1208bc7eSAndroid Build Coastguard Worker 		size_t leadsize = ALIGNMENT_CEILING((uintptr_t)pages, alignment)
183*1208bc7eSAndroid Build Coastguard Worker 		    - (uintptr_t)pages;
184*1208bc7eSAndroid Build Coastguard Worker 		ret = os_pages_trim(pages, alloc_size, leadsize, size, commit);
185*1208bc7eSAndroid Build Coastguard Worker 	} while (ret == NULL);
186*1208bc7eSAndroid Build Coastguard Worker 
187*1208bc7eSAndroid Build Coastguard Worker 	assert(ret != NULL);
188*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(ret) == ret);
189*1208bc7eSAndroid Build Coastguard Worker 	return ret;
190*1208bc7eSAndroid Build Coastguard Worker }
191*1208bc7eSAndroid Build Coastguard Worker 
192*1208bc7eSAndroid Build Coastguard Worker void *
pages_map(void * addr,size_t size,size_t alignment,bool * commit)193*1208bc7eSAndroid Build Coastguard Worker pages_map(void *addr, size_t size, size_t alignment, bool *commit) {
194*1208bc7eSAndroid Build Coastguard Worker 	assert(alignment >= PAGE);
195*1208bc7eSAndroid Build Coastguard Worker 	assert(ALIGNMENT_ADDR2BASE(addr, alignment) == addr);
196*1208bc7eSAndroid Build Coastguard Worker 
197*1208bc7eSAndroid Build Coastguard Worker 	/*
198*1208bc7eSAndroid Build Coastguard Worker 	 * Ideally, there would be a way to specify alignment to mmap() (like
199*1208bc7eSAndroid Build Coastguard Worker 	 * NetBSD has), but in the absence of such a feature, we have to work
200*1208bc7eSAndroid Build Coastguard Worker 	 * hard to efficiently create aligned mappings.  The reliable, but
201*1208bc7eSAndroid Build Coastguard Worker 	 * slow method is to create a mapping that is over-sized, then trim the
202*1208bc7eSAndroid Build Coastguard Worker 	 * excess.  However, that always results in one or two calls to
203*1208bc7eSAndroid Build Coastguard Worker 	 * os_pages_unmap(), and it can leave holes in the process's virtual
204*1208bc7eSAndroid Build Coastguard Worker 	 * memory map if memory grows downward.
205*1208bc7eSAndroid Build Coastguard Worker 	 *
206*1208bc7eSAndroid Build Coastguard Worker 	 * Optimistically try mapping precisely the right amount before falling
207*1208bc7eSAndroid Build Coastguard Worker 	 * back to the slow method, with the expectation that the optimistic
208*1208bc7eSAndroid Build Coastguard Worker 	 * approach works most of the time.
209*1208bc7eSAndroid Build Coastguard Worker 	 */
210*1208bc7eSAndroid Build Coastguard Worker 
211*1208bc7eSAndroid Build Coastguard Worker 	void *ret = os_pages_map(addr, size, os_page, commit);
212*1208bc7eSAndroid Build Coastguard Worker 	if (ret == NULL || ret == addr) {
213*1208bc7eSAndroid Build Coastguard Worker 		return ret;
214*1208bc7eSAndroid Build Coastguard Worker 	}
215*1208bc7eSAndroid Build Coastguard Worker 	assert(addr == NULL);
216*1208bc7eSAndroid Build Coastguard Worker 	if (ALIGNMENT_ADDR2OFFSET(ret, alignment) != 0) {
217*1208bc7eSAndroid Build Coastguard Worker 		os_pages_unmap(ret, size);
218*1208bc7eSAndroid Build Coastguard Worker 		return pages_map_slow(size, alignment, commit);
219*1208bc7eSAndroid Build Coastguard Worker 	}
220*1208bc7eSAndroid Build Coastguard Worker 
221*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(ret) == ret);
222*1208bc7eSAndroid Build Coastguard Worker 	return ret;
223*1208bc7eSAndroid Build Coastguard Worker }
224*1208bc7eSAndroid Build Coastguard Worker 
225*1208bc7eSAndroid Build Coastguard Worker void
pages_unmap(void * addr,size_t size)226*1208bc7eSAndroid Build Coastguard Worker pages_unmap(void *addr, size_t size) {
227*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(addr) == addr);
228*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_CEILING(size) == size);
229*1208bc7eSAndroid Build Coastguard Worker 
230*1208bc7eSAndroid Build Coastguard Worker 	os_pages_unmap(addr, size);
231*1208bc7eSAndroid Build Coastguard Worker }
232*1208bc7eSAndroid Build Coastguard Worker 
233*1208bc7eSAndroid Build Coastguard Worker static bool
pages_commit_impl(void * addr,size_t size,bool commit)234*1208bc7eSAndroid Build Coastguard Worker pages_commit_impl(void *addr, size_t size, bool commit) {
235*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(addr) == addr);
236*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_CEILING(size) == size);
237*1208bc7eSAndroid Build Coastguard Worker 
238*1208bc7eSAndroid Build Coastguard Worker 	if (os_overcommits) {
239*1208bc7eSAndroid Build Coastguard Worker 		return true;
240*1208bc7eSAndroid Build Coastguard Worker 	}
241*1208bc7eSAndroid Build Coastguard Worker 
242*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
243*1208bc7eSAndroid Build Coastguard Worker 	return (commit ? (addr != VirtualAlloc(addr, size, MEM_COMMIT,
244*1208bc7eSAndroid Build Coastguard Worker 	    PAGE_READWRITE)) : (!VirtualFree(addr, size, MEM_DECOMMIT)));
245*1208bc7eSAndroid Build Coastguard Worker #else
246*1208bc7eSAndroid Build Coastguard Worker 	{
247*1208bc7eSAndroid Build Coastguard Worker 		int prot = commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT;
248*1208bc7eSAndroid Build Coastguard Worker 		void *result = mmap(addr, size, prot, mmap_flags | MAP_FIXED,
249*1208bc7eSAndroid Build Coastguard Worker 		    -1, 0);
250*1208bc7eSAndroid Build Coastguard Worker 		if (result == MAP_FAILED) {
251*1208bc7eSAndroid Build Coastguard Worker 			return true;
252*1208bc7eSAndroid Build Coastguard Worker 		}
253*1208bc7eSAndroid Build Coastguard Worker 		if (result != addr) {
254*1208bc7eSAndroid Build Coastguard Worker 			/*
255*1208bc7eSAndroid Build Coastguard Worker 			 * We succeeded in mapping memory, but not in the right
256*1208bc7eSAndroid Build Coastguard Worker 			 * place.
257*1208bc7eSAndroid Build Coastguard Worker 			 */
258*1208bc7eSAndroid Build Coastguard Worker 			os_pages_unmap(result, size);
259*1208bc7eSAndroid Build Coastguard Worker 			return true;
260*1208bc7eSAndroid Build Coastguard Worker 		}
261*1208bc7eSAndroid Build Coastguard Worker 		return false;
262*1208bc7eSAndroid Build Coastguard Worker 	}
263*1208bc7eSAndroid Build Coastguard Worker #endif
264*1208bc7eSAndroid Build Coastguard Worker }
265*1208bc7eSAndroid Build Coastguard Worker 
266*1208bc7eSAndroid Build Coastguard Worker bool
pages_commit(void * addr,size_t size)267*1208bc7eSAndroid Build Coastguard Worker pages_commit(void *addr, size_t size) {
268*1208bc7eSAndroid Build Coastguard Worker 	return pages_commit_impl(addr, size, true);
269*1208bc7eSAndroid Build Coastguard Worker }
270*1208bc7eSAndroid Build Coastguard Worker 
271*1208bc7eSAndroid Build Coastguard Worker bool
pages_decommit(void * addr,size_t size)272*1208bc7eSAndroid Build Coastguard Worker pages_decommit(void *addr, size_t size) {
273*1208bc7eSAndroid Build Coastguard Worker 	return pages_commit_impl(addr, size, false);
274*1208bc7eSAndroid Build Coastguard Worker }
275*1208bc7eSAndroid Build Coastguard Worker 
276*1208bc7eSAndroid Build Coastguard Worker bool
pages_purge_lazy(void * addr,size_t size)277*1208bc7eSAndroid Build Coastguard Worker pages_purge_lazy(void *addr, size_t size) {
278*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(addr) == addr);
279*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_CEILING(size) == size);
280*1208bc7eSAndroid Build Coastguard Worker 
281*1208bc7eSAndroid Build Coastguard Worker 	if (!pages_can_purge_lazy) {
282*1208bc7eSAndroid Build Coastguard Worker 		return true;
283*1208bc7eSAndroid Build Coastguard Worker 	}
284*1208bc7eSAndroid Build Coastguard Worker 	if (!pages_can_purge_lazy_runtime) {
285*1208bc7eSAndroid Build Coastguard Worker 		/*
286*1208bc7eSAndroid Build Coastguard Worker 		 * Built with lazy purge enabled, but detected it was not
287*1208bc7eSAndroid Build Coastguard Worker 		 * supported on the current system.
288*1208bc7eSAndroid Build Coastguard Worker 		 */
289*1208bc7eSAndroid Build Coastguard Worker 		return true;
290*1208bc7eSAndroid Build Coastguard Worker 	}
291*1208bc7eSAndroid Build Coastguard Worker 
292*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
293*1208bc7eSAndroid Build Coastguard Worker 	VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE);
294*1208bc7eSAndroid Build Coastguard Worker 	return false;
295*1208bc7eSAndroid Build Coastguard Worker #elif defined(JEMALLOC_PURGE_MADVISE_FREE)
296*1208bc7eSAndroid Build Coastguard Worker 	return (madvise(addr, size,
297*1208bc7eSAndroid Build Coastguard Worker #  ifdef MADV_FREE
298*1208bc7eSAndroid Build Coastguard Worker 	    MADV_FREE
299*1208bc7eSAndroid Build Coastguard Worker #  else
300*1208bc7eSAndroid Build Coastguard Worker 	    JEMALLOC_MADV_FREE
301*1208bc7eSAndroid Build Coastguard Worker #  endif
302*1208bc7eSAndroid Build Coastguard Worker 	    ) != 0);
303*1208bc7eSAndroid Build Coastguard Worker #elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \
304*1208bc7eSAndroid Build Coastguard Worker     !defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS)
305*1208bc7eSAndroid Build Coastguard Worker 	return (madvise(addr, size, MADV_DONTNEED) != 0);
306*1208bc7eSAndroid Build Coastguard Worker #else
307*1208bc7eSAndroid Build Coastguard Worker 	not_reached();
308*1208bc7eSAndroid Build Coastguard Worker #endif
309*1208bc7eSAndroid Build Coastguard Worker }
310*1208bc7eSAndroid Build Coastguard Worker 
311*1208bc7eSAndroid Build Coastguard Worker bool
pages_purge_forced(void * addr,size_t size)312*1208bc7eSAndroid Build Coastguard Worker pages_purge_forced(void *addr, size_t size) {
313*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(addr) == addr);
314*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_CEILING(size) == size);
315*1208bc7eSAndroid Build Coastguard Worker 
316*1208bc7eSAndroid Build Coastguard Worker 	if (!pages_can_purge_forced) {
317*1208bc7eSAndroid Build Coastguard Worker 		return true;
318*1208bc7eSAndroid Build Coastguard Worker 	}
319*1208bc7eSAndroid Build Coastguard Worker 
320*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \
321*1208bc7eSAndroid Build Coastguard Worker     defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS)
322*1208bc7eSAndroid Build Coastguard Worker 	return (madvise(addr, size, MADV_DONTNEED) != 0);
323*1208bc7eSAndroid Build Coastguard Worker #elif defined(JEMALLOC_MAPS_COALESCE)
324*1208bc7eSAndroid Build Coastguard Worker 	/* Try to overlay a new demand-zeroed mapping. */
325*1208bc7eSAndroid Build Coastguard Worker 	return pages_commit(addr, size);
326*1208bc7eSAndroid Build Coastguard Worker #else
327*1208bc7eSAndroid Build Coastguard Worker 	not_reached();
328*1208bc7eSAndroid Build Coastguard Worker #endif
329*1208bc7eSAndroid Build Coastguard Worker }
330*1208bc7eSAndroid Build Coastguard Worker 
331*1208bc7eSAndroid Build Coastguard Worker static bool
pages_huge_impl(void * addr,size_t size,bool aligned)332*1208bc7eSAndroid Build Coastguard Worker pages_huge_impl(void *addr, size_t size, bool aligned) {
333*1208bc7eSAndroid Build Coastguard Worker 	if (aligned) {
334*1208bc7eSAndroid Build Coastguard Worker 		assert(HUGEPAGE_ADDR2BASE(addr) == addr);
335*1208bc7eSAndroid Build Coastguard Worker 		assert(HUGEPAGE_CEILING(size) == size);
336*1208bc7eSAndroid Build Coastguard Worker 	}
337*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_HAVE_MADVISE_HUGE
338*1208bc7eSAndroid Build Coastguard Worker 	return (madvise(addr, size, MADV_HUGEPAGE) != 0);
339*1208bc7eSAndroid Build Coastguard Worker #else
340*1208bc7eSAndroid Build Coastguard Worker 	return true;
341*1208bc7eSAndroid Build Coastguard Worker #endif
342*1208bc7eSAndroid Build Coastguard Worker }
343*1208bc7eSAndroid Build Coastguard Worker 
344*1208bc7eSAndroid Build Coastguard Worker bool
pages_huge(void * addr,size_t size)345*1208bc7eSAndroid Build Coastguard Worker pages_huge(void *addr, size_t size) {
346*1208bc7eSAndroid Build Coastguard Worker 	return pages_huge_impl(addr, size, true);
347*1208bc7eSAndroid Build Coastguard Worker }
348*1208bc7eSAndroid Build Coastguard Worker 
349*1208bc7eSAndroid Build Coastguard Worker static bool
pages_huge_unaligned(void * addr,size_t size)350*1208bc7eSAndroid Build Coastguard Worker pages_huge_unaligned(void *addr, size_t size) {
351*1208bc7eSAndroid Build Coastguard Worker 	return pages_huge_impl(addr, size, false);
352*1208bc7eSAndroid Build Coastguard Worker }
353*1208bc7eSAndroid Build Coastguard Worker 
354*1208bc7eSAndroid Build Coastguard Worker static bool
pages_nohuge_impl(void * addr,size_t size,bool aligned)355*1208bc7eSAndroid Build Coastguard Worker pages_nohuge_impl(void *addr, size_t size, bool aligned) {
356*1208bc7eSAndroid Build Coastguard Worker 	if (aligned) {
357*1208bc7eSAndroid Build Coastguard Worker 		assert(HUGEPAGE_ADDR2BASE(addr) == addr);
358*1208bc7eSAndroid Build Coastguard Worker 		assert(HUGEPAGE_CEILING(size) == size);
359*1208bc7eSAndroid Build Coastguard Worker 	}
360*1208bc7eSAndroid Build Coastguard Worker 
361*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_HAVE_MADVISE_HUGE
362*1208bc7eSAndroid Build Coastguard Worker 	return (madvise(addr, size, MADV_NOHUGEPAGE) != 0);
363*1208bc7eSAndroid Build Coastguard Worker #else
364*1208bc7eSAndroid Build Coastguard Worker 	return false;
365*1208bc7eSAndroid Build Coastguard Worker #endif
366*1208bc7eSAndroid Build Coastguard Worker }
367*1208bc7eSAndroid Build Coastguard Worker 
368*1208bc7eSAndroid Build Coastguard Worker bool
pages_nohuge(void * addr,size_t size)369*1208bc7eSAndroid Build Coastguard Worker pages_nohuge(void *addr, size_t size) {
370*1208bc7eSAndroid Build Coastguard Worker 	return pages_nohuge_impl(addr, size, true);
371*1208bc7eSAndroid Build Coastguard Worker }
372*1208bc7eSAndroid Build Coastguard Worker 
373*1208bc7eSAndroid Build Coastguard Worker static bool
pages_nohuge_unaligned(void * addr,size_t size)374*1208bc7eSAndroid Build Coastguard Worker pages_nohuge_unaligned(void *addr, size_t size) {
375*1208bc7eSAndroid Build Coastguard Worker 	return pages_nohuge_impl(addr, size, false);
376*1208bc7eSAndroid Build Coastguard Worker }
377*1208bc7eSAndroid Build Coastguard Worker 
378*1208bc7eSAndroid Build Coastguard Worker bool
pages_dontdump(void * addr,size_t size)379*1208bc7eSAndroid Build Coastguard Worker pages_dontdump(void *addr, size_t size) {
380*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(addr) == addr);
381*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_CEILING(size) == size);
382*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MADVISE_DONTDUMP
383*1208bc7eSAndroid Build Coastguard Worker 	return madvise(addr, size, MADV_DONTDUMP) != 0;
384*1208bc7eSAndroid Build Coastguard Worker #else
385*1208bc7eSAndroid Build Coastguard Worker 	return false;
386*1208bc7eSAndroid Build Coastguard Worker #endif
387*1208bc7eSAndroid Build Coastguard Worker }
388*1208bc7eSAndroid Build Coastguard Worker 
389*1208bc7eSAndroid Build Coastguard Worker bool
pages_dodump(void * addr,size_t size)390*1208bc7eSAndroid Build Coastguard Worker pages_dodump(void *addr, size_t size) {
391*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_ADDR2BASE(addr) == addr);
392*1208bc7eSAndroid Build Coastguard Worker 	assert(PAGE_CEILING(size) == size);
393*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MADVISE_DONTDUMP
394*1208bc7eSAndroid Build Coastguard Worker 	return madvise(addr, size, MADV_DODUMP) != 0;
395*1208bc7eSAndroid Build Coastguard Worker #else
396*1208bc7eSAndroid Build Coastguard Worker 	return false;
397*1208bc7eSAndroid Build Coastguard Worker #endif
398*1208bc7eSAndroid Build Coastguard Worker }
399*1208bc7eSAndroid Build Coastguard Worker 
400*1208bc7eSAndroid Build Coastguard Worker 
401*1208bc7eSAndroid Build Coastguard Worker static size_t
os_page_detect(void)402*1208bc7eSAndroid Build Coastguard Worker os_page_detect(void) {
403*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
404*1208bc7eSAndroid Build Coastguard Worker 	SYSTEM_INFO si;
405*1208bc7eSAndroid Build Coastguard Worker 	GetSystemInfo(&si);
406*1208bc7eSAndroid Build Coastguard Worker 	return si.dwPageSize;
407*1208bc7eSAndroid Build Coastguard Worker #elif defined(__FreeBSD__)
408*1208bc7eSAndroid Build Coastguard Worker 	return getpagesize();
409*1208bc7eSAndroid Build Coastguard Worker #else
410*1208bc7eSAndroid Build Coastguard Worker 	long result = sysconf(_SC_PAGESIZE);
411*1208bc7eSAndroid Build Coastguard Worker 	if (result == -1) {
412*1208bc7eSAndroid Build Coastguard Worker 		return LG_PAGE;
413*1208bc7eSAndroid Build Coastguard Worker 	}
414*1208bc7eSAndroid Build Coastguard Worker 	return (size_t)result;
415*1208bc7eSAndroid Build Coastguard Worker #endif
416*1208bc7eSAndroid Build Coastguard Worker }
417*1208bc7eSAndroid Build Coastguard Worker 
418*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
419*1208bc7eSAndroid Build Coastguard Worker static bool
os_overcommits_sysctl(void)420*1208bc7eSAndroid Build Coastguard Worker os_overcommits_sysctl(void) {
421*1208bc7eSAndroid Build Coastguard Worker 	int vm_overcommit;
422*1208bc7eSAndroid Build Coastguard Worker 	size_t sz;
423*1208bc7eSAndroid Build Coastguard Worker 
424*1208bc7eSAndroid Build Coastguard Worker 	sz = sizeof(vm_overcommit);
425*1208bc7eSAndroid Build Coastguard Worker #if defined(__FreeBSD__) && defined(VM_OVERCOMMIT)
426*1208bc7eSAndroid Build Coastguard Worker 	int mib[2];
427*1208bc7eSAndroid Build Coastguard Worker 
428*1208bc7eSAndroid Build Coastguard Worker 	mib[0] = CTL_VM;
429*1208bc7eSAndroid Build Coastguard Worker 	mib[1] = VM_OVERCOMMIT;
430*1208bc7eSAndroid Build Coastguard Worker 	if (sysctl(mib, 2, &vm_overcommit, &sz, NULL, 0) != 0) {
431*1208bc7eSAndroid Build Coastguard Worker 		return false; /* Error. */
432*1208bc7eSAndroid Build Coastguard Worker 	}
433*1208bc7eSAndroid Build Coastguard Worker #else
434*1208bc7eSAndroid Build Coastguard Worker 	if (sysctlbyname("vm.overcommit", &vm_overcommit, &sz, NULL, 0) != 0) {
435*1208bc7eSAndroid Build Coastguard Worker 		return false; /* Error. */
436*1208bc7eSAndroid Build Coastguard Worker 	}
437*1208bc7eSAndroid Build Coastguard Worker #endif
438*1208bc7eSAndroid Build Coastguard Worker 
439*1208bc7eSAndroid Build Coastguard Worker 	return ((vm_overcommit & 0x3) == 0);
440*1208bc7eSAndroid Build Coastguard Worker }
441*1208bc7eSAndroid Build Coastguard Worker #endif
442*1208bc7eSAndroid Build Coastguard Worker 
443*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY
444*1208bc7eSAndroid Build Coastguard Worker /*
445*1208bc7eSAndroid Build Coastguard Worker  * Use syscall(2) rather than {open,read,close}(2) when possible to avoid
446*1208bc7eSAndroid Build Coastguard Worker  * reentry during bootstrapping if another library has interposed system call
447*1208bc7eSAndroid Build Coastguard Worker  * wrappers.
448*1208bc7eSAndroid Build Coastguard Worker  */
449*1208bc7eSAndroid Build Coastguard Worker static bool
os_overcommits_proc(void)450*1208bc7eSAndroid Build Coastguard Worker os_overcommits_proc(void) {
451*1208bc7eSAndroid Build Coastguard Worker 	int fd;
452*1208bc7eSAndroid Build Coastguard Worker 	char buf[1];
453*1208bc7eSAndroid Build Coastguard Worker 
454*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
455*1208bc7eSAndroid Build Coastguard Worker 	#if defined(O_CLOEXEC)
456*1208bc7eSAndroid Build Coastguard Worker 		fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY |
457*1208bc7eSAndroid Build Coastguard Worker 			O_CLOEXEC);
458*1208bc7eSAndroid Build Coastguard Worker 	#else
459*1208bc7eSAndroid Build Coastguard Worker 		fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY);
460*1208bc7eSAndroid Build Coastguard Worker 		if (fd != -1) {
461*1208bc7eSAndroid Build Coastguard Worker 			fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
462*1208bc7eSAndroid Build Coastguard Worker 		}
463*1208bc7eSAndroid Build Coastguard Worker 	#endif
464*1208bc7eSAndroid Build Coastguard Worker #elif defined(JEMALLOC_USE_SYSCALL) && defined(SYS_openat)
465*1208bc7eSAndroid Build Coastguard Worker 	#if defined(O_CLOEXEC)
466*1208bc7eSAndroid Build Coastguard Worker 		fd = (int)syscall(SYS_openat,
467*1208bc7eSAndroid Build Coastguard Worker 			AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY | O_CLOEXEC);
468*1208bc7eSAndroid Build Coastguard Worker 	#else
469*1208bc7eSAndroid Build Coastguard Worker 		fd = (int)syscall(SYS_openat,
470*1208bc7eSAndroid Build Coastguard Worker 			AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY);
471*1208bc7eSAndroid Build Coastguard Worker 		if (fd != -1) {
472*1208bc7eSAndroid Build Coastguard Worker 			fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
473*1208bc7eSAndroid Build Coastguard Worker 		}
474*1208bc7eSAndroid Build Coastguard Worker 	#endif
475*1208bc7eSAndroid Build Coastguard Worker #else
476*1208bc7eSAndroid Build Coastguard Worker 	#if defined(O_CLOEXEC)
477*1208bc7eSAndroid Build Coastguard Worker 		fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY | O_CLOEXEC);
478*1208bc7eSAndroid Build Coastguard Worker 	#else
479*1208bc7eSAndroid Build Coastguard Worker 		fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY);
480*1208bc7eSAndroid Build Coastguard Worker 		if (fd != -1) {
481*1208bc7eSAndroid Build Coastguard Worker 			fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
482*1208bc7eSAndroid Build Coastguard Worker 		}
483*1208bc7eSAndroid Build Coastguard Worker 	#endif
484*1208bc7eSAndroid Build Coastguard Worker #endif
485*1208bc7eSAndroid Build Coastguard Worker 
486*1208bc7eSAndroid Build Coastguard Worker 	if (fd == -1) {
487*1208bc7eSAndroid Build Coastguard Worker 		return false; /* Error. */
488*1208bc7eSAndroid Build Coastguard Worker 	}
489*1208bc7eSAndroid Build Coastguard Worker 
490*1208bc7eSAndroid Build Coastguard Worker 	ssize_t nread = malloc_read_fd(fd, &buf, sizeof(buf));
491*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
492*1208bc7eSAndroid Build Coastguard Worker 	syscall(SYS_close, fd);
493*1208bc7eSAndroid Build Coastguard Worker #else
494*1208bc7eSAndroid Build Coastguard Worker 	close(fd);
495*1208bc7eSAndroid Build Coastguard Worker #endif
496*1208bc7eSAndroid Build Coastguard Worker 
497*1208bc7eSAndroid Build Coastguard Worker 	if (nread < 1) {
498*1208bc7eSAndroid Build Coastguard Worker 		return false; /* Error. */
499*1208bc7eSAndroid Build Coastguard Worker 	}
500*1208bc7eSAndroid Build Coastguard Worker 	/*
501*1208bc7eSAndroid Build Coastguard Worker 	 * /proc/sys/vm/overcommit_memory meanings:
502*1208bc7eSAndroid Build Coastguard Worker 	 * 0: Heuristic overcommit.
503*1208bc7eSAndroid Build Coastguard Worker 	 * 1: Always overcommit.
504*1208bc7eSAndroid Build Coastguard Worker 	 * 2: Never overcommit.
505*1208bc7eSAndroid Build Coastguard Worker 	 */
506*1208bc7eSAndroid Build Coastguard Worker 	return (buf[0] == '0' || buf[0] == '1');
507*1208bc7eSAndroid Build Coastguard Worker }
508*1208bc7eSAndroid Build Coastguard Worker #endif
509*1208bc7eSAndroid Build Coastguard Worker 
510*1208bc7eSAndroid Build Coastguard Worker void
pages_set_thp_state(void * ptr,size_t size)511*1208bc7eSAndroid Build Coastguard Worker pages_set_thp_state (void *ptr, size_t size) {
512*1208bc7eSAndroid Build Coastguard Worker 	if (opt_thp == thp_mode_default || opt_thp == init_system_thp_mode) {
513*1208bc7eSAndroid Build Coastguard Worker 		return;
514*1208bc7eSAndroid Build Coastguard Worker 	}
515*1208bc7eSAndroid Build Coastguard Worker 	assert(opt_thp != thp_mode_not_supported &&
516*1208bc7eSAndroid Build Coastguard Worker 	    init_system_thp_mode != thp_mode_not_supported);
517*1208bc7eSAndroid Build Coastguard Worker 
518*1208bc7eSAndroid Build Coastguard Worker 	if (opt_thp == thp_mode_always
519*1208bc7eSAndroid Build Coastguard Worker 	    && init_system_thp_mode != thp_mode_never) {
520*1208bc7eSAndroid Build Coastguard Worker 		assert(init_system_thp_mode == thp_mode_default);
521*1208bc7eSAndroid Build Coastguard Worker 		pages_huge_unaligned(ptr, size);
522*1208bc7eSAndroid Build Coastguard Worker 	} else if (opt_thp == thp_mode_never) {
523*1208bc7eSAndroid Build Coastguard Worker 		assert(init_system_thp_mode == thp_mode_default ||
524*1208bc7eSAndroid Build Coastguard Worker 		    init_system_thp_mode == thp_mode_always);
525*1208bc7eSAndroid Build Coastguard Worker 		pages_nohuge_unaligned(ptr, size);
526*1208bc7eSAndroid Build Coastguard Worker 	}
527*1208bc7eSAndroid Build Coastguard Worker }
528*1208bc7eSAndroid Build Coastguard Worker 
529*1208bc7eSAndroid Build Coastguard Worker static void
init_thp_state(void)530*1208bc7eSAndroid Build Coastguard Worker init_thp_state(void) {
531*1208bc7eSAndroid Build Coastguard Worker 	if (!have_madvise_huge) {
532*1208bc7eSAndroid Build Coastguard Worker 		if (metadata_thp_enabled() && opt_abort) {
533*1208bc7eSAndroid Build Coastguard Worker 			malloc_write("<jemalloc>: no MADV_HUGEPAGE support\n");
534*1208bc7eSAndroid Build Coastguard Worker 			abort();
535*1208bc7eSAndroid Build Coastguard Worker 		}
536*1208bc7eSAndroid Build Coastguard Worker 		goto label_error;
537*1208bc7eSAndroid Build Coastguard Worker 	}
538*1208bc7eSAndroid Build Coastguard Worker 
539*1208bc7eSAndroid Build Coastguard Worker 	static const char sys_state_madvise[] = "always [madvise] never\n";
540*1208bc7eSAndroid Build Coastguard Worker 	static const char sys_state_always[] = "[always] madvise never\n";
541*1208bc7eSAndroid Build Coastguard Worker 	static const char sys_state_never[] = "always madvise [never]\n";
542*1208bc7eSAndroid Build Coastguard Worker 	char buf[sizeof(sys_state_madvise)];
543*1208bc7eSAndroid Build Coastguard Worker 
544*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
545*1208bc7eSAndroid Build Coastguard Worker 	int fd = (int)syscall(SYS_open,
546*1208bc7eSAndroid Build Coastguard Worker 	    "/sys/kernel/mm/transparent_hugepage/enabled", O_RDONLY);
547*1208bc7eSAndroid Build Coastguard Worker #else
548*1208bc7eSAndroid Build Coastguard Worker 	int fd = open("/sys/kernel/mm/transparent_hugepage/enabled", O_RDONLY);
549*1208bc7eSAndroid Build Coastguard Worker #endif
550*1208bc7eSAndroid Build Coastguard Worker 	if (fd == -1) {
551*1208bc7eSAndroid Build Coastguard Worker 		goto label_error;
552*1208bc7eSAndroid Build Coastguard Worker 	}
553*1208bc7eSAndroid Build Coastguard Worker 
554*1208bc7eSAndroid Build Coastguard Worker 	ssize_t nread = malloc_read_fd(fd, &buf, sizeof(buf));
555*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
556*1208bc7eSAndroid Build Coastguard Worker 	syscall(SYS_close, fd);
557*1208bc7eSAndroid Build Coastguard Worker #else
558*1208bc7eSAndroid Build Coastguard Worker 	close(fd);
559*1208bc7eSAndroid Build Coastguard Worker #endif
560*1208bc7eSAndroid Build Coastguard Worker 
561*1208bc7eSAndroid Build Coastguard Worker 	if (strncmp(buf, sys_state_madvise, (size_t)nread) == 0) {
562*1208bc7eSAndroid Build Coastguard Worker 		init_system_thp_mode = thp_mode_default;
563*1208bc7eSAndroid Build Coastguard Worker 	} else if (strncmp(buf, sys_state_always, (size_t)nread) == 0) {
564*1208bc7eSAndroid Build Coastguard Worker 		init_system_thp_mode = thp_mode_always;
565*1208bc7eSAndroid Build Coastguard Worker 	} else if (strncmp(buf, sys_state_never, (size_t)nread) == 0) {
566*1208bc7eSAndroid Build Coastguard Worker 		init_system_thp_mode = thp_mode_never;
567*1208bc7eSAndroid Build Coastguard Worker 	} else {
568*1208bc7eSAndroid Build Coastguard Worker 		goto label_error;
569*1208bc7eSAndroid Build Coastguard Worker 	}
570*1208bc7eSAndroid Build Coastguard Worker 	return;
571*1208bc7eSAndroid Build Coastguard Worker label_error:
572*1208bc7eSAndroid Build Coastguard Worker 	opt_thp = init_system_thp_mode = thp_mode_not_supported;
573*1208bc7eSAndroid Build Coastguard Worker }
574*1208bc7eSAndroid Build Coastguard Worker 
575*1208bc7eSAndroid Build Coastguard Worker bool
pages_boot(void)576*1208bc7eSAndroid Build Coastguard Worker pages_boot(void) {
577*1208bc7eSAndroid Build Coastguard Worker 	os_page = os_page_detect();
578*1208bc7eSAndroid Build Coastguard Worker 	if (os_page > PAGE) {
579*1208bc7eSAndroid Build Coastguard Worker 		malloc_write("<jemalloc>: Unsupported system page size\n");
580*1208bc7eSAndroid Build Coastguard Worker 		if (opt_abort) {
581*1208bc7eSAndroid Build Coastguard Worker 			abort();
582*1208bc7eSAndroid Build Coastguard Worker 		}
583*1208bc7eSAndroid Build Coastguard Worker 		return true;
584*1208bc7eSAndroid Build Coastguard Worker 	}
585*1208bc7eSAndroid Build Coastguard Worker 
586*1208bc7eSAndroid Build Coastguard Worker #ifndef _WIN32
587*1208bc7eSAndroid Build Coastguard Worker 	mmap_flags = MAP_PRIVATE | MAP_ANON;
588*1208bc7eSAndroid Build Coastguard Worker #endif
589*1208bc7eSAndroid Build Coastguard Worker 
590*1208bc7eSAndroid Build Coastguard Worker #if defined(__ANDROID__)
591*1208bc7eSAndroid Build Coastguard Worker   /* Android always supports overcommits. */
592*1208bc7eSAndroid Build Coastguard Worker   os_overcommits = true;
593*1208bc7eSAndroid Build Coastguard Worker #else  /* __ANDROID__ */
594*1208bc7eSAndroid Build Coastguard Worker 
595*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
596*1208bc7eSAndroid Build Coastguard Worker 	os_overcommits = os_overcommits_sysctl();
597*1208bc7eSAndroid Build Coastguard Worker #elif defined(JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY)
598*1208bc7eSAndroid Build Coastguard Worker 	os_overcommits = os_overcommits_proc();
599*1208bc7eSAndroid Build Coastguard Worker #  ifdef MAP_NORESERVE
600*1208bc7eSAndroid Build Coastguard Worker 	if (os_overcommits) {
601*1208bc7eSAndroid Build Coastguard Worker 		mmap_flags |= MAP_NORESERVE;
602*1208bc7eSAndroid Build Coastguard Worker 	}
603*1208bc7eSAndroid Build Coastguard Worker #  endif
604*1208bc7eSAndroid Build Coastguard Worker #else
605*1208bc7eSAndroid Build Coastguard Worker 	os_overcommits = false;
606*1208bc7eSAndroid Build Coastguard Worker #endif
607*1208bc7eSAndroid Build Coastguard Worker 
608*1208bc7eSAndroid Build Coastguard Worker #endif  /* __ANDROID__ */
609*1208bc7eSAndroid Build Coastguard Worker 
610*1208bc7eSAndroid Build Coastguard Worker 	init_thp_state();
611*1208bc7eSAndroid Build Coastguard Worker 
612*1208bc7eSAndroid Build Coastguard Worker 	/* Detect lazy purge runtime support. */
613*1208bc7eSAndroid Build Coastguard Worker 	if (pages_can_purge_lazy) {
614*1208bc7eSAndroid Build Coastguard Worker 		bool committed = false;
615*1208bc7eSAndroid Build Coastguard Worker 		void *madv_free_page = os_pages_map(NULL, PAGE, PAGE, &committed);
616*1208bc7eSAndroid Build Coastguard Worker 		if (madv_free_page == NULL) {
617*1208bc7eSAndroid Build Coastguard Worker 			return true;
618*1208bc7eSAndroid Build Coastguard Worker 		}
619*1208bc7eSAndroid Build Coastguard Worker 		assert(pages_can_purge_lazy_runtime);
620*1208bc7eSAndroid Build Coastguard Worker 		if (pages_purge_lazy(madv_free_page, PAGE)) {
621*1208bc7eSAndroid Build Coastguard Worker 			pages_can_purge_lazy_runtime = false;
622*1208bc7eSAndroid Build Coastguard Worker 		}
623*1208bc7eSAndroid Build Coastguard Worker 		os_pages_unmap(madv_free_page, PAGE);
624*1208bc7eSAndroid Build Coastguard Worker 	}
625*1208bc7eSAndroid Build Coastguard Worker 
626*1208bc7eSAndroid Build Coastguard Worker 	return false;
627*1208bc7eSAndroid Build Coastguard Worker }
628