1#define	JEMALLOC_PAGES_C_
2#include "jemalloc/internal/jemalloc_internal.h"
3
4/******************************************************************************/
5/* Defines/includes needed for special android code. */
6
7#if defined(__ANDROID__)
8#include <sys/prctl.h>
9
10/* Definitions of prctl arguments to set a vma name in Android kernels. */
11#define ANDROID_PR_SET_VMA            0x53564d41
12#define ANDROID_PR_SET_VMA_ANON_NAME  0
13#endif
14
15/******************************************************************************/
16
17void *
18pages_map(void *addr, size_t size)
19{
20	void *ret;
21
22	assert(size != 0);
23
24#ifdef _WIN32
25	/*
26	 * If VirtualAlloc can't allocate at the given address when one is
27	 * given, it fails and returns NULL.
28	 */
29	ret = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE,
30	    PAGE_READWRITE);
31#else
32	/*
33	 * We don't use MAP_FIXED here, because it can cause the *replacement*
34	 * of existing mappings, and we only want to create new mappings.
35	 */
36	ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
37	    -1, 0);
38	assert(ret != NULL);
39
40	if (ret == MAP_FAILED)
41		ret = NULL;
42	else if (addr != NULL && ret != addr) {
43		/*
44		 * We succeeded in mapping memory, but not in the right place.
45		 */
46		pages_unmap(ret, size);
47		ret = NULL;
48	}
49#endif
50#if defined(__ANDROID__)
51	if (ret != NULL) {
52		/* Name this memory as being used by libc */
53		prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, ret,
54		    size, "libc_malloc");
55	}
56#endif
57	assert(ret == NULL || (addr == NULL && ret != addr)
58	    || (addr != NULL && ret == addr));
59	return (ret);
60}
61
62void
63pages_unmap(void *addr, size_t size)
64{
65
66#ifdef _WIN32
67	if (VirtualFree(addr, 0, MEM_RELEASE) == 0)
68#else
69	if (munmap(addr, size) == -1)
70#endif
71	{
72		char buf[BUFERROR_BUF];
73
74		buferror(get_errno(), buf, sizeof(buf));
75		malloc_printf("<jemalloc>: Error in "
76#ifdef _WIN32
77		              "VirtualFree"
78#else
79		              "munmap"
80#endif
81		              "(): %s\n", buf);
82		if (opt_abort)
83			abort();
84	}
85}
86
87void *
88pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size)
89{
90	void *ret = (void *)((uintptr_t)addr + leadsize);
91
92	assert(alloc_size >= leadsize + size);
93#ifdef _WIN32
94	{
95		void *new_addr;
96
97		pages_unmap(addr, alloc_size);
98		new_addr = pages_map(ret, size);
99		if (new_addr == ret)
100			return (ret);
101		if (new_addr)
102			pages_unmap(new_addr, size);
103		return (NULL);
104	}
105#else
106	{
107		size_t trailsize = alloc_size - leadsize - size;
108
109		if (leadsize != 0)
110			pages_unmap(addr, leadsize);
111		if (trailsize != 0)
112			pages_unmap((void *)((uintptr_t)ret + size), trailsize);
113		return (ret);
114	}
115#endif
116}
117
118static bool
119pages_commit_impl(void *addr, size_t size, bool commit)
120{
121
122#ifndef _WIN32
123	/*
124	 * The following decommit/commit implementation is functional, but
125	 * always disabled because it doesn't add value beyong improved
126	 * debugging (at the cost of extra system calls) on systems that
127	 * overcommit.
128	 */
129	if (false) {
130		int prot = commit ? (PROT_READ | PROT_WRITE) : PROT_NONE;
131		void *result = mmap(addr, size, prot, MAP_PRIVATE | MAP_ANON |
132		    MAP_FIXED, -1, 0);
133		if (result == MAP_FAILED)
134			return (true);
135		if (result != addr) {
136			/*
137			 * We succeeded in mapping memory, but not in the right
138			 * place.
139			 */
140			pages_unmap(result, size);
141			return (true);
142		}
143		return (false);
144	}
145#endif
146	return (true);
147}
148
149bool
150pages_commit(void *addr, size_t size)
151{
152
153	return (pages_commit_impl(addr, size, true));
154}
155
156bool
157pages_decommit(void *addr, size_t size)
158{
159
160	return (pages_commit_impl(addr, size, false));
161}
162
163bool
164pages_purge(void *addr, size_t size)
165{
166	bool unzeroed;
167
168#ifdef _WIN32
169	VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE);
170	unzeroed = true;
171#elif defined(JEMALLOC_HAVE_MADVISE)
172#  ifdef JEMALLOC_PURGE_MADVISE_DONTNEED
173#    define JEMALLOC_MADV_PURGE MADV_DONTNEED
174#    define JEMALLOC_MADV_ZEROS true
175#  elif defined(JEMALLOC_PURGE_MADVISE_FREE)
176#    define JEMALLOC_MADV_PURGE MADV_FREE
177#    define JEMALLOC_MADV_ZEROS false
178#  else
179#    error "No madvise(2) flag defined for purging unused dirty pages."
180#  endif
181	int err = madvise(addr, size, JEMALLOC_MADV_PURGE);
182	unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0);
183#  undef JEMALLOC_MADV_PURGE
184#  undef JEMALLOC_MADV_ZEROS
185#else
186	/* Last resort no-op. */
187	unzeroed = true;
188#endif
189	return (unzeroed);
190}
191
192