1570af302Sopenharmony_ci#define _GNU_SOURCE 2570af302Sopenharmony_ci#include <stdlib.h> 3570af302Sopenharmony_ci#include <string.h> 4570af302Sopenharmony_ci#include <limits.h> 5570af302Sopenharmony_ci#include <stdint.h> 6570af302Sopenharmony_ci#include <errno.h> 7570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 8570af302Sopenharmony_ci#include <unistd.h> 9570af302Sopenharmony_ci#include <debug.h> 10570af302Sopenharmony_ci#endif 11570af302Sopenharmony_ci#include <sys/mman.h> 12570af302Sopenharmony_ci#include "libc.h" 13570af302Sopenharmony_ci#include "atomic.h" 14570af302Sopenharmony_ci#include "pthread_impl.h" 15570af302Sopenharmony_ci#include "malloc_impl.h" 16570af302Sopenharmony_ci#include "fork_impl.h" 17570af302Sopenharmony_ci 18570af302Sopenharmony_ci#define malloc __libc_malloc_impl 19570af302Sopenharmony_ci#define realloc __libc_realloc 20570af302Sopenharmony_ci#define free __libc_free 21570af302Sopenharmony_ci 22570af302Sopenharmony_ci#if defined(__GNUC__) && defined(__PIC__) 23570af302Sopenharmony_ci#define inline inline __attribute__((always_inline)) 24570af302Sopenharmony_ci#endif 25570af302Sopenharmony_ci 26570af302Sopenharmony_cistatic struct { 27570af302Sopenharmony_ci volatile uint64_t binmap; 28570af302Sopenharmony_ci struct bin bins[64]; 29570af302Sopenharmony_ci volatile int split_merge_lock[2]; 30570af302Sopenharmony_ci} mal; 31570af302Sopenharmony_ci 32570af302Sopenharmony_ci/* Synchronization tools */ 33570af302Sopenharmony_ci 34570af302Sopenharmony_cistatic inline void lock(volatile int *lk) 35570af302Sopenharmony_ci{ 36570af302Sopenharmony_ci int need_locks = libc.need_locks; 37570af302Sopenharmony_ci if (need_locks) { 38570af302Sopenharmony_ci while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1); 39570af302Sopenharmony_ci if (need_locks < 0) libc.need_locks = 0; 40570af302Sopenharmony_ci } 41570af302Sopenharmony_ci} 42570af302Sopenharmony_ci 43570af302Sopenharmony_cistatic inline void unlock(volatile int *lk) 44570af302Sopenharmony_ci{ 45570af302Sopenharmony_ci if (lk[0]) { 46570af302Sopenharmony_ci a_store(lk, 0); 47570af302Sopenharmony_ci if (lk[1]) __wake(lk, 1, 1); 48570af302Sopenharmony_ci } 49570af302Sopenharmony_ci} 50570af302Sopenharmony_ci 51570af302Sopenharmony_cistatic inline void lock_bin(int i) 52570af302Sopenharmony_ci{ 53570af302Sopenharmony_ci lock(mal.bins[i].lock); 54570af302Sopenharmony_ci if (!mal.bins[i].head) 55570af302Sopenharmony_ci mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i); 56570af302Sopenharmony_ci} 57570af302Sopenharmony_ci 58570af302Sopenharmony_cistatic inline void unlock_bin(int i) 59570af302Sopenharmony_ci{ 60570af302Sopenharmony_ci unlock(mal.bins[i].lock); 61570af302Sopenharmony_ci} 62570af302Sopenharmony_ci 63570af302Sopenharmony_cistatic int first_set(uint64_t x) 64570af302Sopenharmony_ci{ 65570af302Sopenharmony_ci#if 1 66570af302Sopenharmony_ci return a_ctz_64(x); 67570af302Sopenharmony_ci#else 68570af302Sopenharmony_ci static const char debruijn64[64] = { 69570af302Sopenharmony_ci 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, 70570af302Sopenharmony_ci 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, 71570af302Sopenharmony_ci 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, 72570af302Sopenharmony_ci 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 73570af302Sopenharmony_ci }; 74570af302Sopenharmony_ci static const char debruijn32[32] = { 75570af302Sopenharmony_ci 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 76570af302Sopenharmony_ci 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 77570af302Sopenharmony_ci }; 78570af302Sopenharmony_ci if (sizeof(long) < 8) { 79570af302Sopenharmony_ci uint32_t y = x; 80570af302Sopenharmony_ci if (!y) { 81570af302Sopenharmony_ci y = x>>32; 82570af302Sopenharmony_ci return 32 + debruijn32[(y&-y)*0x076be629 >> 27]; 83570af302Sopenharmony_ci } 84570af302Sopenharmony_ci return debruijn32[(y&-y)*0x076be629 >> 27]; 85570af302Sopenharmony_ci } 86570af302Sopenharmony_ci return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; 87570af302Sopenharmony_ci#endif 88570af302Sopenharmony_ci} 89570af302Sopenharmony_ci 90570af302Sopenharmony_cistatic const unsigned char bin_tab[60] = { 91570af302Sopenharmony_ci 32,33,34,35,36,36,37,37,38,38,39,39, 92570af302Sopenharmony_ci 40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43, 93570af302Sopenharmony_ci 44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45, 94570af302Sopenharmony_ci 46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47, 95570af302Sopenharmony_ci}; 96570af302Sopenharmony_ci 97570af302Sopenharmony_cistatic int bin_index(size_t x) 98570af302Sopenharmony_ci{ 99570af302Sopenharmony_ci x = x / SIZE_ALIGN - 1; 100570af302Sopenharmony_ci if (x <= 32) return x; 101570af302Sopenharmony_ci if (x < 512) return bin_tab[x/8-4]; 102570af302Sopenharmony_ci if (x > 0x1c00) return 63; 103570af302Sopenharmony_ci return bin_tab[x/128-4] + 16; 104570af302Sopenharmony_ci} 105570af302Sopenharmony_ci 106570af302Sopenharmony_cistatic int bin_index_up(size_t x) 107570af302Sopenharmony_ci{ 108570af302Sopenharmony_ci x = x / SIZE_ALIGN - 1; 109570af302Sopenharmony_ci if (x <= 32) return x; 110570af302Sopenharmony_ci x--; 111570af302Sopenharmony_ci if (x < 512) return bin_tab[x/8-4] + 1; 112570af302Sopenharmony_ci return bin_tab[x/128-4] + 17; 113570af302Sopenharmony_ci} 114570af302Sopenharmony_ci 115570af302Sopenharmony_ci#if 0 116570af302Sopenharmony_civoid __dump_heap(int x) 117570af302Sopenharmony_ci{ 118570af302Sopenharmony_ci struct chunk *c; 119570af302Sopenharmony_ci int i; 120570af302Sopenharmony_ci for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c)) 121570af302Sopenharmony_ci fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n", 122570af302Sopenharmony_ci c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)), 123570af302Sopenharmony_ci c->csize & 15, 124570af302Sopenharmony_ci NEXT_CHUNK(c)->psize & 15); 125570af302Sopenharmony_ci for (i=0; i<64; i++) { 126570af302Sopenharmony_ci if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) { 127570af302Sopenharmony_ci fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head); 128570af302Sopenharmony_ci if (!(mal.binmap & 1ULL<<i)) 129570af302Sopenharmony_ci fprintf(stderr, "missing from binmap!\n"); 130570af302Sopenharmony_ci } else if (mal.binmap & 1ULL<<i) 131570af302Sopenharmony_ci fprintf(stderr, "binmap wrongly contains %d!\n", i); 132570af302Sopenharmony_ci } 133570af302Sopenharmony_ci} 134570af302Sopenharmony_ci#endif 135570af302Sopenharmony_ci 136570af302Sopenharmony_ci/* This function returns true if the interval [old,new] 137570af302Sopenharmony_ci * intersects the 'len'-sized interval below &libc.auxv 138570af302Sopenharmony_ci * (interpreted as the main-thread stack) or below &b 139570af302Sopenharmony_ci * (the current stack). It is used to defend against 140570af302Sopenharmony_ci * buggy brk implementations that can cross the stack. */ 141570af302Sopenharmony_ci 142570af302Sopenharmony_cistatic int traverses_stack_p(uintptr_t old, uintptr_t new) 143570af302Sopenharmony_ci{ 144570af302Sopenharmony_ci const uintptr_t len = 8<<20; 145570af302Sopenharmony_ci uintptr_t a, b; 146570af302Sopenharmony_ci 147570af302Sopenharmony_ci b = (uintptr_t)libc.auxv; 148570af302Sopenharmony_ci a = b > len ? b-len : 0; 149570af302Sopenharmony_ci if (new>a && old<b) return 1; 150570af302Sopenharmony_ci 151570af302Sopenharmony_ci b = (uintptr_t)&b; 152570af302Sopenharmony_ci a = b > len ? b-len : 0; 153570af302Sopenharmony_ci if (new>a && old<b) return 1; 154570af302Sopenharmony_ci 155570af302Sopenharmony_ci return 0; 156570af302Sopenharmony_ci} 157570af302Sopenharmony_ci 158570af302Sopenharmony_ci/* Expand the heap in-place if brk can be used, or otherwise via mmap, 159570af302Sopenharmony_ci * using an exponential lower bound on growth by mmap to make 160570af302Sopenharmony_ci * fragmentation asymptotically irrelevant. The size argument is both 161570af302Sopenharmony_ci * an input and an output, since the caller needs to know the size 162570af302Sopenharmony_ci * allocated, which will be larger than requested due to page alignment 163570af302Sopenharmony_ci * and mmap minimum size rules. The caller is responsible for locking 164570af302Sopenharmony_ci * to prevent concurrent calls. */ 165570af302Sopenharmony_ci 166570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 167570af302Sopenharmony_civoid *__expand_heap(size_t *pn) 168570af302Sopenharmony_ci#else 169570af302Sopenharmony_cistatic void *__expand_heap(size_t *pn) 170570af302Sopenharmony_ci#endif 171570af302Sopenharmony_ci{ 172570af302Sopenharmony_ci static uintptr_t brk; 173570af302Sopenharmony_ci static unsigned mmap_step; 174570af302Sopenharmony_ci size_t n = *pn; 175570af302Sopenharmony_ci 176570af302Sopenharmony_ci if (n > SIZE_MAX/2 - PAGE_SIZE) { 177570af302Sopenharmony_ci errno = ENOMEM; 178570af302Sopenharmony_ci return 0; 179570af302Sopenharmony_ci } 180570af302Sopenharmony_ci n += -n & PAGE_SIZE-1; 181570af302Sopenharmony_ci 182570af302Sopenharmony_ci if (!brk) { 183570af302Sopenharmony_ci brk = __syscall(SYS_brk, 0); 184570af302Sopenharmony_ci brk += -brk & PAGE_SIZE-1; 185570af302Sopenharmony_ci } 186570af302Sopenharmony_ci 187570af302Sopenharmony_ci if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n) 188570af302Sopenharmony_ci && __syscall(SYS_brk, brk+n)==brk+n) { 189570af302Sopenharmony_ci *pn = n; 190570af302Sopenharmony_ci brk += n; 191570af302Sopenharmony_ci return (void *)(brk-n); 192570af302Sopenharmony_ci } 193570af302Sopenharmony_ci 194570af302Sopenharmony_ci size_t min = (size_t)PAGE_SIZE << mmap_step/2; 195570af302Sopenharmony_ci if (n < min) n = min; 196570af302Sopenharmony_ci void *area = __mmap(0, n, PROT_READ|PROT_WRITE, 197570af302Sopenharmony_ci MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 198570af302Sopenharmony_ci if (area == MAP_FAILED) return 0; 199570af302Sopenharmony_ci *pn = n; 200570af302Sopenharmony_ci mmap_step++; 201570af302Sopenharmony_ci return area; 202570af302Sopenharmony_ci} 203570af302Sopenharmony_ci 204570af302Sopenharmony_cistatic struct chunk *expand_heap(size_t n) 205570af302Sopenharmony_ci{ 206570af302Sopenharmony_ci static void *end; 207570af302Sopenharmony_ci void *p; 208570af302Sopenharmony_ci struct chunk *w; 209570af302Sopenharmony_ci 210570af302Sopenharmony_ci /* The argument n already accounts for the caller's chunk 211570af302Sopenharmony_ci * overhead needs, but if the heap can't be extended in-place, 212570af302Sopenharmony_ci * we need room for an extra zero-sized sentinel chunk. */ 213570af302Sopenharmony_ci n += SIZE_ALIGN; 214570af302Sopenharmony_ci 215570af302Sopenharmony_ci p = __expand_heap(&n); 216570af302Sopenharmony_ci if (!p) return 0; 217570af302Sopenharmony_ci 218570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 219570af302Sopenharmony_ci lock(g_mem_lock); 220570af302Sopenharmony_ci#endif 221570af302Sopenharmony_ci /* If not just expanding existing space, we need to make a 222570af302Sopenharmony_ci * new sentinel chunk below the allocated space. */ 223570af302Sopenharmony_ci if (p != end) { 224570af302Sopenharmony_ci /* Valid/safe because of the prologue increment. */ 225570af302Sopenharmony_ci n -= SIZE_ALIGN; 226570af302Sopenharmony_ci p = (char *)p + SIZE_ALIGN; 227570af302Sopenharmony_ci w = MEM_TO_CHUNK(p); 228570af302Sopenharmony_ci w->psize = 0 | C_INUSE; 229570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 230570af302Sopenharmony_ci insert_block_list(w); 231570af302Sopenharmony_ci#endif 232570af302Sopenharmony_ci } 233570af302Sopenharmony_ci 234570af302Sopenharmony_ci /* Record new heap end and fill in footer. */ 235570af302Sopenharmony_ci end = (char *)p + n; 236570af302Sopenharmony_ci w = MEM_TO_CHUNK(end); 237570af302Sopenharmony_ci w->psize = n | C_INUSE; 238570af302Sopenharmony_ci w->csize = 0 | C_INUSE; 239570af302Sopenharmony_ci 240570af302Sopenharmony_ci /* Fill in header, which may be new or may be replacing a 241570af302Sopenharmony_ci * zero-size sentinel header at the old end-of-heap. */ 242570af302Sopenharmony_ci w = MEM_TO_CHUNK(p); 243570af302Sopenharmony_ci w->csize = n | C_INUSE; 244570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 245570af302Sopenharmony_ci calculate_checksum(w, MEM_TO_CHUNK(end)); 246570af302Sopenharmony_ci 247570af302Sopenharmony_ci unlock(g_mem_lock); 248570af302Sopenharmony_ci#endif 249570af302Sopenharmony_ci 250570af302Sopenharmony_ci return w; 251570af302Sopenharmony_ci} 252570af302Sopenharmony_ci 253570af302Sopenharmony_cistatic int adjust_size(size_t *n) 254570af302Sopenharmony_ci{ 255570af302Sopenharmony_ci /* Result of pointer difference must fit in ptrdiff_t. */ 256570af302Sopenharmony_ci if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) { 257570af302Sopenharmony_ci if (*n) { 258570af302Sopenharmony_ci errno = ENOMEM; 259570af302Sopenharmony_ci return -1; 260570af302Sopenharmony_ci } else { 261570af302Sopenharmony_ci *n = SIZE_ALIGN; 262570af302Sopenharmony_ci return 0; 263570af302Sopenharmony_ci } 264570af302Sopenharmony_ci } 265570af302Sopenharmony_ci *n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK; 266570af302Sopenharmony_ci return 0; 267570af302Sopenharmony_ci} 268570af302Sopenharmony_ci 269570af302Sopenharmony_cistatic void unbin(struct chunk *c, int i) 270570af302Sopenharmony_ci{ 271570af302Sopenharmony_ci if (c->prev == c->next) 272570af302Sopenharmony_ci a_and_64(&mal.binmap, ~(1ULL<<i)); 273570af302Sopenharmony_ci c->prev->next = c->next; 274570af302Sopenharmony_ci c->next->prev = c->prev; 275570af302Sopenharmony_ci c->csize |= C_INUSE; 276570af302Sopenharmony_ci NEXT_CHUNK(c)->psize |= C_INUSE; 277570af302Sopenharmony_ci} 278570af302Sopenharmony_ci 279570af302Sopenharmony_cistatic void bin_chunk(struct chunk *self, int i) 280570af302Sopenharmony_ci{ 281570af302Sopenharmony_ci self->next = BIN_TO_CHUNK(i); 282570af302Sopenharmony_ci self->prev = mal.bins[i].tail; 283570af302Sopenharmony_ci self->next->prev = self; 284570af302Sopenharmony_ci self->prev->next = self; 285570af302Sopenharmony_ci if (self->prev == BIN_TO_CHUNK(i)) 286570af302Sopenharmony_ci a_or_64(&mal.binmap, 1ULL<<i); 287570af302Sopenharmony_ci} 288570af302Sopenharmony_ci 289570af302Sopenharmony_cistatic void trim(struct chunk *self, size_t n) 290570af302Sopenharmony_ci{ 291570af302Sopenharmony_ci size_t n1 = CHUNK_SIZE(self); 292570af302Sopenharmony_ci struct chunk *next, *split; 293570af302Sopenharmony_ci 294570af302Sopenharmony_ci if (n >= n1 - DONTCARE) return; 295570af302Sopenharmony_ci 296570af302Sopenharmony_ci next = NEXT_CHUNK(self); 297570af302Sopenharmony_ci split = (void *)((char *)self + n); 298570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 299570af302Sopenharmony_ci lock(g_mem_lock); 300570af302Sopenharmony_ci#endif 301570af302Sopenharmony_ci split->psize = n | C_INUSE; 302570af302Sopenharmony_ci split->csize = n1-n; 303570af302Sopenharmony_ci next->psize = n1-n; 304570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 305570af302Sopenharmony_ci calculate_checksum(split, next); 306570af302Sopenharmony_ci#endif 307570af302Sopenharmony_ci self->csize = n | C_INUSE; 308570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 309570af302Sopenharmony_ci calculate_checksum(self, NULL); 310570af302Sopenharmony_ci unlock(g_mem_lock); 311570af302Sopenharmony_ci#endif 312570af302Sopenharmony_ci 313570af302Sopenharmony_ci int i = bin_index(n1-n); 314570af302Sopenharmony_ci lock_bin(i); 315570af302Sopenharmony_ci 316570af302Sopenharmony_ci bin_chunk(split, i); 317570af302Sopenharmony_ci 318570af302Sopenharmony_ci unlock_bin(i); 319570af302Sopenharmony_ci} 320570af302Sopenharmony_ci 321570af302Sopenharmony_civoid *malloc(size_t n) 322570af302Sopenharmony_ci{ 323570af302Sopenharmony_ci struct chunk *c; 324570af302Sopenharmony_ci int i, j; 325570af302Sopenharmony_ci uint64_t mask; 326570af302Sopenharmony_ci 327570af302Sopenharmony_ci if (adjust_size(&n) < 0) return 0; 328570af302Sopenharmony_ci 329570af302Sopenharmony_ci if (n > MMAP_THRESHOLD) { 330570af302Sopenharmony_ci size_t len = n + OVERHEAD + PAGE_SIZE - 1 & -PAGE_SIZE; 331570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 332570af302Sopenharmony_ci if (g_enable_check) { 333570af302Sopenharmony_ci /* Allocate two more pages for protection, loacted at the head and tail of user memory respectively */ 334570af302Sopenharmony_ci len += PAGE_SIZE << 1; 335570af302Sopenharmony_ci } 336570af302Sopenharmony_ci#endif 337570af302Sopenharmony_ci char *base = __mmap(0, len, PROT_READ|PROT_WRITE, 338570af302Sopenharmony_ci MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 339570af302Sopenharmony_ci if (base == (void *)-1) return 0; 340570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 341570af302Sopenharmony_ci if (g_enable_check) { 342570af302Sopenharmony_ci if (mprotect(base, PAGE_SIZE, PROT_NONE) || 343570af302Sopenharmony_ci mprotect(base + len - PAGE_SIZE, PAGE_SIZE, PROT_NONE)) { 344570af302Sopenharmony_ci printf("%s %d, mprotect failed, err: %s!\n", __func__, __LINE__, strerror(errno)); 345570af302Sopenharmony_ci } 346570af302Sopenharmony_ci base += PAGE_SIZE; 347570af302Sopenharmony_ci } 348570af302Sopenharmony_ci#endif 349570af302Sopenharmony_ci c = (void *)(base + SIZE_ALIGN - OVERHEAD); 350570af302Sopenharmony_ci c->csize = len - (SIZE_ALIGN - OVERHEAD); 351570af302Sopenharmony_ci c->psize = SIZE_ALIGN - OVERHEAD; 352570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 353570af302Sopenharmony_ci if (g_enable_check) { 354570af302Sopenharmony_ci c->csize -= PAGE_SIZE << 1; 355570af302Sopenharmony_ci insert_node(CHUNK_TO_MEM(c), CHUNK_SIZE(c)); 356570af302Sopenharmony_ci } 357570af302Sopenharmony_ci#endif 358570af302Sopenharmony_ci return CHUNK_TO_MEM(c); 359570af302Sopenharmony_ci } 360570af302Sopenharmony_ci 361570af302Sopenharmony_ci i = bin_index_up(n); 362570af302Sopenharmony_ci if (i<63 && (mal.binmap & (1ULL<<i))) { 363570af302Sopenharmony_ci lock_bin(i); 364570af302Sopenharmony_ci c = mal.bins[i].head; 365570af302Sopenharmony_ci if (c != BIN_TO_CHUNK(i) && CHUNK_SIZE(c)-n <= DONTCARE) { 366570af302Sopenharmony_ci unbin(c, i); 367570af302Sopenharmony_ci unlock_bin(i); 368570af302Sopenharmony_ci return CHUNK_TO_MEM(c); 369570af302Sopenharmony_ci } 370570af302Sopenharmony_ci unlock_bin(i); 371570af302Sopenharmony_ci } 372570af302Sopenharmony_ci lock(mal.split_merge_lock); 373570af302Sopenharmony_ci for (mask = mal.binmap & -(1ULL<<i); mask; mask -= (mask&-mask)) { 374570af302Sopenharmony_ci j = first_set(mask); 375570af302Sopenharmony_ci lock_bin(j); 376570af302Sopenharmony_ci c = mal.bins[j].head; 377570af302Sopenharmony_ci if (c != BIN_TO_CHUNK(j)) { 378570af302Sopenharmony_ci unbin(c, j); 379570af302Sopenharmony_ci unlock_bin(j); 380570af302Sopenharmony_ci break; 381570af302Sopenharmony_ci } 382570af302Sopenharmony_ci unlock_bin(j); 383570af302Sopenharmony_ci } 384570af302Sopenharmony_ci if (!mask) { 385570af302Sopenharmony_ci c = expand_heap(n); 386570af302Sopenharmony_ci if (!c) { 387570af302Sopenharmony_ci unlock(mal.split_merge_lock); 388570af302Sopenharmony_ci return 0; 389570af302Sopenharmony_ci } 390570af302Sopenharmony_ci } 391570af302Sopenharmony_ci trim(c, n); 392570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 393570af302Sopenharmony_ci if (g_enable_check) { 394570af302Sopenharmony_ci insert_node(CHUNK_TO_MEM(c), CHUNK_SIZE(c)); 395570af302Sopenharmony_ci } 396570af302Sopenharmony_ci#endif 397570af302Sopenharmony_ci unlock(mal.split_merge_lock); 398570af302Sopenharmony_ci return CHUNK_TO_MEM(c); 399570af302Sopenharmony_ci} 400570af302Sopenharmony_ci 401570af302Sopenharmony_ciint __malloc_allzerop(void *p) 402570af302Sopenharmony_ci{ 403570af302Sopenharmony_ci return IS_MMAPPED(MEM_TO_CHUNK(p)); 404570af302Sopenharmony_ci} 405570af302Sopenharmony_ci 406570af302Sopenharmony_civoid *realloc(void *p, size_t n) 407570af302Sopenharmony_ci{ 408570af302Sopenharmony_ci struct chunk *self, *next; 409570af302Sopenharmony_ci size_t n0, n1; 410570af302Sopenharmony_ci void *new; 411570af302Sopenharmony_ci 412570af302Sopenharmony_ci if (!p) return malloc(n); 413570af302Sopenharmony_ci 414570af302Sopenharmony_ci if (adjust_size(&n) < 0) return 0; 415570af302Sopenharmony_ci 416570af302Sopenharmony_ci self = MEM_TO_CHUNK(p); 417570af302Sopenharmony_ci n1 = n0 = CHUNK_SIZE(self); 418570af302Sopenharmony_ci 419570af302Sopenharmony_ci if (n<=n0 && n0-n<=DONTCARE) return p; 420570af302Sopenharmony_ci 421570af302Sopenharmony_ci if (IS_MMAPPED(self)) { 422570af302Sopenharmony_ci size_t extra = self->psize; 423570af302Sopenharmony_ci char *base = (char *)self - extra; 424570af302Sopenharmony_ci size_t oldlen = n0 + extra; 425570af302Sopenharmony_ci size_t newlen = n + extra; 426570af302Sopenharmony_ci /* Crash on realloc of freed chunk */ 427570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 428570af302Sopenharmony_ci if (extra & 1) { 429570af302Sopenharmony_ci if (g_enable_check) { 430570af302Sopenharmony_ci get_free_trace(CHUNK_TO_MEM(self)); 431570af302Sopenharmony_ci a_crash(); 432570af302Sopenharmony_ci } else { 433570af302Sopenharmony_ci a_crash(); 434570af302Sopenharmony_ci } 435570af302Sopenharmony_ci } 436570af302Sopenharmony_ci#else 437570af302Sopenharmony_ci if (extra & 1) a_crash(); 438570af302Sopenharmony_ci#endif 439570af302Sopenharmony_ci if (newlen < PAGE_SIZE && (new = malloc(n-OVERHEAD))) { 440570af302Sopenharmony_ci n0 = n; 441570af302Sopenharmony_ci goto copy_free_ret; 442570af302Sopenharmony_ci } 443570af302Sopenharmony_ci newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE; 444570af302Sopenharmony_ci if (oldlen == newlen) return p; 445570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 446570af302Sopenharmony_ci if (g_enable_check) { 447570af302Sopenharmony_ci goto copy_realloc; 448570af302Sopenharmony_ci } 449570af302Sopenharmony_ci#endif 450570af302Sopenharmony_ci base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE); 451570af302Sopenharmony_ci if (base == (void *)-1) 452570af302Sopenharmony_ci goto copy_realloc; 453570af302Sopenharmony_ci self = (void *)(base + extra); 454570af302Sopenharmony_ci self->csize = newlen - extra; 455570af302Sopenharmony_ci return CHUNK_TO_MEM(self); 456570af302Sopenharmony_ci } 457570af302Sopenharmony_ci 458570af302Sopenharmony_ci next = NEXT_CHUNK(self); 459570af302Sopenharmony_ci 460570af302Sopenharmony_ci /* Crash on corrupted footer (likely from buffer overflow) */ 461570af302Sopenharmony_ci if (next->psize != self->csize) a_crash(); 462570af302Sopenharmony_ci 463570af302Sopenharmony_ci if (n < n0) { 464570af302Sopenharmony_ci int i = bin_index_up(n); 465570af302Sopenharmony_ci int j = bin_index(n0); 466570af302Sopenharmony_ci if (i<j && (mal.binmap & (1ULL << i))) 467570af302Sopenharmony_ci goto copy_realloc; 468570af302Sopenharmony_ci struct chunk *split = (void *)((char *)self + n); 469570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 470570af302Sopenharmony_ci lock(g_mem_lock); 471570af302Sopenharmony_ci#endif 472570af302Sopenharmony_ci self->csize = split->psize = n | C_INUSE; 473570af302Sopenharmony_ci split->csize = next->psize = n0-n | C_INUSE; 474570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 475570af302Sopenharmony_ci calculate_checksum(self, next); 476570af302Sopenharmony_ci unlock(g_mem_lock); 477570af302Sopenharmony_ci#endif 478570af302Sopenharmony_ci __bin_chunk(split); 479570af302Sopenharmony_ci return CHUNK_TO_MEM(self); 480570af302Sopenharmony_ci } 481570af302Sopenharmony_ci 482570af302Sopenharmony_ci lock(mal.split_merge_lock); 483570af302Sopenharmony_ci 484570af302Sopenharmony_ci size_t nsize = next->csize & C_INUSE ? 0 : CHUNK_SIZE(next); 485570af302Sopenharmony_ci if (n0+nsize >= n) { 486570af302Sopenharmony_ci int i = bin_index(nsize); 487570af302Sopenharmony_ci lock_bin(i); 488570af302Sopenharmony_ci if (!(next->csize & C_INUSE)) { 489570af302Sopenharmony_ci unbin(next, i); 490570af302Sopenharmony_ci unlock_bin(i); 491570af302Sopenharmony_ci next = NEXT_CHUNK(next); 492570af302Sopenharmony_ci self->csize = next->psize = n0+nsize | C_INUSE; 493570af302Sopenharmony_ci trim(self, n); 494570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 495570af302Sopenharmony_ci if (g_enable_check) { 496570af302Sopenharmony_ci int status = delete_node(p); 497570af302Sopenharmony_ci if (status != 0) { 498570af302Sopenharmony_ci get_free_trace(CHUNK_TO_MEM(self)); 499570af302Sopenharmony_ci a_crash(); 500570af302Sopenharmony_ci } 501570af302Sopenharmony_ci insert_node(CHUNK_TO_MEM(self), CHUNK_SIZE(self)); 502570af302Sopenharmony_ci } 503570af302Sopenharmony_ci#endif 504570af302Sopenharmony_ci unlock(mal.split_merge_lock); 505570af302Sopenharmony_ci return CHUNK_TO_MEM(self); 506570af302Sopenharmony_ci } 507570af302Sopenharmony_ci unlock_bin(i); 508570af302Sopenharmony_ci } 509570af302Sopenharmony_ci unlock(mal.split_merge_lock); 510570af302Sopenharmony_ci 511570af302Sopenharmony_cicopy_realloc: 512570af302Sopenharmony_ci /* As a last resort, allocate a new chunk and copy to it. */ 513570af302Sopenharmony_ci new = malloc(n-OVERHEAD); 514570af302Sopenharmony_ci if (!new) return 0; 515570af302Sopenharmony_cicopy_free_ret: 516570af302Sopenharmony_ci memcpy(new, p, (n<n0 ? n : n0) - OVERHEAD); 517570af302Sopenharmony_ci free(CHUNK_TO_MEM(self)); 518570af302Sopenharmony_ci return new; 519570af302Sopenharmony_ci} 520570af302Sopenharmony_ci 521570af302Sopenharmony_civoid __bin_chunk(struct chunk *self) 522570af302Sopenharmony_ci{ 523570af302Sopenharmony_ci struct chunk *next = NEXT_CHUNK(self); 524570af302Sopenharmony_ci 525570af302Sopenharmony_ci /* Crash on corrupted footer (likely from buffer overflow) */ 526570af302Sopenharmony_ci if (next->psize != self->csize) a_crash(); 527570af302Sopenharmony_ci 528570af302Sopenharmony_ci lock(mal.split_merge_lock); 529570af302Sopenharmony_ci 530570af302Sopenharmony_ci size_t osize = CHUNK_SIZE(self), size = osize; 531570af302Sopenharmony_ci 532570af302Sopenharmony_ci /* Since we hold split_merge_lock, only transition from free to 533570af302Sopenharmony_ci * in-use can race; in-use to free is impossible */ 534570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 535570af302Sopenharmony_ci lock(g_mem_lock); 536570af302Sopenharmony_ci#endif 537570af302Sopenharmony_ci size_t psize = self->psize & C_INUSE ? 0 : CHUNK_PSIZE(self); 538570af302Sopenharmony_ci size_t nsize = next->csize & C_INUSE ? 0 : CHUNK_SIZE(next); 539570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 540570af302Sopenharmony_ci calculate_checksum(self, next); 541570af302Sopenharmony_ci unlock(g_mem_lock); 542570af302Sopenharmony_ci#endif 543570af302Sopenharmony_ci 544570af302Sopenharmony_ci if (psize) { 545570af302Sopenharmony_ci int i = bin_index(psize); 546570af302Sopenharmony_ci lock_bin(i); 547570af302Sopenharmony_ci if (!(self->psize & C_INUSE)) { 548570af302Sopenharmony_ci struct chunk *prev = PREV_CHUNK(self); 549570af302Sopenharmony_ci unbin(prev, i); 550570af302Sopenharmony_ci self = prev; 551570af302Sopenharmony_ci size += psize; 552570af302Sopenharmony_ci } 553570af302Sopenharmony_ci unlock_bin(i); 554570af302Sopenharmony_ci } 555570af302Sopenharmony_ci if (nsize) { 556570af302Sopenharmony_ci int i = bin_index(nsize); 557570af302Sopenharmony_ci lock_bin(i); 558570af302Sopenharmony_ci if (!(next->csize & C_INUSE)) { 559570af302Sopenharmony_ci unbin(next, i); 560570af302Sopenharmony_ci next = NEXT_CHUNK(next); 561570af302Sopenharmony_ci size += nsize; 562570af302Sopenharmony_ci } 563570af302Sopenharmony_ci unlock_bin(i); 564570af302Sopenharmony_ci } 565570af302Sopenharmony_ci 566570af302Sopenharmony_ci int i = bin_index(size); 567570af302Sopenharmony_ci lock_bin(i); 568570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 569570af302Sopenharmony_ci lock(g_mem_lock); 570570af302Sopenharmony_ci#endif 571570af302Sopenharmony_ci self->csize = size; 572570af302Sopenharmony_ci next->psize = size; 573570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 574570af302Sopenharmony_ci calculate_checksum(self, next); 575570af302Sopenharmony_ci unlock(g_mem_lock); 576570af302Sopenharmony_ci#endif 577570af302Sopenharmony_ci bin_chunk(self, i); 578570af302Sopenharmony_ci unlock(mal.split_merge_lock); 579570af302Sopenharmony_ci 580570af302Sopenharmony_ci /* Replace middle of large chunks with fresh zero pages */ 581570af302Sopenharmony_ci if (size > RECLAIM && (size^(size-osize)) > size-osize) { 582570af302Sopenharmony_ci uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE; 583570af302Sopenharmony_ci uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE; 584570af302Sopenharmony_ci int e = errno; 585570af302Sopenharmony_ci#ifndef __LITEOS_A__ 586570af302Sopenharmony_ci __madvise((void *)a, b-a, MADV_DONTNEED); 587570af302Sopenharmony_ci#else 588570af302Sopenharmony_ci __mmap((void *)a, b-a, PROT_READ|PROT_WRITE, 589570af302Sopenharmony_ci MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); 590570af302Sopenharmony_ci#endif 591570af302Sopenharmony_ci errno = e; 592570af302Sopenharmony_ci } 593570af302Sopenharmony_ci 594570af302Sopenharmony_ci unlock_bin(i); 595570af302Sopenharmony_ci} 596570af302Sopenharmony_ci 597570af302Sopenharmony_cistatic void unmap_chunk(struct chunk *self) 598570af302Sopenharmony_ci{ 599570af302Sopenharmony_ci size_t extra = self->psize; 600570af302Sopenharmony_ci char *base = (char *)self - extra; 601570af302Sopenharmony_ci size_t len = CHUNK_SIZE(self) + extra; 602570af302Sopenharmony_ci /* Crash on double free */ 603570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 604570af302Sopenharmony_ci if (extra & 1) { 605570af302Sopenharmony_ci if (g_enable_check) { 606570af302Sopenharmony_ci get_free_trace(CHUNK_TO_MEM(self)); 607570af302Sopenharmony_ci a_crash(); 608570af302Sopenharmony_ci } else { 609570af302Sopenharmony_ci a_crash(); 610570af302Sopenharmony_ci } 611570af302Sopenharmony_ci } 612570af302Sopenharmony_ci if (g_enable_check) { 613570af302Sopenharmony_ci base -= PAGE_SIZE; 614570af302Sopenharmony_ci len += PAGE_SIZE << 1; 615570af302Sopenharmony_ci } 616570af302Sopenharmony_ci#else 617570af302Sopenharmony_ci if (extra & 1) a_crash(); 618570af302Sopenharmony_ci#endif 619570af302Sopenharmony_ci int e = errno; 620570af302Sopenharmony_ci __munmap(base, len); 621570af302Sopenharmony_ci errno = e; 622570af302Sopenharmony_ci} 623570af302Sopenharmony_ci 624570af302Sopenharmony_civoid free(void *p) 625570af302Sopenharmony_ci{ 626570af302Sopenharmony_ci if (!p) return; 627570af302Sopenharmony_ci 628570af302Sopenharmony_ci struct chunk *self = MEM_TO_CHUNK(p); 629570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 630570af302Sopenharmony_ci if (g_enable_check) { 631570af302Sopenharmony_ci if (!IS_MMAPPED(self)) { 632570af302Sopenharmony_ci check_chunk_integrity(self); 633570af302Sopenharmony_ci } 634570af302Sopenharmony_ci int status = delete_node(p); 635570af302Sopenharmony_ci if (status != 0) { 636570af302Sopenharmony_ci get_free_trace(p); 637570af302Sopenharmony_ci a_crash(); 638570af302Sopenharmony_ci } 639570af302Sopenharmony_ci } 640570af302Sopenharmony_ci#endif 641570af302Sopenharmony_ci 642570af302Sopenharmony_ci if (IS_MMAPPED(self)) 643570af302Sopenharmony_ci unmap_chunk(self); 644570af302Sopenharmony_ci else { 645570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 646570af302Sopenharmony_ci if (g_enable_check) { 647570af302Sopenharmony_ci insert_free_tail(self); 648570af302Sopenharmony_ci if (g_recycle_size >= RECYCLE_SIZE_MAX) { 649570af302Sopenharmony_ci clean_recycle_list(false); 650570af302Sopenharmony_ci return; 651570af302Sopenharmony_ci } 652570af302Sopenharmony_ci if (g_recycle_num < RECYCLE_MAX) { 653570af302Sopenharmony_ci return; 654570af302Sopenharmony_ci } 655570af302Sopenharmony_ci self = get_free_head(); 656570af302Sopenharmony_ci } 657570af302Sopenharmony_ci#endif 658570af302Sopenharmony_ci __bin_chunk(self); 659570af302Sopenharmony_ci } 660570af302Sopenharmony_ci} 661570af302Sopenharmony_ci 662570af302Sopenharmony_civoid __malloc_donate(char *start, char *end) 663570af302Sopenharmony_ci{ 664570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 665570af302Sopenharmony_ci size_t align_start_up = (SIZE_ALIGN-1) & (-(uintptr_t)start - BLOCK_HEAD); 666570af302Sopenharmony_ci#else 667570af302Sopenharmony_ci size_t align_start_up = (SIZE_ALIGN-1) & (-(uintptr_t)start - OVERHEAD); 668570af302Sopenharmony_ci#endif 669570af302Sopenharmony_ci size_t align_end_down = (SIZE_ALIGN-1) & (uintptr_t)end; 670570af302Sopenharmony_ci 671570af302Sopenharmony_ci /* Getting past this condition ensures that the padding for alignment 672570af302Sopenharmony_ci * and header overhead will not overflow and will leave a nonzero 673570af302Sopenharmony_ci * multiple of SIZE_ALIGN bytes between start and end. */ 674570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 675570af302Sopenharmony_ci if (end - start <= BLOCK_HEAD + align_start_up + align_end_down) 676570af302Sopenharmony_ci return; 677570af302Sopenharmony_ci start += align_start_up + BLOCK_HEAD; 678570af302Sopenharmony_ci#else 679570af302Sopenharmony_ci if (end - start <= OVERHEAD + align_start_up + align_end_down) 680570af302Sopenharmony_ci return; 681570af302Sopenharmony_ci start += align_start_up + OVERHEAD; 682570af302Sopenharmony_ci#endif 683570af302Sopenharmony_ci end -= align_end_down; 684570af302Sopenharmony_ci 685570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 686570af302Sopenharmony_ci lock(g_mem_lock); 687570af302Sopenharmony_ci#endif 688570af302Sopenharmony_ci struct chunk *c = MEM_TO_CHUNK(start), *n = MEM_TO_CHUNK(end); 689570af302Sopenharmony_ci c->psize = n->csize = C_INUSE; 690570af302Sopenharmony_ci c->csize = n->psize = C_INUSE | (end-start); 691570af302Sopenharmony_ci#ifdef __LITEOS_DEBUG__ 692570af302Sopenharmony_ci calculate_checksum(c, n); 693570af302Sopenharmony_ci insert_block_list(c); 694570af302Sopenharmony_ci unlock(g_mem_lock); 695570af302Sopenharmony_ci#endif 696570af302Sopenharmony_ci __bin_chunk(c); 697570af302Sopenharmony_ci} 698570af302Sopenharmony_ci 699570af302Sopenharmony_civoid __malloc_atfork(int who) 700570af302Sopenharmony_ci{ 701570af302Sopenharmony_ci if (who<0) { 702570af302Sopenharmony_ci lock(mal.split_merge_lock); 703570af302Sopenharmony_ci for (int i=0; i<64; i++) 704570af302Sopenharmony_ci lock(mal.bins[i].lock); 705570af302Sopenharmony_ci } else if (!who) { 706570af302Sopenharmony_ci for (int i=0; i<64; i++) 707570af302Sopenharmony_ci unlock(mal.bins[i].lock); 708570af302Sopenharmony_ci unlock(mal.split_merge_lock); 709570af302Sopenharmony_ci } else { 710570af302Sopenharmony_ci for (int i=0; i<64; i++) 711570af302Sopenharmony_ci mal.bins[i].lock[0] = mal.bins[i].lock[1] = 0; 712570af302Sopenharmony_ci mal.split_merge_lock[1] = 0; 713570af302Sopenharmony_ci mal.split_merge_lock[0] = 0; 714570af302Sopenharmony_ci } 715570af302Sopenharmony_ci} 716