blob: a4263d597406e81b509fb4a24ce87692050d5192 [file] [log] [blame]
Carl Shapiro69759ea2011-07-21 18:13:35 -07001/* Copyright 2006 The Android Open Source Project */
2
3/* A wrapper file for dlmalloc.c that compiles in the
4 * mspace_*() functions, which provide an interface for
5 * creating multiple heaps.
6 */
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10#include <unistd.h>
11#include <stdint.h>
12#include <sys/ioctl.h>
13
Carl Shapiro69759ea2011-07-21 18:13:35 -070014/* It's a pain getting the mallinfo stuff to work
15 * with Linux, OSX, and klibc, so just turn it off
16 * for now.
17 * TODO: make mallinfo work
18 */
19#define NO_MALLINFO 1
20
21/* Allow setting the maximum heap footprint.
22 */
23#define USE_MAX_ALLOWED_FOOTPRINT 1
24
25/* Don't try to trim memory.
26 * TODO: support this.
27 */
28#define MORECORE_CANNOT_TRIM 1
29
30/* Use mmap()d anonymous memory to guarantee
31 * that an mspace is contiguous.
32 *
33 * create_mspace() won't work right if this is
34 * defined, so hide the definition of it and
35 * break any users at build time.
36 */
37#define USE_CONTIGUOUS_MSPACES 1
38#if USE_CONTIGUOUS_MSPACES
39/* This combination of settings forces sys_alloc()
40 * to always use MORECORE(). It won't expect the
41 * results to be contiguous, but we'll guarantee
42 * that they are.
43 */
44#define HAVE_MMAP 0
45#define HAVE_MORECORE 1
46#define MORECORE_CONTIGUOUS 0
47/* m is always the appropriate local when MORECORE() is called. */
48#define MORECORE(S) contiguous_mspace_morecore(m, S)
49#define create_mspace HIDDEN_create_mspace_HIDDEN
50#define destroy_mspace HIDDEN_destroy_mspace_HIDDEN
51typedef struct malloc_state *mstate0;
52static void *contiguous_mspace_morecore(mstate0 m, ssize_t nb);
53#endif /* USE_CONTIGUOUS_MSPACES */
54
55#define MSPACES 1
56#define ONLY_MSPACES 1
57#include "dlmalloc.c"
58
59#ifndef PAGESIZE
60#define PAGESIZE mparams.page_size
61#endif
62
63#define ALIGN_UP(p, alignment) \
64 (((uintptr_t)(p) + (alignment)-1) & ~((alignment)-1))
65
66/* A direct copy of dlmalloc_usable_size(),
67 * which isn't compiled in when ONLY_MSPACES is set.
68 * The mspace parameter isn't actually necessary,
69 * but we include it to be consistent with the
70 * rest of the mspace_*() functions.
71 */
72size_t mspace_usable_size(mspace _unused, const void* mem) {
73 if (mem != 0) {
74 const mchunkptr p = mem2chunk(mem);
75 if (cinuse(p))
76 return chunksize(p) - overhead_for(p);
77 }
78 return 0;
79}
80
81#if USE_CONTIGUOUS_MSPACES
82#include <sys/mman.h>
83#include <limits.h>
84
85#define CONTIG_STATE_MAGIC 0xf00dd00d
86struct mspace_contig_state {
87 unsigned int magic;
88 char *brk;
89 char *top;
90 mspace m;
91};
92
93static void *contiguous_mspace_morecore(mstate m, ssize_t nb) {
94 struct mspace_contig_state *cs;
95 char *oldbrk;
96 const unsigned int pagesize = PAGESIZE;
97
98 cs = (struct mspace_contig_state *)((uintptr_t)m & ~(pagesize-1));
99 assert(cs->magic == CONTIG_STATE_MAGIC);
100 assert(cs->m == m);
101assert(nb >= 0); //xxx deal with the trim case
102
103 oldbrk = cs->brk;
104 if (nb > 0) {
105 /* Break to the first page boundary that satisfies the request.
106 */
107 char *newbrk = (char *)ALIGN_UP(oldbrk + nb, pagesize);
108 if (newbrk > cs->top)
109 return CMFAIL;
110
111 /* Update the protection on the underlying memory.
112 * Pages we've given to dlmalloc are read/write, and
113 * pages we haven't are not accessable (read or write
114 * will cause a seg fault).
115 */
116 if (mprotect(cs, newbrk - (char *)cs, PROT_READ | PROT_WRITE) < 0)
117 return CMFAIL;
118 if (newbrk != cs->top) {
119 if (mprotect(newbrk, cs->top - newbrk, PROT_NONE) < 0)
120 return CMFAIL;
121 }
122
123 cs->brk = newbrk;
124
125 /* Make sure that dlmalloc will merge this block with the
126 * initial block that was passed to create_mspace_with_base().
127 * We don't care about extern vs. non-extern, so just clear it.
128 */
129 m->seg.sflags &= ~EXTERN_BIT;
130 }
131
132 return oldbrk;
133}
134
135mspace create_contiguous_mspace_with_base(size_t starting_capacity,
136 size_t max_capacity, int locked, void *base) {
137 struct mspace_contig_state *cs;
138 unsigned int pagesize;
139 mstate m;
140
141 init_mparams();
142 pagesize = PAGESIZE;
143 assert(starting_capacity <= max_capacity);
144 assert(((uintptr_t)base & (pagesize-1)) == 0);
145 assert(((uintptr_t)max_capacity & (pagesize-1)) == 0);
146 starting_capacity = (size_t)ALIGN_UP(starting_capacity, pagesize);
147
148 /* Make the first page read/write. dlmalloc needs to use that page.
149 */
150 if (mprotect(base, starting_capacity, PROT_READ | PROT_WRITE) < 0) {
151 goto error;
152 }
153
154 /* Create the mspace, pointing to the memory given.
155 */
156 m = create_mspace_with_base((char *)base + sizeof(*cs), starting_capacity,
157 locked);
158 if (m == (mspace)0) {
159 goto error;
160 }
161 /* Make sure that m is in the same page as base.
162 */
163 assert(((uintptr_t)m & (uintptr_t)~(pagesize-1)) == (uintptr_t)base);
164 /* Use some space for the information that our MORECORE needs.
165 */
166 cs = (struct mspace_contig_state *)base;
167
168 /* Find out exactly how much of the memory the mspace
169 * is using.
170 */
171 cs->brk = m->seg.base + m->seg.size;
172 cs->top = (char *)base + max_capacity;
173
174 assert((char *)base <= cs->brk);
175 assert(cs->brk <= cs->top);
176 /* Prevent access to the memory we haven't handed out yet.
177 */
178 if (cs->brk != cs->top) {
179 /* mprotect() requires page-aligned arguments, but it's possible
180 * for cs->brk not to be page-aligned at this point.
181 */
182 char *prot_brk = (char *)ALIGN_UP(cs->brk, pagesize);
183 if ((mprotect(base, prot_brk - (char *)base, PROT_READ | PROT_WRITE) < 0) ||
184 (mprotect(prot_brk, cs->top - prot_brk, PROT_NONE) < 0)) {
185 goto error;
186 }
187 }
188
189 cs->m = m;
190 cs->magic = CONTIG_STATE_MAGIC;
191
192 return (mspace)m;
193
194error:
195 return (mspace)0;
196}
197
Carl Shapiro69759ea2011-07-21 18:13:35 -0700198size_t destroy_contiguous_mspace(mspace msp) {
199 mstate ms = (mstate)msp;
200
201 if (ok_magic(ms)) {
202 struct mspace_contig_state *cs;
203 size_t length;
204 const unsigned int pagesize = PAGESIZE;
205
206 cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
207 assert(cs->magic == CONTIG_STATE_MAGIC);
208 assert(cs->m == ms);
209
210 length = cs->top - (char *)cs;
211 if (munmap((char *)cs, length) != 0)
212 return length;
213 }
214 else {
215 USAGE_ERROR_ACTION(ms, ms);
216 }
217 return 0;
218}
219
220void *contiguous_mspace_sbrk0(mspace msp) {
221 struct mspace_contig_state *cs;
222 mstate ms;
223 const unsigned int pagesize = PAGESIZE;
224
225 ms = (mstate)msp;
226 cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
227 assert(cs->magic == CONTIG_STATE_MAGIC);
228 assert(cs->m == ms);
229 return cs->brk;
230}
231#endif /* USE_CONTIGUOUS_MSPACES */