-
Notifications
You must be signed in to change notification settings - Fork 12
/
sm_malloc.c
108 lines (97 loc) · 2.38 KB
/
sm_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
98
99
100
101
102
103
104
105
106
107
108
/*
* This file is a part of SMalloc.
* SMalloc is MIT licensed.
* Copyright (c) 2017 Andrey Rys.
*/
#include "smalloc_i.h"
void *sm_malloc_pool(struct smalloc_pool *spool, size_t n)
{
struct smalloc_hdr *basehdr, *shdr, *dhdr;
char *s;
int found;
size_t x;
again: if (!smalloc_verify_pool(spool)) {
errno = EINVAL;
return NULL;
}
if (n == 0) n++; /* return a block successfully */
if (n > SIZE_MAX
|| n > (spool->pool_size - HEADER_SZ)) goto oom;
shdr = basehdr = (struct smalloc_hdr *)spool->pool;
while (CHAR_PTR(shdr)-CHAR_PTR(basehdr) < spool->pool_size) {
/*
* Already allocated block.
* Skip it by jumping over it.
*/
if (smalloc_is_alloc(spool, shdr)) {
s = CHAR_PTR(HEADER_TO_USER(shdr));
s += shdr->rsz + HEADER_SZ;
shdr = HEADER_PTR(s);
continue;
}
/*
* Free blocks ahead!
* Do a second search over them to find out if they're
* really large enough to fit the new allocation.
*/
else {
dhdr = shdr; found = 0;
while (CHAR_PTR(dhdr)-CHAR_PTR(basehdr) < spool->pool_size) {
/* pre calculate free block size */
x = CHAR_PTR(dhdr)-CHAR_PTR(shdr);
/*
* ugh, found next allocated block.
* skip this candidate then.
*/
if (smalloc_is_alloc(spool, dhdr))
goto allocblock;
/*
* did not see allocated block yet,
* but this free block is of enough size
* - finally, use it.
*/
if (n + HEADER_SZ <= x) {
x -= HEADER_SZ;
found = 1;
goto outfound;
}
dhdr++;
}
outfound: if (found) {
uintptr_t tag;
/* allocate and return this block */
shdr->rsz = x;
shdr->usz = n;
shdr->tag = tag = smalloc_mktag(shdr);
if (spool->do_zero) memset(HEADER_TO_USER(shdr), 0, shdr->rsz);
s = CHAR_PTR(HEADER_TO_USER(shdr));
s += shdr->usz;
for (x = 0;
x < sizeof(struct smalloc_hdr);
x += sizeof(uintptr_t)) {
tag = smalloc_uinthash(tag);
memcpy(s+x, &tag, sizeof(uintptr_t));
}
memset(s+x, 0xff, shdr->rsz - shdr->usz);
return HEADER_TO_USER(shdr);
}
/* continue first search for next free block */
allocblock: shdr = dhdr;
continue;
}
shdr++;
}
oom: if (spool->oomfn) {
x = spool->oomfn(spool, n);
if (x > spool->pool_size) {
spool->pool_size = x;
if (sm_align_pool(spool)) goto again;
}
}
errno = ENOMEM;
return NULL;
}
void *sm_malloc(size_t n)
{
return sm_malloc_pool(&smalloc_curr_pool, n);
}