forked from aligrudi/neatlibc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
malloc.c
97 lines (88 loc) · 1.98 KB
/
malloc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define PGSIZE 4096
#define PGMASK (PGSIZE - 1)
#define MSETMAX 4096
#define MSETLEN (1 << 15)
/* placed at the beginning of regions for small allocations */
struct mset {
int refs; /* number of allocations */
int size; /* remaining size */
};
/* placed before each small allocation */
struct mhdr {
int moff; /* mset offset */
int size; /* allocation size */
};
static struct mset *pool;
static int mk_pool(void)
{
if (pool && !pool->refs) {
pool->size = sizeof(*pool);
return 0;
}
pool = mmap(NULL, MSETLEN, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (pool == MAP_FAILED) {
pool = NULL;
return 1;
}
pool->size = sizeof(*pool);
pool->refs = 0;
return 0;
}
void *malloc(long n)
{
void *m;
if (n >= MSETMAX) {
m = mmap(NULL, n + PGSIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (m == MAP_FAILED)
return NULL;
*(long *) m = n + PGSIZE; /* store length in the first page */
return m + PGSIZE;
}
if (!pool || n + sizeof(struct mhdr) > MSETLEN - pool->size)
if (mk_pool())
return NULL;
m = (void *) pool + pool->size;
((struct mhdr *) m)->moff = pool->size;
((struct mhdr *) m)->size = n;
pool->refs++;
pool->size += (n + sizeof(struct mhdr) + 7) & ~7;
if (!((unsigned long) (pool + pool->size + sizeof(struct mhdr)) & PGMASK))
pool->size += sizeof(long);
return m + sizeof(struct mhdr);
}
void free(void *v)
{
if (!v)
return;
if ((unsigned long) v & PGMASK) {
struct mhdr *mhdr = v - sizeof(struct mhdr);
struct mset *mset = (void *) mhdr - mhdr->moff;
mset->refs--;
if (!mset->refs && mset != pool)
munmap(mset, mset->size);
} else {
munmap(v - PGSIZE, *(long *) (v - PGSIZE));
}
}
void *calloc(long n, long sz)
{
void *r = malloc(n * sz);
if (r)
memset(r, 0, n * sz);
return r;
}
void *realloc(void *v, long sz)
{
void *r = malloc(sz);
if (r) {
struct mhdr *m = v - sizeof(*m);
memcpy(r, v, m->size);
free(v);
}
return r;
}