This repository has been archived by the owner on Sep 24, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
alloc.c
148 lines (112 loc) · 3.26 KB
/
alloc.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
141
142
143
144
145
146
147
148
/**
* \file
*
* \internal
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <nyanttp/ny.h>
#include <nyanttp/alloc.h>
#include <nyanttp/const.h>
#include <nyanttp/expect.h>
#include <nyanttp/pure.h>
#include <nyanttp/util.h>
#include <nyanttp/mem.h>
static ny_const size_t max(size_t a, size_t b) {
return a > b ? a : b;
}
static ny_pure void *index(struct ny_alloc const *restrict alloc, uint32_t idx) {
/* Calculate octet offset */
size_t offset = alloc->size * idx;
/* Upper bound */
assert(offset < alloc->memsize);
return alloc->pool + offset;
}
static ny_pure uint32_t pointer(struct ny_alloc const *restrict alloc, void *ptr) {
/* Lower bound */
assert(((uintptr_t) ptr) >= ((uintptr_t) alloc->pool));
/* Calculate octet offset */
size_t offset = ((uintptr_t) ptr) - ((uintptr_t) alloc->pool);
/* Alignment */
assert(offset % alloc->size == 0);
/* Upper bound */
assert(offset + alloc->size <= alloc->memsize);
return offset / alloc->size;
}
int ny_alloc_init(struct ny_alloc *restrict alloc, struct ny *restrict ny,
uint32_t number, uint16_t size) {
assert(alloc);
assert(ny);
assert(number);
assert(size);
int status = -1;
if (unlikely(number > UINT32_C(4194304) || size > UINT16_C(1024))) {
ny_error_set(&ny->error, NY_ERROR_DOMAIN_ERRNO, ERANGE);
goto exit;
}
/* Minimum size of 4 bytes, aligned to word size */
alloc->size = ny_util_align(max(size, sizeof (uint32_t)), sizeof (void *));
/* Size of memory allocation */
alloc->memsize = ny_util_align(number * alloc->size, ny->page_size);
/* Adjust object number to fill up last page */
size_t actual = alloc->memsize / alloc->size;
/* Allocate memory for pool */
alloc->pool = ny_mem_alloc(alloc->memsize);
if (unlikely(!alloc->pool)) {
ny_error_set(&ny->error, NY_ERROR_DOMAIN_ERRNO, errno);
goto exit;
}
#if NY_ALLOC_ADVISE
/* Advise the OS about the access pattern */
posix_madvise(alloc->pool, alloc->memsize,
POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
#endif
/* Initialise free list */
alloc->free = 0;
for (uint_least32_t iter = 0; iter < actual - 1; ++iter)
*(uint32_t *) index(alloc, iter) = iter + 1;
/* Sentinel */
*(uint32_t *) index(alloc, actual - 1) = UINT32_MAX;
status = 0;
exit:
return status;
}
void ny_alloc_destroy(struct ny_alloc *restrict alloc) {
assert(alloc);
assert(alloc->pool);
assert(alloc->memsize);
int _;
/* Free memory pool */
_ = ny_mem_free(alloc->pool, alloc->memsize);
assert(!_);
alloc->pool = NULL;
alloc->memsize = 0;
}
void *ny_alloc_acquire(struct ny_alloc *restrict alloc) {
assert(alloc);
void *object = NULL;
/* Any objects remaining? */
if (likely(alloc->free != UINT32_MAX)) {
/* Pop object from list */
object = index(alloc, alloc->free);
alloc->free = *(uint32_t *) object;
}
return object;
}
void ny_alloc_release(struct ny_alloc *restrict alloc, void *restrict object) {
assert(alloc);
assert(object);
#ifdef NY_DEBUG_ALLOC
/* Attempt to discover double-free situations */
for (uint_least32_t iter = alloc->free; iter != UINT32_MAX;
iter = *(uint32_t *) index(alloc, iter)) {
assert(pointer(alloc, object) != iter);
}
#endif
/* Push object back onto list */
*(uint32_t *) object = alloc->free;
alloc->free = pointer(alloc, object);
}