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