1570af302Sopenharmony_ci#include <stdlib.h> 2570af302Sopenharmony_ci#include <stdint.h> 3570af302Sopenharmony_ci#include <limits.h> 4570af302Sopenharmony_ci#include <string.h> 5570af302Sopenharmony_ci#include <sys/mman.h> 6570af302Sopenharmony_ci#ifndef __LITEOS__ 7570af302Sopenharmony_ci#include <sys/prctl.h> 8570af302Sopenharmony_ci#endif 9570af302Sopenharmony_ci#include <errno.h> 10570af302Sopenharmony_ci 11570af302Sopenharmony_ci#include "meta.h" 12570af302Sopenharmony_ci 13570af302Sopenharmony_ci#ifdef USE_JEMALLOC 14570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF 15570af302Sopenharmony_ciextern void je_malloc_disable(); 16570af302Sopenharmony_ciextern void je_malloc_enable(); 17570af302Sopenharmony_ciextern int je_iterate(uintptr_t base, size_t size, 18570af302Sopenharmony_ci void (*callback)(uintptr_t ptr, size_t size, void* arg), void* arg); 19570af302Sopenharmony_ciextern int je_mallopt(int param, int value); 20570af302Sopenharmony_ci#endif 21570af302Sopenharmony_ci#endif 22570af302Sopenharmony_ci 23570af302Sopenharmony_ci#ifdef MALLOC_SECURE_ALL 24570af302Sopenharmony_ci#include <fcntl.h> 25570af302Sopenharmony_ci#define RANDOM_BUFFER_LEN 512 26570af302Sopenharmony_cistatic uint8_t buffer[RANDOM_BUFFER_LEN] = { 0 }; 27570af302Sopenharmony_cistatic size_t ri = RANDOM_BUFFER_LEN; 28570af302Sopenharmony_ci 29570af302Sopenharmony_cistatic uint8_t get_random8() 30570af302Sopenharmony_ci{ 31570af302Sopenharmony_ci uint8_t num; 32570af302Sopenharmony_ci if ((ri >= RANDOM_BUFFER_LEN) || (buffer[0] == 0)) { 33570af302Sopenharmony_ci int fd = open("/dev/urandom", O_RDONLY); 34570af302Sopenharmony_ci if (fd < 0) { 35570af302Sopenharmony_ci num = (uint8_t)get_random_secret(); 36570af302Sopenharmony_ci return num; 37570af302Sopenharmony_ci } 38570af302Sopenharmony_ci 39570af302Sopenharmony_ci read(fd, buffer, RANDOM_BUFFER_LEN); 40570af302Sopenharmony_ci close(fd); 41570af302Sopenharmony_ci ri = 0; 42570af302Sopenharmony_ci } 43570af302Sopenharmony_ci num = buffer[ri]; 44570af302Sopenharmony_ci ri++; 45570af302Sopenharmony_ci return num; 46570af302Sopenharmony_ci} 47570af302Sopenharmony_ci 48570af302Sopenharmony_cistatic int get_randomIdx(int avail_mask, int last_idx) 49570af302Sopenharmony_ci{ 50570af302Sopenharmony_ci uint32_t mask; 51570af302Sopenharmony_ci uint32_t r; 52570af302Sopenharmony_ci uint32_t cmask; 53570af302Sopenharmony_ci int idx; 54570af302Sopenharmony_ci 55570af302Sopenharmony_ci mask = avail_mask; 56570af302Sopenharmony_ci r = get_random8() % last_idx; 57570af302Sopenharmony_ci cmask = ~((2u << (last_idx - r)) - 1); 58570af302Sopenharmony_ci 59570af302Sopenharmony_ci if (mask & cmask) { 60570af302Sopenharmony_ci idx = 31 - a_clz_32(mask & cmask); 61570af302Sopenharmony_ci } else { 62570af302Sopenharmony_ci idx = a_ctz_32(mask); 63570af302Sopenharmony_ci } 64570af302Sopenharmony_ci 65570af302Sopenharmony_ci return idx; 66570af302Sopenharmony_ci} 67570af302Sopenharmony_ci#endif 68570af302Sopenharmony_ci 69570af302Sopenharmony_ciLOCK_OBJ_DEF; 70570af302Sopenharmony_ci 71570af302Sopenharmony_ciconst uint16_t size_classes[] = { 72570af302Sopenharmony_ci 1, 2, 3, 4, 5, 6, 7, 8, 73570af302Sopenharmony_ci 9, 10, 12, 15, 74570af302Sopenharmony_ci 18, 20, 25, 31, 75570af302Sopenharmony_ci 36, 42, 50, 63, 76570af302Sopenharmony_ci 72, 84, 102, 127, 77570af302Sopenharmony_ci 146, 170, 204, 255, 78570af302Sopenharmony_ci 292, 340, 409, 511, 79570af302Sopenharmony_ci 584, 682, 818, 1023, 80570af302Sopenharmony_ci 1169, 1364, 1637, 2047, 81570af302Sopenharmony_ci 2340, 2730, 3276, 4095, 82570af302Sopenharmony_ci 4680, 5460, 6552, 8191, 83570af302Sopenharmony_ci}; 84570af302Sopenharmony_ci 85570af302Sopenharmony_cistatic const uint8_t small_cnt_tab[][3] = { 86570af302Sopenharmony_ci { 30, 30, 30 }, 87570af302Sopenharmony_ci { 31, 15, 15 }, 88570af302Sopenharmony_ci { 20, 10, 10 }, 89570af302Sopenharmony_ci { 31, 15, 7 }, 90570af302Sopenharmony_ci { 25, 12, 6 }, 91570af302Sopenharmony_ci { 21, 10, 5 }, 92570af302Sopenharmony_ci { 18, 8, 4 }, 93570af302Sopenharmony_ci { 31, 15, 7 }, 94570af302Sopenharmony_ci { 28, 14, 6 }, 95570af302Sopenharmony_ci}; 96570af302Sopenharmony_ci 97570af302Sopenharmony_cistatic const uint8_t med_cnt_tab[4] = { 28, 24, 20, 32 }; 98570af302Sopenharmony_ci 99570af302Sopenharmony_cistruct malloc_context ctx = { 0 }; 100570af302Sopenharmony_ci 101570af302Sopenharmony_cistruct meta *alloc_meta(void) 102570af302Sopenharmony_ci{ 103570af302Sopenharmony_ci struct meta *m; 104570af302Sopenharmony_ci unsigned char *p; 105570af302Sopenharmony_ci if (!ctx.init_done) { 106570af302Sopenharmony_ci#ifndef PAGESIZE 107570af302Sopenharmony_ci ctx.pagesize = get_page_size(); 108570af302Sopenharmony_ci#endif 109570af302Sopenharmony_ci ctx.secret = get_random_secret(); 110570af302Sopenharmony_ci ctx.init_done = 1; 111570af302Sopenharmony_ci } 112570af302Sopenharmony_ci size_t pagesize = PGSZ; 113570af302Sopenharmony_ci if (pagesize < 4096) pagesize = 4096; 114570af302Sopenharmony_ci if ((m = dequeue_head(&ctx.free_meta_head))) return m; 115570af302Sopenharmony_ci if (!ctx.avail_meta_count) { 116570af302Sopenharmony_ci int need_unprotect = 1; 117570af302Sopenharmony_ci if (!ctx.avail_meta_area_count && ctx.brk!=-1) { 118570af302Sopenharmony_ci uintptr_t new = ctx.brk + pagesize; 119570af302Sopenharmony_ci int need_guard = 0; 120570af302Sopenharmony_ci if (!ctx.brk) { 121570af302Sopenharmony_ci need_guard = 1; 122570af302Sopenharmony_ci ctx.brk = brk(0); 123570af302Sopenharmony_ci // some ancient kernels returned _ebss 124570af302Sopenharmony_ci // instead of next page as initial brk. 125570af302Sopenharmony_ci ctx.brk += -ctx.brk & (pagesize-1); 126570af302Sopenharmony_ci new = ctx.brk + 2*pagesize; 127570af302Sopenharmony_ci } 128570af302Sopenharmony_ci if (brk(new) != new) { 129570af302Sopenharmony_ci ctx.brk = -1; 130570af302Sopenharmony_ci } else { 131570af302Sopenharmony_ci#ifndef __LITEOS__ 132570af302Sopenharmony_ci prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ctx.brk, new - ctx.brk, "native_heap:meta"); 133570af302Sopenharmony_ci#endif 134570af302Sopenharmony_ci if (need_guard) mmap((void *)ctx.brk, pagesize, 135570af302Sopenharmony_ci PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); 136570af302Sopenharmony_ci ctx.brk = new; 137570af302Sopenharmony_ci ctx.avail_meta_areas = (void *)(new - pagesize); 138570af302Sopenharmony_ci ctx.avail_meta_area_count = pagesize>>12; 139570af302Sopenharmony_ci need_unprotect = 0; 140570af302Sopenharmony_ci } 141570af302Sopenharmony_ci } 142570af302Sopenharmony_ci if (!ctx.avail_meta_area_count) { 143570af302Sopenharmony_ci size_t n = 2UL << ctx.meta_alloc_shift; 144570af302Sopenharmony_ci p = mmap(0, n*pagesize, PROT_NONE, 145570af302Sopenharmony_ci MAP_PRIVATE|MAP_ANON, -1, 0); 146570af302Sopenharmony_ci if (p==MAP_FAILED) return 0; 147570af302Sopenharmony_ci ctx.avail_meta_areas = p + pagesize; 148570af302Sopenharmony_ci ctx.avail_meta_area_count = (n-1)*(pagesize>>12); 149570af302Sopenharmony_ci ctx.meta_alloc_shift++; 150570af302Sopenharmony_ci } 151570af302Sopenharmony_ci p = ctx.avail_meta_areas; 152570af302Sopenharmony_ci if ((uintptr_t)p & (pagesize-1)) need_unprotect = 0; 153570af302Sopenharmony_ci if (need_unprotect) 154570af302Sopenharmony_ci if (mprotect(p, pagesize, PROT_READ|PROT_WRITE) 155570af302Sopenharmony_ci && errno != ENOSYS) 156570af302Sopenharmony_ci return 0; 157570af302Sopenharmony_ci ctx.avail_meta_area_count--; 158570af302Sopenharmony_ci ctx.avail_meta_areas = p + 4096; 159570af302Sopenharmony_ci if (ctx.meta_area_tail) { 160570af302Sopenharmony_ci ctx.meta_area_tail->next = (void *)p; 161570af302Sopenharmony_ci } else { 162570af302Sopenharmony_ci ctx.meta_area_head = (void *)p; 163570af302Sopenharmony_ci } 164570af302Sopenharmony_ci ctx.meta_area_tail = (void *)p; 165570af302Sopenharmony_ci ctx.meta_area_tail->check = ctx.secret; 166570af302Sopenharmony_ci ctx.avail_meta_count = ctx.meta_area_tail->nslots 167570af302Sopenharmony_ci = (4096-sizeof(struct meta_area))/sizeof *m; 168570af302Sopenharmony_ci ctx.avail_meta = ctx.meta_area_tail->slots; 169570af302Sopenharmony_ci } 170570af302Sopenharmony_ci ctx.avail_meta_count--; 171570af302Sopenharmony_ci m = ctx.avail_meta++; 172570af302Sopenharmony_ci m->prev = m->next = 0; 173570af302Sopenharmony_ci return m; 174570af302Sopenharmony_ci} 175570af302Sopenharmony_ci 176570af302Sopenharmony_cistatic uint32_t try_avail(struct meta **pm) 177570af302Sopenharmony_ci{ 178570af302Sopenharmony_ci struct meta *m = *pm; 179570af302Sopenharmony_ci uint32_t first; 180570af302Sopenharmony_ci if (!m) return 0; 181570af302Sopenharmony_ci uint32_t mask = m->avail_mask; 182570af302Sopenharmony_ci if (!mask) { 183570af302Sopenharmony_ci if (!m) return 0; 184570af302Sopenharmony_ci if (!m->freed_mask) { 185570af302Sopenharmony_ci dequeue(pm, m); 186570af302Sopenharmony_ci m = *pm; 187570af302Sopenharmony_ci if (!m) return 0; 188570af302Sopenharmony_ci } else { 189570af302Sopenharmony_ci m = m->next; 190570af302Sopenharmony_ci *pm = m; 191570af302Sopenharmony_ci } 192570af302Sopenharmony_ci 193570af302Sopenharmony_ci mask = m->freed_mask; 194570af302Sopenharmony_ci 195570af302Sopenharmony_ci // skip fully-free group unless it's the only one 196570af302Sopenharmony_ci // or it's a permanently non-freeable group 197570af302Sopenharmony_ci if (mask == (2u<<m->last_idx)-1 && m->freeable) { 198570af302Sopenharmony_ci m = m->next; 199570af302Sopenharmony_ci *pm = m; 200570af302Sopenharmony_ci mask = m->freed_mask; 201570af302Sopenharmony_ci } 202570af302Sopenharmony_ci 203570af302Sopenharmony_ci // activate more slots in a not-fully-active group 204570af302Sopenharmony_ci // if needed, but only as a last resort. prefer using 205570af302Sopenharmony_ci // any other group with free slots. this avoids 206570af302Sopenharmony_ci // touching & dirtying as-yet-unused pages. 207570af302Sopenharmony_ci if (!(mask & ((2u<<m->mem->active_idx)-1))) { 208570af302Sopenharmony_ci if (m->next != m) { 209570af302Sopenharmony_ci m = m->next; 210570af302Sopenharmony_ci *pm = m; 211570af302Sopenharmony_ci } else { 212570af302Sopenharmony_ci int cnt = m->mem->active_idx + 2; 213570af302Sopenharmony_ci int size = size_classes[m->sizeclass]*UNIT; 214570af302Sopenharmony_ci int span = UNIT + size*cnt; 215570af302Sopenharmony_ci // activate up to next 4k boundary 216570af302Sopenharmony_ci while ((span^(span+size-1)) < 4096) { 217570af302Sopenharmony_ci cnt++; 218570af302Sopenharmony_ci span += size; 219570af302Sopenharmony_ci } 220570af302Sopenharmony_ci if (cnt > m->last_idx+1) 221570af302Sopenharmony_ci cnt = m->last_idx+1; 222570af302Sopenharmony_ci m->mem->active_idx = cnt-1; 223570af302Sopenharmony_ci } 224570af302Sopenharmony_ci } 225570af302Sopenharmony_ci mask = activate_group(m); 226570af302Sopenharmony_ci assert(mask); 227570af302Sopenharmony_ci decay_bounces(m->sizeclass); 228570af302Sopenharmony_ci } 229570af302Sopenharmony_ci#ifdef MALLOC_SECURE_ALL 230570af302Sopenharmony_ci int idx = get_randomIdx(mask, m->last_idx); 231570af302Sopenharmony_ci first = 1 << idx; 232570af302Sopenharmony_ci#else 233570af302Sopenharmony_ci first = mask&-mask; 234570af302Sopenharmony_ci#endif 235570af302Sopenharmony_ci m->avail_mask = mask-first; 236570af302Sopenharmony_ci return first; 237570af302Sopenharmony_ci} 238570af302Sopenharmony_ci 239570af302Sopenharmony_cistatic int alloc_slot(int, size_t); 240570af302Sopenharmony_ci 241570af302Sopenharmony_cistatic struct meta *alloc_group(int sc, size_t req) 242570af302Sopenharmony_ci{ 243570af302Sopenharmony_ci size_t size = UNIT*size_classes[sc]; 244570af302Sopenharmony_ci int i = 0, cnt; 245570af302Sopenharmony_ci unsigned char *p; 246570af302Sopenharmony_ci struct meta *m = alloc_meta(); 247570af302Sopenharmony_ci if (!m) return 0; 248570af302Sopenharmony_ci size_t usage = ctx.usage_by_class[sc]; 249570af302Sopenharmony_ci size_t pagesize = PGSZ; 250570af302Sopenharmony_ci int active_idx; 251570af302Sopenharmony_ci if (sc < 9) { 252570af302Sopenharmony_ci while (i<2 && 4*small_cnt_tab[sc][i] > usage) 253570af302Sopenharmony_ci i++; 254570af302Sopenharmony_ci cnt = small_cnt_tab[sc][i]; 255570af302Sopenharmony_ci } else { 256570af302Sopenharmony_ci // lookup max number of slots fitting in power-of-two size 257570af302Sopenharmony_ci // from a table, along with number of factors of two we 258570af302Sopenharmony_ci // can divide out without a remainder or reaching 1. 259570af302Sopenharmony_ci cnt = med_cnt_tab[sc&3]; 260570af302Sopenharmony_ci 261570af302Sopenharmony_ci // reduce cnt to avoid excessive eagar allocation. 262570af302Sopenharmony_ci while (!(cnt&1) && 4*cnt > usage) 263570af302Sopenharmony_ci cnt >>= 1; 264570af302Sopenharmony_ci 265570af302Sopenharmony_ci // data structures don't support groups whose slot offsets 266570af302Sopenharmony_ci // in units don't fit in 16 bits. 267570af302Sopenharmony_ci while (size*cnt >= 65536*UNIT) 268570af302Sopenharmony_ci cnt >>= 1; 269570af302Sopenharmony_ci } 270570af302Sopenharmony_ci 271570af302Sopenharmony_ci // If we selected a count of 1 above but it's not sufficient to use 272570af302Sopenharmony_ci // mmap, increase to 2. Then it might be; if not it will nest. 273570af302Sopenharmony_ci if (cnt==1 && size*cnt+UNIT <= pagesize/2) cnt = 2; 274570af302Sopenharmony_ci 275570af302Sopenharmony_ci // All choices of size*cnt are "just below" a power of two, so anything 276570af302Sopenharmony_ci // larger than half the page size should be allocated as whole pages. 277570af302Sopenharmony_ci if (size*cnt+UNIT > pagesize/2) { 278570af302Sopenharmony_ci // check/update bounce counter to start/increase retention 279570af302Sopenharmony_ci // of freed maps, and inhibit use of low-count, odd-size 280570af302Sopenharmony_ci // small mappings and single-slot groups if activated. 281570af302Sopenharmony_ci int nosmall = is_bouncing(sc); 282570af302Sopenharmony_ci account_bounce(sc); 283570af302Sopenharmony_ci step_seq(); 284570af302Sopenharmony_ci 285570af302Sopenharmony_ci // since the following count reduction opportunities have 286570af302Sopenharmony_ci // an absolute memory usage cost, don't overdo them. count 287570af302Sopenharmony_ci // coarse usage as part of usage. 288570af302Sopenharmony_ci if (!(sc&1) && sc<32) usage += ctx.usage_by_class[sc+1]; 289570af302Sopenharmony_ci 290570af302Sopenharmony_ci // try to drop to a lower count if the one found above 291570af302Sopenharmony_ci // increases usage by more than 25%. these reduced counts 292570af302Sopenharmony_ci // roughly fill an integral number of pages, just not a 293570af302Sopenharmony_ci // power of two, limiting amount of unusable space. 294570af302Sopenharmony_ci if (4*cnt > usage && !nosmall) { 295570af302Sopenharmony_ci if (0); 296570af302Sopenharmony_ci else if ((sc&3)==1 && size*cnt>8*pagesize) cnt = 2; 297570af302Sopenharmony_ci else if ((sc&3)==2 && size*cnt>4*pagesize) cnt = 3; 298570af302Sopenharmony_ci else if ((sc&3)==0 && size*cnt>8*pagesize) cnt = 3; 299570af302Sopenharmony_ci else if ((sc&3)==0 && size*cnt>2*pagesize) cnt = 5; 300570af302Sopenharmony_ci } 301570af302Sopenharmony_ci size_t needed = size*cnt + UNIT; 302570af302Sopenharmony_ci needed += -needed & (pagesize-1); 303570af302Sopenharmony_ci 304570af302Sopenharmony_ci // produce an individually-mmapped allocation if usage is low, 305570af302Sopenharmony_ci // bounce counter hasn't triggered, and either it saves memory 306570af302Sopenharmony_ci // or it avoids eagar slot allocation without wasting too much. 307570af302Sopenharmony_ci if (!nosmall && cnt<=7) { 308570af302Sopenharmony_ci req += IB + UNIT; 309570af302Sopenharmony_ci req += -req & (pagesize-1); 310570af302Sopenharmony_ci if (req<size+UNIT || (req>=4*pagesize && 2*cnt>usage)) { 311570af302Sopenharmony_ci cnt = 1; 312570af302Sopenharmony_ci needed = req; 313570af302Sopenharmony_ci } 314570af302Sopenharmony_ci } 315570af302Sopenharmony_ci 316570af302Sopenharmony_ci p = mmap(0, needed, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 317570af302Sopenharmony_ci if (p==MAP_FAILED) { 318570af302Sopenharmony_ci free_meta(m); 319570af302Sopenharmony_ci return 0; 320570af302Sopenharmony_ci } 321570af302Sopenharmony_ci#ifndef __LITEOS__ 322570af302Sopenharmony_ci prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, needed, "native_heap:brk"); 323570af302Sopenharmony_ci#endif 324570af302Sopenharmony_ci m->maplen = needed>>12; 325570af302Sopenharmony_ci ctx.mmap_counter++; 326570af302Sopenharmony_ci active_idx = (4096-UNIT)/size-1; 327570af302Sopenharmony_ci if (active_idx > cnt-1) active_idx = cnt-1; 328570af302Sopenharmony_ci if (active_idx < 0) active_idx = 0; 329570af302Sopenharmony_ci } else { 330570af302Sopenharmony_ci int j = size_to_class(UNIT+cnt*size-IB); 331570af302Sopenharmony_ci int idx = alloc_slot(j, UNIT+cnt*size-IB); 332570af302Sopenharmony_ci if (idx < 0) { 333570af302Sopenharmony_ci free_meta(m); 334570af302Sopenharmony_ci return 0; 335570af302Sopenharmony_ci } 336570af302Sopenharmony_ci struct meta *g = ctx.active[j]; 337570af302Sopenharmony_ci p = enframe(g, idx, UNIT*size_classes[j]-IB, ctx.mmap_counter); 338570af302Sopenharmony_ci m->maplen = 0; 339570af302Sopenharmony_ci p[-3] = (p[-3]&31) | (6<<5); 340570af302Sopenharmony_ci for (int i=0; i<=cnt; i++) 341570af302Sopenharmony_ci p[UNIT+i*size-4] = 0; 342570af302Sopenharmony_ci active_idx = cnt-1; 343570af302Sopenharmony_ci } 344570af302Sopenharmony_ci ctx.usage_by_class[sc] += cnt; 345570af302Sopenharmony_ci m->avail_mask = (2u<<active_idx)-1; 346570af302Sopenharmony_ci m->freed_mask = (2u<<(cnt-1))-1 - m->avail_mask; 347570af302Sopenharmony_ci m->mem = (void *)p; 348570af302Sopenharmony_ci m->mem->meta = encode_ptr(m, ctx.secret); 349570af302Sopenharmony_ci m->mem->active_idx = active_idx; 350570af302Sopenharmony_ci m->last_idx = cnt-1; 351570af302Sopenharmony_ci m->freeable = 1; 352570af302Sopenharmony_ci m->sizeclass = sc; 353570af302Sopenharmony_ci return m; 354570af302Sopenharmony_ci} 355570af302Sopenharmony_ci 356570af302Sopenharmony_cistatic int alloc_slot(int sc, size_t req) 357570af302Sopenharmony_ci{ 358570af302Sopenharmony_ci uint32_t first = try_avail(&ctx.active[sc]); 359570af302Sopenharmony_ci if (first) return a_ctz_32(first); 360570af302Sopenharmony_ci 361570af302Sopenharmony_ci struct meta *g = alloc_group(sc, req); 362570af302Sopenharmony_ci if (!g) return -1; 363570af302Sopenharmony_ci 364570af302Sopenharmony_ci g->avail_mask--; 365570af302Sopenharmony_ci queue(&ctx.active[sc], g); 366570af302Sopenharmony_ci return 0; 367570af302Sopenharmony_ci} 368570af302Sopenharmony_ci 369570af302Sopenharmony_civoid *malloc(size_t n) 370570af302Sopenharmony_ci{ 371570af302Sopenharmony_ci if (size_overflows(n)) return 0; 372570af302Sopenharmony_ci struct meta *g; 373570af302Sopenharmony_ci uint32_t mask, first; 374570af302Sopenharmony_ci int sc; 375570af302Sopenharmony_ci int idx; 376570af302Sopenharmony_ci int ctr; 377570af302Sopenharmony_ci 378570af302Sopenharmony_ci if (n >= MMAP_THRESHOLD) { 379570af302Sopenharmony_ci size_t needed = n + IB + UNIT; 380570af302Sopenharmony_ci void *p = mmap(0, needed, PROT_READ|PROT_WRITE, 381570af302Sopenharmony_ci MAP_PRIVATE|MAP_ANON, -1, 0); 382570af302Sopenharmony_ci if (p==MAP_FAILED) return 0; 383570af302Sopenharmony_ci wrlock(); 384570af302Sopenharmony_ci#ifndef __LITEOS__ 385570af302Sopenharmony_ci prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, needed, "native_heap:mmap"); 386570af302Sopenharmony_ci#endif 387570af302Sopenharmony_ci step_seq(); 388570af302Sopenharmony_ci g = alloc_meta(); 389570af302Sopenharmony_ci if (!g) { 390570af302Sopenharmony_ci unlock(); 391570af302Sopenharmony_ci munmap(p, needed); 392570af302Sopenharmony_ci return 0; 393570af302Sopenharmony_ci } 394570af302Sopenharmony_ci g->mem = p; 395570af302Sopenharmony_ci g->mem->meta = encode_ptr(g, ctx.secret); 396570af302Sopenharmony_ci g->last_idx = 0; 397570af302Sopenharmony_ci g->freeable = 1; 398570af302Sopenharmony_ci g->sizeclass = 63; 399570af302Sopenharmony_ci g->maplen = (needed+4095)/4096; 400570af302Sopenharmony_ci g->avail_mask = g->freed_mask = 0; 401570af302Sopenharmony_ci // use a global counter to cycle offset in 402570af302Sopenharmony_ci // individually-mmapped allocations. 403570af302Sopenharmony_ci ctx.mmap_counter++; 404570af302Sopenharmony_ci idx = 0; 405570af302Sopenharmony_ci goto success; 406570af302Sopenharmony_ci } 407570af302Sopenharmony_ci 408570af302Sopenharmony_ci sc = size_to_class(n); 409570af302Sopenharmony_ci 410570af302Sopenharmony_ci rdlock(); 411570af302Sopenharmony_ci g = ctx.active[sc]; 412570af302Sopenharmony_ci 413570af302Sopenharmony_ci // use coarse size classes initially when there are not yet 414570af302Sopenharmony_ci // any groups of desired size. this allows counts of 2 or 3 415570af302Sopenharmony_ci // to be allocated at first rather than having to start with 416570af302Sopenharmony_ci // 7 or 5, the min counts for even size classes. 417570af302Sopenharmony_ci if (!g && sc>=4 && sc<32 && sc!=6 && !(sc&1) && !ctx.usage_by_class[sc]) { 418570af302Sopenharmony_ci size_t usage = ctx.usage_by_class[sc|1]; 419570af302Sopenharmony_ci // if a new group may be allocated, count it toward 420570af302Sopenharmony_ci // usage in deciding if we can use coarse class. 421570af302Sopenharmony_ci if (!ctx.active[sc|1] || (!ctx.active[sc|1]->avail_mask 422570af302Sopenharmony_ci && !ctx.active[sc|1]->freed_mask)) 423570af302Sopenharmony_ci usage += 3; 424570af302Sopenharmony_ci if (usage <= 12) 425570af302Sopenharmony_ci sc |= 1; 426570af302Sopenharmony_ci g = ctx.active[sc]; 427570af302Sopenharmony_ci } 428570af302Sopenharmony_ci 429570af302Sopenharmony_ci for (;;) { 430570af302Sopenharmony_ci mask = g ? g->avail_mask : 0; 431570af302Sopenharmony_ci#ifdef MALLOC_SECURE_ALL 432570af302Sopenharmony_ci if (!mask) break; 433570af302Sopenharmony_ci idx = get_randomIdx(mask, g->last_idx); 434570af302Sopenharmony_ci first = 1u << idx; 435570af302Sopenharmony_ci 436570af302Sopenharmony_ci if (RDLOCK_IS_EXCLUSIVE || !MT) 437570af302Sopenharmony_ci g->avail_mask = mask-first; 438570af302Sopenharmony_ci else if (a_cas(&g->avail_mask, mask, mask-first)!=mask) 439570af302Sopenharmony_ci continue; 440570af302Sopenharmony_ci#else 441570af302Sopenharmony_ci first = mask&-mask; 442570af302Sopenharmony_ci if (!first) break; 443570af302Sopenharmony_ci if (RDLOCK_IS_EXCLUSIVE || !MT) 444570af302Sopenharmony_ci g->avail_mask = mask-first; 445570af302Sopenharmony_ci else if (a_cas(&g->avail_mask, mask, mask-first)!=mask) 446570af302Sopenharmony_ci continue; 447570af302Sopenharmony_ci idx = a_ctz_32(first); 448570af302Sopenharmony_ci#endif 449570af302Sopenharmony_ci goto success; 450570af302Sopenharmony_ci } 451570af302Sopenharmony_ci upgradelock(); 452570af302Sopenharmony_ci 453570af302Sopenharmony_ci idx = alloc_slot(sc, n); 454570af302Sopenharmony_ci if (idx < 0) { 455570af302Sopenharmony_ci unlock(); 456570af302Sopenharmony_ci return 0; 457570af302Sopenharmony_ci } 458570af302Sopenharmony_ci g = ctx.active[sc]; 459570af302Sopenharmony_ci 460570af302Sopenharmony_cisuccess: 461570af302Sopenharmony_ci ctr = ctx.mmap_counter; 462570af302Sopenharmony_ci unlock(); 463570af302Sopenharmony_ci return enframe(g, idx, n, ctr); 464570af302Sopenharmony_ci} 465570af302Sopenharmony_ci 466570af302Sopenharmony_ciint is_allzero(void *p) 467570af302Sopenharmony_ci{ 468570af302Sopenharmony_ci struct meta *g = get_meta(p); 469570af302Sopenharmony_ci return g->sizeclass >= 48 || 470570af302Sopenharmony_ci get_stride(g) < UNIT*size_classes[g->sizeclass]; 471570af302Sopenharmony_ci} 472570af302Sopenharmony_ci 473570af302Sopenharmony_ciint mallopt(int param, int value) 474570af302Sopenharmony_ci{ 475570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF 476570af302Sopenharmony_ci return je_mallopt(param, value); 477570af302Sopenharmony_ci#endif 478570af302Sopenharmony_ci return 0; 479570af302Sopenharmony_ci} 480570af302Sopenharmony_ci 481570af302Sopenharmony_civoid malloc_disable(void) 482570af302Sopenharmony_ci{ 483570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF 484570af302Sopenharmony_ci je_malloc_disable(); 485570af302Sopenharmony_ci#endif 486570af302Sopenharmony_ci} 487570af302Sopenharmony_ci 488570af302Sopenharmony_civoid malloc_enable(void) 489570af302Sopenharmony_ci{ 490570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF 491570af302Sopenharmony_ci je_malloc_enable(); 492570af302Sopenharmony_ci#endif 493570af302Sopenharmony_ci} 494570af302Sopenharmony_ci 495570af302Sopenharmony_ciint malloc_iterate(void* base, size_t size, void (*callback)(void* base, size_t size, void* arg), void* arg) 496570af302Sopenharmony_ci{ 497570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF 498570af302Sopenharmony_ci return je_iterate(base, size, callback, arg); 499570af302Sopenharmony_ci#endif 500570af302Sopenharmony_ci return 0; 501570af302Sopenharmony_ci} 502570af302Sopenharmony_ci 503570af302Sopenharmony_cissize_t malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count) 504570af302Sopenharmony_ci{ 505570af302Sopenharmony_ci return 0; 506570af302Sopenharmony_ci} 507