import mallocng
[musl] / src / malloc / mallocng / malloc.c
1 #include <stdlib.h>
2 #include <stdint.h>
3 #include <limits.h>
4 #include <string.h>
5 #include <sys/mman.h>
6 #include <errno.h>
7
8 #include "meta.h"
9
10 LOCK_OBJ_DEF;
11
12 const uint16_t size_classes[] = {
13         1, 2, 3, 4, 5, 6, 7, 8,
14         9, 10, 12, 15,
15         18, 20, 25, 31,
16         36, 42, 50, 63,
17         72, 84, 102, 127,
18         146, 170, 204, 255,
19         292, 340, 409, 511,
20         584, 682, 818, 1023,
21         1169, 1364, 1637, 2047,
22         2340, 2730, 3276, 4095,
23         4680, 5460, 6552, 8191,
24 };
25
26 static const uint8_t small_cnt_tab[][3] = {
27         { 30, 30, 30 },
28         { 31, 15, 15 },
29         { 20, 10, 10 },
30         { 31, 15, 7 },
31         { 25, 12, 6 },
32         { 21, 10, 5 },
33         { 18, 8, 4 },
34         { 31, 15, 7 },
35         { 28, 14, 6 },
36 };
37
38 static const uint8_t med_cnt_tab[4] = { 28, 24, 20, 32 };
39
40 struct malloc_context ctx = { 0 };
41
42 struct meta *alloc_meta(void)
43 {
44         struct meta *m;
45         unsigned char *p;
46         if (!ctx.init_done) {
47 #ifndef PAGESIZE
48                 ctx.pagesize = get_page_size();
49 #endif
50                 ctx.secret = get_random_secret();
51                 ctx.init_done = 1;
52         }
53         size_t pagesize = PGSZ;
54         if (pagesize < 4096) pagesize = 4096;
55         if ((m = dequeue_head(&ctx.free_meta_head))) return m;
56         if (!ctx.avail_meta_count) {
57                 int need_unprotect = 1;
58                 if (!ctx.avail_meta_area_count && ctx.brk!=-1) {
59                         uintptr_t new = ctx.brk + pagesize;
60                         int need_guard = 0;
61                         if (!ctx.brk) {
62                                 need_guard = 1;
63                                 ctx.brk = brk(0);
64                                 // some ancient kernels returned _ebss
65                                 // instead of next page as initial brk.
66                                 ctx.brk += -ctx.brk & (pagesize-1);
67                                 new = ctx.brk + 2*pagesize;
68                         }
69                         if (brk(new) != new) {
70                                 ctx.brk = -1;
71                         } else {
72                                 if (need_guard) mmap((void *)ctx.brk, pagesize,
73                                         PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
74                                 ctx.brk = new;
75                                 ctx.avail_meta_areas = (void *)(new - pagesize);
76                                 ctx.avail_meta_area_count = pagesize>>12;
77                                 need_unprotect = 0;
78                         }
79                 }
80                 if (!ctx.avail_meta_area_count) {
81                         size_t n = 2UL << ctx.meta_alloc_shift;
82                         p = mmap(0, n*pagesize, PROT_NONE,
83                                 MAP_PRIVATE|MAP_ANON, -1, 0);
84                         if (p==MAP_FAILED) return 0;
85                         ctx.avail_meta_areas = p + pagesize;
86                         ctx.avail_meta_area_count = (n-1)*(pagesize>>12);
87                         ctx.meta_alloc_shift++;
88                 }
89                 p = ctx.avail_meta_areas;
90                 if ((uintptr_t)p & (pagesize-1)) need_unprotect = 0;
91                 if (need_unprotect)
92                         if (mprotect(p, pagesize, PROT_READ|PROT_WRITE)
93                             && errno != ENOSYS)
94                                 return 0;
95                 ctx.avail_meta_area_count--;
96                 ctx.avail_meta_areas = p + 4096;
97                 if (ctx.meta_area_tail) {
98                         ctx.meta_area_tail->next = (void *)p;
99                 } else {
100                         ctx.meta_area_head = (void *)p;
101                 }
102                 ctx.meta_area_tail = (void *)p;
103                 ctx.meta_area_tail->check = ctx.secret;
104                 ctx.avail_meta_count = ctx.meta_area_tail->nslots
105                         = (4096-sizeof(struct meta_area))/sizeof *m;
106                 ctx.avail_meta = ctx.meta_area_tail->slots;
107         }
108         ctx.avail_meta_count--;
109         m = ctx.avail_meta++;
110         m->prev = m->next = 0;
111         return m;
112 }
113
114 static uint32_t try_avail(struct meta **pm)
115 {
116         struct meta *m = *pm;
117         uint32_t first;
118         if (!m) return 0;
119         uint32_t mask = m->avail_mask;
120         if (!mask) {
121                 if (!m) return 0;
122                 if (!m->freed_mask) {
123                         dequeue(pm, m);
124                         m = *pm;
125                         if (!m) return 0;
126                 } else {
127                         m = m->next;
128                         *pm = m;
129                 }
130
131                 mask = m->freed_mask;
132
133                 // skip fully-free group unless it's the only one
134                 // or it's a permanently non-freeable group
135                 if (mask == (2u<<m->last_idx)-1 && m->freeable) {
136                         m = m->next;
137                         *pm = m;
138                         mask = m->freed_mask;
139                 }
140
141                 // activate more slots in a not-fully-active group
142                 // if needed, but only as a last resort. prefer using
143                 // any other group with free slots. this avoids
144                 // touching & dirtying as-yet-unused pages.
145                 if (!(mask & ((2u<<m->mem->active_idx)-1))) {
146                         if (m->next != m) {
147                                 m = m->next;
148                                 *pm = m;
149                         } else {
150                                 int cnt = m->mem->active_idx + 2;
151                                 int size = size_classes[m->sizeclass]*UNIT;
152                                 int span = UNIT + size*cnt;
153                                 // activate up to next 4k boundary
154                                 while ((span^(span+size-1)) < 4096) {
155                                         cnt++;
156                                         span += size;
157                                 }
158                                 if (cnt > m->last_idx+1)
159                                         cnt = m->last_idx+1;
160                                 m->mem->active_idx = cnt-1;
161                         }
162                 }
163                 mask = activate_group(m);
164                 assert(mask);
165                 decay_bounces(m->sizeclass);
166         }
167         first = mask&-mask;
168         m->avail_mask = mask-first;
169         return first;
170 }
171
172 static int alloc_slot(int, size_t);
173
174 static struct meta *alloc_group(int sc, size_t req)
175 {
176         size_t size = UNIT*size_classes[sc];
177         int i = 0, cnt;
178         unsigned char *p;
179         struct meta *m = alloc_meta();
180         if (!m) return 0;
181         size_t usage = ctx.usage_by_class[sc];
182         size_t pagesize = PGSZ;
183         int active_idx;
184         if (sc < 9) {
185                 while (i<2 && 4*small_cnt_tab[sc][i] > usage)
186                         i++;
187                 cnt = small_cnt_tab[sc][i];
188         } else {
189                 // lookup max number of slots fitting in power-of-two size
190                 // from a table, along with number of factors of two we
191                 // can divide out without a remainder or reaching 1.
192                 cnt = med_cnt_tab[sc&3];
193
194                 // reduce cnt to avoid excessive eagar allocation.
195                 while (!(cnt&1) && 4*cnt > usage)
196                         cnt >>= 1;
197
198                 // data structures don't support groups whose slot offsets
199                 // in units don't fit in 16 bits.
200                 while (size*cnt >= 65536*UNIT)
201                         cnt >>= 1;
202         }
203
204         // If we selected a count of 1 above but it's not sufficient to use
205         // mmap, increase to 2. Then it might be; if not it will nest.
206         if (cnt==1 && size*cnt+UNIT <= pagesize/2) cnt = 2;
207
208         // All choices of size*cnt are "just below" a power of two, so anything
209         // larger than half the page size should be allocated as whole pages.
210         if (size*cnt+UNIT > pagesize/2) {
211                 // check/update bounce counter to start/increase retention
212                 // of freed maps, and inhibit use of low-count, odd-size
213                 // small mappings and single-slot groups if activated.
214                 int nosmall = is_bouncing(sc);
215                 account_bounce(sc);
216                 step_seq();
217
218                 // since the following count reduction opportunities have
219                 // an absolute memory usage cost, don't overdo them. count
220                 // coarse usage as part of usage.
221                 if (!(sc&1) && sc<32) usage += ctx.usage_by_class[sc+1];
222
223                 // try to drop to a lower count if the one found above
224                 // increases usage by more than 25%. these reduced counts
225                 // roughly fill an integral number of pages, just not a
226                 // power of two, limiting amount of unusable space.
227                 if (4*cnt > usage && !nosmall) {
228                         if (0);
229                         else if ((sc&3)==1 && size*cnt>8*pagesize) cnt = 2;
230                         else if ((sc&3)==2 && size*cnt>4*pagesize) cnt = 3;
231                         else if ((sc&3)==0 && size*cnt>8*pagesize) cnt = 3;
232                         else if ((sc&3)==0 && size*cnt>2*pagesize) cnt = 5;
233                 }
234                 size_t needed = size*cnt + UNIT;
235                 needed += -needed & (pagesize-1);
236
237                 // produce an individually-mmapped allocation if usage is low,
238                 // bounce counter hasn't triggered, and either it saves memory
239                 // or it avoids eagar slot allocation without wasting too much.
240                 if (!nosmall && cnt<=7) {
241                         req += IB + UNIT;
242                         req += -req & (pagesize-1);
243                         if (req<size+UNIT || (req>=4*pagesize && 2*cnt>usage)) {
244                                 cnt = 1;
245                                 needed = req;
246                         }
247                 }
248
249                 p = mmap(0, needed, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
250                 if (p==MAP_FAILED) {
251                         free_meta(m);
252                         return 0;
253                 }
254                 m->maplen = needed>>12;
255                 ctx.mmap_counter++;
256                 active_idx = (4096-UNIT)/size-1;
257                 if (active_idx > cnt-1) active_idx = cnt-1;
258                 if (active_idx < 0) active_idx = 0;
259         } else {
260                 int j = size_to_class(UNIT+cnt*size-IB);
261                 int idx = alloc_slot(j, UNIT+cnt*size-IB);
262                 if (idx < 0) {
263                         free_meta(m);
264                         return 0;
265                 }
266                 struct meta *g = ctx.active[j];
267                 p = enframe(g, idx, UNIT*size_classes[j]-IB, ctx.mmap_counter);
268                 m->maplen = 0;
269                 p[-3] = (p[-3]&31) | (6<<5);
270                 for (int i=0; i<=cnt; i++)
271                         p[UNIT+i*size-4] = 0;
272                 active_idx = cnt-1;
273         }
274         ctx.usage_by_class[sc] += cnt;
275         m->avail_mask = (2u<<active_idx)-1;
276         m->freed_mask = (2u<<(cnt-1))-1 - m->avail_mask;
277         m->mem = (void *)p;
278         m->mem->meta = m;
279         m->mem->active_idx = active_idx;
280         m->last_idx = cnt-1;
281         m->freeable = 1;
282         m->sizeclass = sc;
283         return m;
284 }
285
286 static int alloc_slot(int sc, size_t req)
287 {
288         uint32_t first = try_avail(&ctx.active[sc]);
289         if (first) return a_ctz_32(first);
290
291         struct meta *g = alloc_group(sc, req);
292         if (!g) return -1;
293
294         g->avail_mask--;
295         queue(&ctx.active[sc], g);
296         return 0;
297 }
298
299 void *malloc(size_t n)
300 {
301         if (size_overflows(n)) return 0;
302         struct meta *g;
303         uint32_t mask, first;
304         int sc;
305         int idx;
306         int ctr;
307
308         if (n >= MMAP_THRESHOLD) {
309                 size_t needed = n + IB + UNIT;
310                 void *p = mmap(0, needed, PROT_READ|PROT_WRITE,
311                         MAP_PRIVATE|MAP_ANON, -1, 0);
312                 if (p==MAP_FAILED) return 0;
313                 wrlock();
314                 step_seq();
315                 g = alloc_meta();
316                 if (!g) {
317                         unlock();
318                         munmap(p, needed);
319                         return 0;
320                 }
321                 g->mem = p;
322                 g->mem->meta = g;
323                 g->last_idx = 0;
324                 g->freeable = 1;
325                 g->sizeclass = 63;
326                 g->maplen = (needed+4095)/4096;
327                 g->avail_mask = g->freed_mask = 0;
328                 // use a global counter to cycle offset in
329                 // individually-mmapped allocations.
330                 ctx.mmap_counter++;
331                 idx = 0;
332                 goto success;
333         }
334
335         sc = size_to_class(n);
336
337         rdlock();
338         g = ctx.active[sc];
339
340         // use coarse size classes initially when there are not yet
341         // any groups of desired size. this allows counts of 2 or 3
342         // to be allocated at first rather than having to start with
343         // 7 or 5, the min counts for even size classes.
344         if (!g && sc>=4 && sc<32 && sc!=6 && !(sc&1) && !ctx.usage_by_class[sc]) {
345                 size_t usage = ctx.usage_by_class[sc|1];
346                 // if a new group may be allocated, count it toward
347                 // usage in deciding if we can use coarse class.
348                 if (!ctx.active[sc|1] || (!ctx.active[sc|1]->avail_mask
349                     && !ctx.active[sc|1]->freed_mask))
350                         usage += 3;
351                 if (usage <= 12)
352                         sc |= 1;
353                 g = ctx.active[sc];
354         }
355
356         for (;;) {
357                 mask = g ? g->avail_mask : 0;
358                 first = mask&-mask;
359                 if (!first) break;
360                 if (RDLOCK_IS_EXCLUSIVE || !MT)
361                         g->avail_mask = mask-first;
362                 else if (a_cas(&g->avail_mask, mask, mask-first)!=mask)
363                         continue;
364                 idx = a_ctz_32(first);
365                 goto success;
366         }
367         upgradelock();
368
369         idx = alloc_slot(sc, n);
370         if (idx < 0) {
371                 unlock();
372                 return 0;
373         }
374         g = ctx.active[sc];
375
376 success:
377         ctr = ctx.mmap_counter;
378         unlock();
379         return enframe(g, idx, n, ctr);
380 }
381
382 int is_allzero(void *p)
383 {
384         struct meta *g = get_meta(p);
385         return g->sizeclass >= 48 ||
386                 get_stride(g) < UNIT*size_classes[g->sizeclass];
387 }