malloc: more compact memory pools
[neatlibc.git] / malloc.c
blob3e6c9ad99f63da7281d836d5f4c45fbb46546093
1 #include <stdlib.h>
2 #include <sys/mman.h>
4 #define PGSIZE 4096
5 #define PGMASK (PGSIZE - 1)
6 #define MSETMAX 4096
7 #define MSETLEN (1 << 15)
9 struct mset {
10 int refs;
11 int size;
14 static struct mset *pool;
16 static int mk_pool(void)
18 if (pool && !pool->refs) {
19 pool->size = sizeof(*pool);
20 return 0;
22 pool = mmap(NULL, MSETLEN, PROT_READ | PROT_WRITE,
23 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
24 if (pool == MAP_FAILED) {
25 pool = NULL;
26 return 1;
28 pool->size = sizeof(*pool);
29 pool->refs = 0;
30 return 0;
33 void *malloc(long n)
35 void *m;
36 if (n >= MSETMAX) {
37 m = mmap(NULL, n + PGSIZE, PROT_READ | PROT_WRITE,
38 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
39 if (m == MAP_FAILED)
40 return NULL;
41 *(long *) m = n + PGSIZE; /* store length in the first page */
42 return m + PGSIZE;
44 if (!pool || MSETLEN - pool->size < n + sizeof(void *))
45 if (mk_pool())
46 return NULL;
47 m = (void *) pool + pool->size;
48 *(void **) m = pool; /* the address of the owning mset */
49 pool->refs++;
50 pool->size += (n + sizeof(void *) + 7) & ~7;
51 if (!((pool + pool->size + sizeof(void *)) & PGMASK))
52 pool->size += sizeof(long);
53 return m + sizeof(void *);
56 void free(void *v)
58 if (!v)
59 return;
60 if (v & PGMASK) {
61 struct mset *mset = *(void **) (v - sizeof(void *));
62 mset->refs--;
63 if (!mset->refs && mset != pool)
64 munmap(mset, mset->size);
65 } else {
66 munmap(v - PGSIZE, *(long *) (v - PGSIZE));