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