-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharena.c
140 lines (115 loc) · 2.85 KB
/
arena.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* arena.c - implement arena buffer allocation */
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include "arena.h"
/*
* An arena allocator provides a simple, high-performance memory
* allocator in which blocks allocated from an arena (using
* arenaAlloc()) are not freed individually, but are freed all at
* once in an arenaFree() call.
*/
/*
* Initialize an arena. <blksize> is the default block size; it
* will grow (up to a limit <maxsize>) if allocations are done which are
* bigger than the current blksize over 4 and memory is not immediately
* available in the current block.
* If <backing> is non-null, it points at the address of a the head
* of a simple list of free blocks, to which memory blocks will be
* returned when arenaFree() is called, and from which memory will be
* taken (if available) before resorting to the systmem pool.
*/
void
arenaInit (ARENA * a, size_t blksize, size_t maxsize,
ARENA_BLK ** backing)
{
assert (a != NULL && blksize >= 1024);
a->avail = 0;
a->p = NULL;
a->curblk = NULL;
a->used = NULL;
a->blksize = blksize;
a->maxsize = maxsize;
a->backing = backing;
}
/*
* Allocate a block of size <n> within the arena <a>.
* The memory is not initialized. Blocks may not be individually
* released, but all blocks allocated in a given arena may be
* released at once by calling arenaFree().
*
* Note, arenaAlloc(a, 0) may return NULL.
*/
void *
arenaAlloc (ARENA * a, size_t n)
{
void * buf;
ARENA_BLK * blk;
n = (n + (ARENA_ALIGN - 1)) & ~(ARENA_ALIGN - 1);
if (a->avail >= n) {
buf = a->p;
a->p += n;
a->avail -= n;
return buf;
}
/* the current block is used up */
if (a->curblk != NULL) {
a->curblk->next = a->used;
a->used = a->curblk;
a->curblk = NULL;
a->avail = 0;
}
while (n > a->blksize / 4) {
if (a->blksize * 2 > a->maxsize)
return NULL;
a->blksize = a->blksize * 2;
}
if (a->backing != NULL) {
while ((blk = *a->backing) != NULL) {
*a->backing = blk->next;
if (blk->size >= a->blksize)
goto haveblk;
free (blk);
}
}
if ((blk = malloc (a->blksize)) == NULL)
return NULL;
blk->size = a->blksize;
haveblk:
blk->next = NULL;
a->curblk = blk;
buf = (blk + 1);
a->avail = blk->size - sizeof (*blk) - n;
a->p = (char *)buf + n;
return buf;
}
/* Release all memory blocks held in the arena <a> */
void
arenaFree (ARENA * a)
{
ARENA_BLK * blk;
ARENA_BLK * next;
if (a->curblk != NULL) {
a->curblk->next = a->used;
a->used = a->curblk;
a->curblk = NULL;
a->avail = 0;
}
if ((blk = a->used) == NULL)
return;
if (a->backing != NULL) {
while (blk->next != NULL)
blk = blk->next;
blk->next = *a->backing;
*a->backing = a->used;
a->used = NULL;
return;
}
/* if there's no backing store, release to the system heap */
do {
next = blk->next;
free (blk);
} while ((blk = next) != NULL);
a->used = NULL;
return;
}