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
|
#include "mempool.h"
#include <stdlib.h>
#include <string.h>
#define NO_BLOCK ((size_t)-1)
static inline size_t min(size_t a, size_t b) { return a < b ? a : b; }
/// Initialize the free list.
/// All of the blocks in the pool are assumed free.
static void init_free_list(mempool* pool) {
assert(pool);
for (size_t i = 0; i < pool->num_blocks - 1; ++i) {
pool->block_info[i].next = i + 1;
}
pool->block_info[pool->num_blocks - 1].next = NO_BLOCK;
}
bool mempool_make_(
mempool* pool, BlockInfo* block_info, void* blocks, size_t num_blocks,
size_t block_size_bytes) {
assert(pool);
assert((block_info && blocks) || (!block_info && !blocks));
assert(num_blocks >= 1);
pool->block_size_bytes = block_size_bytes;
pool->num_blocks = num_blocks;
pool->head = 0;
// Initialize blocks and block info.
if (!block_info) {
block_info = calloc(num_blocks, sizeof(BlockInfo));
blocks = calloc(num_blocks, block_size_bytes);
pool->dynamic = true;
if ((block_info == 0) || (blocks == 0)) {
return false;
}
} else {
memset(blocks, 0, num_blocks * block_size_bytes);
memset(block_info, 0, num_blocks * sizeof(BlockInfo));
pool->dynamic = false;
}
pool->block_info = block_info;
pool->blocks = blocks;
init_free_list(pool);
return true;
}
void mempool_del_(mempool* pool) {
assert(pool);
if (pool->dynamic) {
if (pool->block_info) {
free(pool->block_info);
pool->block_info = 0;
}
if (pool->blocks) {
free(pool->blocks);
pool->blocks = 0;
}
}
}
void mempool_clear_(mempool* pool) {
assert(pool);
pool->head = 0;
memset(pool->blocks, 0, pool->num_blocks * pool->block_size_bytes);
memset(pool->block_info, 0, pool->num_blocks * sizeof(BlockInfo));
init_free_list(pool);
}
void* mempool_alloc_(mempool* pool) {
assert(pool);
if (pool->head == NO_BLOCK) {
return 0;
}
// Allocate the block.
BlockInfo* head = &pool->block_info[pool->head];
void* block = &pool->blocks[pool->head * pool->block_size_bytes];
head->used = true;
pool->head = head->next;
return block;
}
void mempool_free_(mempool* pool, void** block_ptr) {
assert(pool);
assert(block_ptr);
const size_t block_index =
((uint8_t*)*block_ptr - pool->blocks) / pool->block_size_bytes;
assert(block_index < pool->num_blocks);
BlockInfo* info = &pool->block_info[block_index];
// Disallow double-frees.
assert(info->used);
// Zero out the block so that we don't get stray values the next time it is
// allocated.
memset(*block_ptr, 0, pool->block_size_bytes);
// Free the block and add it to the head of the free list.
info->used = false;
info->next = pool->head;
pool->head = block_index;
*block_ptr = 0;
}
void* mempool_get_block_(const mempool* pool, size_t block_index) {
assert(pool);
assert(block_index < pool->num_blocks);
assert(pool->block_info[block_index].used);
return pool->blocks + block_index * pool->block_size_bytes;
}
size_t mempool_get_block_index_(const mempool* pool, const void* block) {
assert(pool);
const size_t block_byte_index = (const uint8_t*)block - pool->blocks;
assert(block_byte_index % pool->block_size_bytes == 0);
return block_byte_index / pool->block_size_bytes;
}
|