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