• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* 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 
14 #include <cutils/ashmem.h>
15 
16 /* It's a pain getting the mallinfo stuff to work
17  * with Linux, OSX, and klibc, so just turn it off
18  * for now.
19  * TODO: make mallinfo work
20  */
21 #define NO_MALLINFO 1
22 
23 /* Allow setting the maximum heap footprint.
24  */
25 #define USE_MAX_ALLOWED_FOOTPRINT 1
26 
27 /* Don't try to trim memory.
28  * TODO: support this.
29  */
30 #define MORECORE_CANNOT_TRIM 1
31 
32 /* Use mmap()d anonymous memory to guarantee
33  * that an mspace is contiguous.
34  *
35  * create_mspace() won't work right if this is
36  * defined, so hide the definition of it and
37  * break any users at build time.
38  */
39 #define USE_CONTIGUOUS_MSPACES 1
40 #if USE_CONTIGUOUS_MSPACES
41 /* This combination of settings forces sys_alloc()
42  * to always use MORECORE().  It won't expect the
43  * results to be contiguous, but we'll guarantee
44  * that they are.
45  */
46 #define HAVE_MMAP 0
47 #define HAVE_MORECORE 1
48 #define MORECORE_CONTIGUOUS 0
49 /* m is always the appropriate local when MORECORE() is called. */
50 #define MORECORE(S) contiguous_mspace_morecore(m, S)
51 #define create_mspace   HIDDEN_create_mspace_HIDDEN
52 #define destroy_mspace   HIDDEN_destroy_mspace_HIDDEN
53 typedef struct malloc_state *mstate0;
54 static void *contiguous_mspace_morecore(mstate0 m, ssize_t nb);
55 #endif
56 
57 #define MSPACES 1
58 #define ONLY_MSPACES 1
59 #include "../../../bionic/libc/bionic/dlmalloc.c"
60 
61 #ifndef PAGESIZE
62 #define PAGESIZE  mparams.page_size
63 #endif
64 
65 #define ALIGN_UP(p, alignment) \
66     (((uintptr_t)(p) + (alignment)-1) & ~((alignment)-1))
67 
68 /* A direct copy of dlmalloc_usable_size(),
69  * which isn't compiled in when ONLY_MSPACES is set.
70  * The mspace parameter isn't actually necessary,
71  * but we include it to be consistent with the
72  * rest of the mspace_*() functions.
73  */
mspace_usable_size(mspace _unused,const void * mem)74 size_t mspace_usable_size(mspace _unused, const void* mem) {
75   if (mem != 0) {
76     const mchunkptr p = mem2chunk(mem);
77     if (cinuse(p))
78       return chunksize(p) - overhead_for(p);
79   }
80   return 0;
81 }
82 
83 #if USE_CONTIGUOUS_MSPACES
84 #include <sys/mman.h>
85 #include <limits.h>
86 
87 #define CONTIG_STATE_MAGIC  0xf00dd00d
88 struct mspace_contig_state {
89   unsigned int magic;
90   char *brk;
91   char *top;
92   mspace m;
93 };
94 
contiguous_mspace_morecore(mstate m,ssize_t nb)95 static void *contiguous_mspace_morecore(mstate m, ssize_t nb) {
96   struct mspace_contig_state *cs;
97   char *oldbrk;
98   const unsigned int pagesize = PAGESIZE;
99 
100   cs = (struct mspace_contig_state *)((uintptr_t)m & ~(pagesize-1));
101   assert(cs->magic == CONTIG_STATE_MAGIC);
102   assert(cs->m == m);
103 assert(nb >= 0);  //xxx deal with the trim case
104 
105   oldbrk = cs->brk;
106   if (nb > 0) {
107     /* Break to the first page boundary that satisfies the request.
108      */
109     char *newbrk = (char *)ALIGN_UP(oldbrk + nb, pagesize);
110     if (newbrk > cs->top)
111       return CMFAIL;
112 
113     /* Update the protection on the underlying memory.
114      * Pages we've given to dlmalloc are read/write, and
115      * pages we haven't are not accessable (read or write
116      * will cause a seg fault).
117      */
118     if (mprotect(cs, newbrk - (char *)cs, PROT_READ | PROT_WRITE) < 0)
119       return CMFAIL;
120     if (newbrk != cs->top) {
121       if (mprotect(newbrk, cs->top - newbrk, PROT_NONE) < 0)
122         return CMFAIL;
123     }
124 
125     cs->brk = newbrk;
126 
127     /* Make sure that dlmalloc will merge this block with the
128      * initial block that was passed to create_mspace_with_base().
129      * We don't care about extern vs. non-extern, so just clear it.
130      */
131     m->seg.sflags &= ~EXTERN_BIT;
132   }
133 
134   return oldbrk;
135 }
136 
create_contiguous_mspace_with_base(size_t starting_capacity,size_t max_capacity,int locked,void * base)137 mspace create_contiguous_mspace_with_base(size_t starting_capacity,
138     size_t max_capacity, int locked, void *base) {
139   struct mspace_contig_state *cs;
140   unsigned int pagesize;
141   mstate m;
142 
143   init_mparams();
144   pagesize = PAGESIZE;
145   assert(starting_capacity <= max_capacity);
146   assert(((uintptr_t)base & (pagesize-1)) == 0);
147   assert(((uintptr_t)max_capacity & (pagesize-1)) == 0);
148   starting_capacity = (size_t)ALIGN_UP(starting_capacity, pagesize);
149 
150   /* Make the first page read/write. dlmalloc needs to use that page.
151    */
152   if (mprotect(base, starting_capacity, PROT_READ | PROT_WRITE) < 0) {
153     goto error;
154   }
155 
156   /* Create the mspace, pointing to the memory given.
157    */
158   m = create_mspace_with_base((char *)base + sizeof(*cs), starting_capacity,
159                               locked);
160   if (m == (mspace)0) {
161     goto error;
162   }
163   /* Make sure that m is in the same page as base.
164    */
165   assert(((uintptr_t)m & (uintptr_t)~(pagesize-1)) == (uintptr_t)base);
166   /* Use some space for the information that our MORECORE needs.
167    */
168   cs = (struct mspace_contig_state *)base;
169 
170   /* Find out exactly how much of the memory the mspace
171    * is using.
172    */
173   cs->brk = m->seg.base + m->seg.size;
174   cs->top = (char *)base + max_capacity;
175 
176   assert((char *)base <= cs->brk);
177   assert(cs->brk <= cs->top);
178   /* Prevent access to the memory we haven't handed out yet.
179    */
180   if (cs->brk != cs->top) {
181     /* mprotect() requires page-aligned arguments, but it's possible
182      * for cs->brk not to be page-aligned at this point.
183      */
184     char *prot_brk = (char *)ALIGN_UP(cs->brk, pagesize);
185     if ((mprotect(base, prot_brk - (char *)base, PROT_READ | PROT_WRITE) < 0) ||
186         (mprotect(prot_brk, cs->top - prot_brk, PROT_NONE) < 0)) {
187       goto error;
188     }
189   }
190 
191   cs->m = m;
192   cs->magic = CONTIG_STATE_MAGIC;
193 
194   return (mspace)m;
195 
196 error:
197   return (mspace)0;
198 }
199 
200 
create_contiguous_mspace_with_name(size_t starting_capacity,size_t max_capacity,int locked,char const * name)201 mspace create_contiguous_mspace_with_name(size_t starting_capacity,
202     size_t max_capacity, int locked, char const *name) {
203   int fd, ret;
204   char buf[ASHMEM_NAME_LEN] = "mspace";
205   void *base;
206   unsigned int pagesize;
207   mstate m;
208 
209   if (starting_capacity > max_capacity)
210     return (mspace)0;
211 
212   init_mparams();
213   pagesize = PAGESIZE;
214 
215   /* Create the anonymous memory that will back the mspace.
216    * This reserves all of the virtual address space we could
217    * ever need.  Physical pages will be mapped as the memory
218    * is touched.
219    *
220    * Align max_capacity to a whole page.
221    */
222   max_capacity = (size_t)ALIGN_UP(max_capacity, pagesize);
223 
224   if (name)
225     snprintf(buf, sizeof(buf), "mspace/%s", name);
226   fd = ashmem_create_region(buf, max_capacity);
227   if (fd < 0)
228     return (mspace)0;
229 
230   base = mmap(NULL, max_capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
231   close(fd);
232   if (base == MAP_FAILED)
233     return (mspace)0;
234 
235   /* Make sure that base is at the beginning of a page.
236    */
237   assert(((uintptr_t)base & (pagesize-1)) == 0);
238 
239   m = create_contiguous_mspace_with_base(starting_capacity, max_capacity,
240                                          locked, base);
241   if (m == 0) {
242     munmap(base, max_capacity);
243   }
244   return m;
245 }
246 
create_contiguous_mspace(size_t starting_capacity,size_t max_capacity,int locked)247 mspace create_contiguous_mspace(size_t starting_capacity,
248     size_t max_capacity, int locked) {
249   return create_contiguous_mspace_with_name(starting_capacity,
250       max_capacity, locked, NULL);
251 }
252 
destroy_contiguous_mspace(mspace msp)253 size_t destroy_contiguous_mspace(mspace msp) {
254   mstate ms = (mstate)msp;
255 
256   if (ok_magic(ms)) {
257     struct mspace_contig_state *cs;
258     size_t length;
259     const unsigned int pagesize = PAGESIZE;
260 
261     cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
262     assert(cs->magic == CONTIG_STATE_MAGIC);
263     assert(cs->m == ms);
264 
265     length = cs->top - (char *)cs;
266     if (munmap((char *)cs, length) != 0)
267       return length;
268   }
269   else {
270     USAGE_ERROR_ACTION(ms, ms);
271   }
272   return 0;
273 }
274 
contiguous_mspace_sbrk0(mspace msp)275 void *contiguous_mspace_sbrk0(mspace msp) {
276     struct mspace_contig_state *cs;
277     mstate ms;
278     const unsigned int pagesize = PAGESIZE;
279 
280     ms = (mstate)msp;
281     cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
282     assert(cs->magic == CONTIG_STATE_MAGIC);
283     assert(cs->m == ms);
284     return cs->brk;
285 }
286 #endif
287