PyCyBase 0.1.8.post4__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cbase/__infra__.pxd +6 -0
- cbase/__init__.pxd +6 -0
- cbase/__init__.py +28 -0
- cbase/allocator_protocol/__infra__.pxd +58 -0
- cbase/allocator_protocol/__init__.pxd +58 -0
- cbase/allocator_protocol/__init__.py +45 -0
- cbase/allocator_protocol/c_allocator_protocol.c +31818 -0
- cbase/allocator_protocol/c_allocator_protocol.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_allocator_protocol.h +352 -0
- cbase/allocator_protocol/c_allocator_protocol.pxd +64 -0
- cbase/allocator_protocol/c_allocator_protocol.pyi +144 -0
- cbase/allocator_protocol/c_allocator_protocol.pyx +209 -0
- cbase/allocator_protocol/c_heap_allocator.c +38144 -0
- cbase/allocator_protocol/c_heap_allocator.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_heap_allocator.h +444 -0
- cbase/allocator_protocol/c_heap_allocator.pxd +97 -0
- cbase/allocator_protocol/c_heap_allocator.pyi +161 -0
- cbase/allocator_protocol/c_heap_allocator.pyx +300 -0
- cbase/allocator_protocol/c_nt_shm_allocator.c +33399 -0
- cbase/allocator_protocol/c_nt_shm_allocator.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_nt_shm_allocator.h +996 -0
- cbase/allocator_protocol/c_nt_shm_allocator.pxd +102 -0
- cbase/allocator_protocol/c_nt_shm_allocator.pyx +223 -0
- cbase/allocator_protocol/c_shm_allocator.h +1168 -0
- cbase/allocator_protocol/c_shm_allocator.pxd +142 -0
- cbase/allocator_protocol/c_shm_allocator.pyi +299 -0
- cbase/allocator_protocol/c_shm_allocator.pyx +442 -0
- cbase/allocator_protocol/c_shm_comp.c +4643 -0
- cbase/allocator_protocol/c_shm_comp.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_shm_comp.h +49 -0
- cbase/allocator_protocol/c_shm_comp.pxd +38 -0
- cbase/allocator_protocol/c_shm_comp.pyx +1 -0
- cbase/backports/__infra__.pxd +17 -0
- cbase/backports/__init__.pxd +17 -0
- cbase/backports/__init__.py +9 -0
- cbase/backports/pydict.h +55 -0
- cbase/backports/pydict.pxd +5 -0
- cbase/backports/pylong.c +9946 -0
- cbase/backports/pylong.cp313-win_amd64.pyd +0 -0
- cbase/backports/pylong.h +79 -0
- cbase/backports/pylong.pxd +23 -0
- cbase/backports/pylong.pyx +61 -0
- cbase/bytemap/__infra__.pxd +42 -0
- cbase/bytemap/__init__.pxd +42 -0
- cbase/bytemap/__init__.py +21 -0
- cbase/bytemap/c_bytemap.c +52076 -0
- cbase/bytemap/c_bytemap.cp313-win_amd64.pyd +0 -0
- cbase/bytemap/c_bytemap.h +867 -0
- cbase/bytemap/c_bytemap.pxd +370 -0
- cbase/bytemap/c_bytemap.pyx +1758 -0
- cbase/bytemap/xxh3.h +55 -0
- cbase/bytemap/xxhash.c +42 -0
- cbase/bytemap/xxhash.h +7487 -0
- cbase/env.c +11109 -0
- cbase/env.cp313-win_amd64.pyd +0 -0
- cbase/env.pxd +8 -0
- cbase/env.pyi +48 -0
- cbase/env.pyx +46 -0
- cbase/includes/cbase/allocator_protocol/c_allocator_protocol.c +31818 -0
- cbase/includes/cbase/allocator_protocol/c_allocator_protocol.h +352 -0
- cbase/includes/cbase/allocator_protocol/c_heap_allocator.c +38144 -0
- cbase/includes/cbase/allocator_protocol/c_heap_allocator.h +444 -0
- cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.c +33399 -0
- cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.h +996 -0
- cbase/includes/cbase/allocator_protocol/c_shm_allocator.h +1168 -0
- cbase/includes/cbase/allocator_protocol/c_shm_comp.c +4643 -0
- cbase/includes/cbase/allocator_protocol/c_shm_comp.h +49 -0
- cbase/includes/cbase/backports/pydict.h +55 -0
- cbase/includes/cbase/backports/pylong.c +9946 -0
- cbase/includes/cbase/backports/pylong.h +79 -0
- cbase/includes/cbase/bytemap/c_bytemap.c +52076 -0
- cbase/includes/cbase/bytemap/c_bytemap.h +867 -0
- cbase/includes/cbase/bytemap/xxh3.h +55 -0
- cbase/includes/cbase/bytemap/xxhash.c +42 -0
- cbase/includes/cbase/bytemap/xxhash.h +7487 -0
- cbase/includes/cbase/env.c +11109 -0
- cbase/includes/cbase/int128.h +81 -0
- cbase/includes/cbase/intern_string/c_intern_string.c +28081 -0
- cbase/includes/cbase/intern_string/c_intern_string.h +614 -0
- cbase/includes/cbase/nt/pthread_nt_compat.h +102 -0
- cbase/includes/cbase/nt/regex_nt_compat.h +133 -0
- cbase/includes/cbase/nt/time_sched_nt_compat.h +32 -0
- cbase/int128.h +81 -0
- cbase/int128.pxd +15 -0
- cbase/intern_string/BENCHMARK.md +157 -0
- cbase/intern_string/__infra__.pxd +11 -0
- cbase/intern_string/__init__.pxd +11 -0
- cbase/intern_string/__init__.py +19 -0
- cbase/intern_string/c_intern_string.c +28081 -0
- cbase/intern_string/c_intern_string.cp313-win_amd64.pyd +0 -0
- cbase/intern_string/c_intern_string.h +614 -0
- cbase/intern_string/c_intern_string.pxd +118 -0
- cbase/intern_string/c_intern_string.pyi +376 -0
- cbase/intern_string/c_intern_string.pyx +765 -0
- cbase/nt/pthread_nt_compat.h +102 -0
- cbase/nt/regex_nt_compat.h +133 -0
- cbase/nt/time_sched_nt_compat.h +32 -0
- pycybase-0.1.8.post4.dist-info/METADATA +180 -0
- pycybase-0.1.8.post4.dist-info/RECORD +101 -0
- pycybase-0.1.8.post4.dist-info/WHEEL +5 -0
- pycybase-0.1.8.post4.dist-info/top_level.txt +1 -0
|
Binary file
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
#ifndef AP_HEAP_C_HEAP_ALLOCATOR_H
|
|
2
|
+
#define AP_HEAP_C_HEAP_ALLOCATOR_H
|
|
3
|
+
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <stddef.h>
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
|
|
10
|
+
#ifdef _WIN32
|
|
11
|
+
#include "cbase/nt/pthread_nt_compat.h"
|
|
12
|
+
#else
|
|
13
|
+
#include <pthread.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
// ========== Configuration ==========
|
|
17
|
+
|
|
18
|
+
#ifndef AP_HEAP_AUTOPAGE_CAPACITY
|
|
19
|
+
#define AP_HEAP_AUTOPAGE_CAPACITY (64 * 1024) /* 64 KiB */
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
#ifndef AP_HEAP_AUTOPAGE_CAPACITY_MAX
|
|
23
|
+
#define AP_HEAP_AUTOPAGE_CAPACITY_MAX (16 * 1024 * 1024) /* 16 MiB */
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
#ifndef AP_HEAP_AUTOPAGE_ALIGNMENT
|
|
27
|
+
#define AP_HEAP_AUTOPAGE_ALIGNMENT (4 * 1024) /* 4 KiB */
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
// ========== Heap Allocator Structs ==========
|
|
31
|
+
|
|
32
|
+
typedef struct heap_memory_block {
|
|
33
|
+
size_t capacity;
|
|
34
|
+
size_t size;
|
|
35
|
+
struct heap_memory_block* next_free;
|
|
36
|
+
struct heap_memory_block* next_allocated;
|
|
37
|
+
struct heap_page* parent_page;
|
|
38
|
+
char buffer[];
|
|
39
|
+
} heap_memory_block;
|
|
40
|
+
|
|
41
|
+
typedef struct heap_page {
|
|
42
|
+
size_t capacity;
|
|
43
|
+
size_t occupied;
|
|
44
|
+
struct heap_allocator* allocator;
|
|
45
|
+
struct heap_page* prev;
|
|
46
|
+
struct heap_memory_block* allocated;
|
|
47
|
+
char buffer[];
|
|
48
|
+
} heap_page;
|
|
49
|
+
|
|
50
|
+
typedef struct heap_allocator {
|
|
51
|
+
pthread_mutex_t lock;
|
|
52
|
+
size_t mapped_pages;
|
|
53
|
+
struct heap_memory_block* free_list;
|
|
54
|
+
struct heap_page* active_page;
|
|
55
|
+
size_t autopage_capacity;
|
|
56
|
+
size_t autopage_capacity_max;
|
|
57
|
+
size_t autopage_alignment;
|
|
58
|
+
} heap_allocator;
|
|
59
|
+
|
|
60
|
+
// ========== Utility Functions ==========
|
|
61
|
+
|
|
62
|
+
static inline size_t c_heap_page_roundup(heap_allocator* allocator, size_t size) {
|
|
63
|
+
return (size + allocator->autopage_alignment - 1) & ~(allocator->autopage_alignment - 1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static inline size_t c_heap_block_roundup(size_t size) {
|
|
67
|
+
return (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static inline void c_heap_page_reclaim(heap_allocator* allocator, heap_page* page) {
|
|
71
|
+
if (!allocator || !page) {
|
|
72
|
+
errno = EINVAL;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
heap_memory_block** prevp = &page->allocated;
|
|
77
|
+
while (*prevp) {
|
|
78
|
+
heap_memory_block* block = *prevp;
|
|
79
|
+
if (block->size != 0) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
*prevp = block->next_allocated;
|
|
84
|
+
block->next_allocated = NULL;
|
|
85
|
+
|
|
86
|
+
heap_memory_block** free_prev = &allocator->free_list;
|
|
87
|
+
while (*free_prev && *free_prev != block) {
|
|
88
|
+
free_prev = &(*free_prev)->next_free;
|
|
89
|
+
}
|
|
90
|
+
if (*free_prev == block) {
|
|
91
|
+
*free_prev = block->next_free;
|
|
92
|
+
}
|
|
93
|
+
block->next_free = NULL;
|
|
94
|
+
|
|
95
|
+
size_t cap_total = block->capacity + sizeof(heap_memory_block);
|
|
96
|
+
if (page->occupied >= cap_total) {
|
|
97
|
+
page->occupied -= cap_total;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ========== Public API Functions ==========
|
|
103
|
+
|
|
104
|
+
static inline heap_page* c_heap_allocator_extend(heap_allocator* allocator, size_t capacity, pthread_mutex_t* lock) {
|
|
105
|
+
if (!allocator) {
|
|
106
|
+
errno = EINVAL;
|
|
107
|
+
return NULL;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
uint8_t locked = 0;
|
|
111
|
+
|
|
112
|
+
if (lock) {
|
|
113
|
+
int ret = pthread_mutex_lock(lock);
|
|
114
|
+
if (ret != 0) {
|
|
115
|
+
errno = ret;
|
|
116
|
+
return NULL;
|
|
117
|
+
}
|
|
118
|
+
locked = 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (capacity == 0) {
|
|
122
|
+
if (!allocator->active_page) {
|
|
123
|
+
capacity = allocator->autopage_capacity;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
size_t prev_cap = allocator->active_page->capacity;
|
|
127
|
+
capacity = prev_cap * 2;
|
|
128
|
+
if (capacity < allocator->autopage_capacity) {
|
|
129
|
+
capacity = allocator->autopage_capacity;
|
|
130
|
+
}
|
|
131
|
+
else if (capacity > allocator->autopage_capacity_max) {
|
|
132
|
+
capacity = allocator->autopage_capacity_max;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
size_t total_capacity = c_heap_page_roundup(allocator, capacity);
|
|
138
|
+
|
|
139
|
+
heap_page* page = (heap_page*) calloc(1, total_capacity);
|
|
140
|
+
|
|
141
|
+
if (!page) {
|
|
142
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
143
|
+
return NULL;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
page->capacity = total_capacity;
|
|
147
|
+
page->occupied = sizeof(heap_page);
|
|
148
|
+
page->allocator = allocator;
|
|
149
|
+
page->allocated = NULL;
|
|
150
|
+
page->prev = allocator->active_page;
|
|
151
|
+
allocator->active_page = page;
|
|
152
|
+
allocator->mapped_pages++;
|
|
153
|
+
|
|
154
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
155
|
+
return page;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static inline heap_allocator* c_heap_allocator_new() {
|
|
159
|
+
heap_allocator* allocator = (heap_allocator*) calloc(1, sizeof(heap_allocator));
|
|
160
|
+
if (!allocator) {
|
|
161
|
+
return NULL;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (pthread_mutex_init(&allocator->lock, NULL) != 0) {
|
|
165
|
+
free(allocator);
|
|
166
|
+
return NULL;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
allocator->mapped_pages = 0;
|
|
170
|
+
allocator->free_list = NULL;
|
|
171
|
+
allocator->active_page = NULL;
|
|
172
|
+
allocator->autopage_capacity = AP_HEAP_AUTOPAGE_CAPACITY;
|
|
173
|
+
allocator->autopage_capacity_max = AP_HEAP_AUTOPAGE_CAPACITY_MAX;
|
|
174
|
+
allocator->autopage_alignment = AP_HEAP_AUTOPAGE_ALIGNMENT;
|
|
175
|
+
|
|
176
|
+
return allocator;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static inline void c_heap_allocator_free(heap_allocator* allocator) {
|
|
180
|
+
if (!allocator) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
heap_page* page = allocator->active_page;
|
|
185
|
+
while (page) {
|
|
186
|
+
heap_page* prev = page->prev;
|
|
187
|
+
free(page);
|
|
188
|
+
page = prev;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
pthread_mutex_destroy(&allocator->lock);
|
|
192
|
+
free(allocator);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static inline void* c_heap_calloc(heap_allocator* allocator, size_t size, pthread_mutex_t* lock) {
|
|
196
|
+
if (!allocator || size == 0) {
|
|
197
|
+
errno = EINVAL;
|
|
198
|
+
return NULL;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
size_t cap_net = c_heap_block_roundup(size);
|
|
202
|
+
size_t overhead = sizeof(heap_memory_block);
|
|
203
|
+
size_t cap_total = cap_net + overhead;
|
|
204
|
+
|
|
205
|
+
uint8_t locked = 0;
|
|
206
|
+
pthread_mutex_t* builtin_lock = &allocator->lock;
|
|
207
|
+
pthread_mutex_t* child_lock = &allocator->lock;
|
|
208
|
+
if (lock) {
|
|
209
|
+
if (lock == builtin_lock) {
|
|
210
|
+
child_lock = NULL;
|
|
211
|
+
}
|
|
212
|
+
int ret = pthread_mutex_lock(lock);
|
|
213
|
+
if (ret != 0) {
|
|
214
|
+
errno = ret;
|
|
215
|
+
return NULL;
|
|
216
|
+
}
|
|
217
|
+
locked = 1;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
child_lock = NULL;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
heap_page* page = allocator->active_page;
|
|
224
|
+
if (!page) {
|
|
225
|
+
size_t target_cap = allocator->autopage_capacity;
|
|
226
|
+
while (target_cap < cap_total + sizeof(heap_page)) {
|
|
227
|
+
target_cap *= 2;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
page = c_heap_allocator_extend(allocator, target_cap, child_lock);
|
|
231
|
+
if (!page) {
|
|
232
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
233
|
+
return NULL;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (page->occupied + cap_total > page->capacity) {
|
|
238
|
+
size_t target_cap = page->capacity;
|
|
239
|
+
|
|
240
|
+
if (target_cap < allocator->autopage_capacity) {
|
|
241
|
+
target_cap = allocator->autopage_capacity;
|
|
242
|
+
}
|
|
243
|
+
else if (target_cap < allocator->autopage_capacity_max) {
|
|
244
|
+
target_cap *= 2;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
while (target_cap < cap_total + sizeof(heap_page)) {
|
|
248
|
+
target_cap *= 2;
|
|
249
|
+
}
|
|
250
|
+
page = c_heap_allocator_extend(allocator, target_cap, child_lock);
|
|
251
|
+
if (!page) {
|
|
252
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
253
|
+
return NULL;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
size_t offset = page->occupied;
|
|
258
|
+
heap_memory_block* block = (heap_memory_block*) ((char*) page + offset);
|
|
259
|
+
block->capacity = cap_net;
|
|
260
|
+
block->size = size;
|
|
261
|
+
block->next_free = NULL;
|
|
262
|
+
|
|
263
|
+
block->parent_page = page;
|
|
264
|
+
block->next_allocated = page->allocated;
|
|
265
|
+
page->allocated = block;
|
|
266
|
+
page->occupied += cap_total;
|
|
267
|
+
|
|
268
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
269
|
+
|
|
270
|
+
memset(block + 1, 0, cap_net);
|
|
271
|
+
return (void*) block->buffer;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
static inline void* c_heap_request(heap_allocator* allocator, size_t size, int scan_all_pages, pthread_mutex_t* lock) {
|
|
275
|
+
if (!allocator || size == 0) {
|
|
276
|
+
errno = EINVAL;
|
|
277
|
+
return NULL;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
size_t cap_net = c_heap_block_roundup(size);
|
|
281
|
+
size_t overhead = sizeof(heap_memory_block);
|
|
282
|
+
size_t cap_total = cap_net + overhead;
|
|
283
|
+
|
|
284
|
+
uint8_t locked = 0;
|
|
285
|
+
pthread_mutex_t* builtin_lock = &allocator->lock;
|
|
286
|
+
pthread_mutex_t* child_lock = &allocator->lock;
|
|
287
|
+
if (lock) {
|
|
288
|
+
if (lock == builtin_lock) {
|
|
289
|
+
child_lock = NULL;
|
|
290
|
+
}
|
|
291
|
+
int ret = pthread_mutex_lock(lock);
|
|
292
|
+
if (ret != 0) {
|
|
293
|
+
errno = ret;
|
|
294
|
+
return NULL;
|
|
295
|
+
}
|
|
296
|
+
locked = 1;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
child_lock = NULL;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
heap_memory_block** prevp = &allocator->free_list;
|
|
303
|
+
heap_memory_block* free_blk = allocator->free_list;
|
|
304
|
+
while (free_blk) {
|
|
305
|
+
if (free_blk->capacity >= cap_net) {
|
|
306
|
+
*prevp = free_blk->next_free;
|
|
307
|
+
free_blk->next_free = NULL;
|
|
308
|
+
free_blk->size = size;
|
|
309
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
310
|
+
memset(free_blk + 1, 0, cap_net);
|
|
311
|
+
return (void*) free_blk->buffer;
|
|
312
|
+
}
|
|
313
|
+
prevp = &free_blk->next_free;
|
|
314
|
+
free_blk = free_blk->next_free;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
heap_page* target_page = NULL;
|
|
318
|
+
if (scan_all_pages) {
|
|
319
|
+
heap_page* iter = allocator->active_page;
|
|
320
|
+
while (iter) {
|
|
321
|
+
if (iter->occupied + cap_total <= iter->capacity) {
|
|
322
|
+
target_page = iter;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
iter = iter->prev;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else if (allocator->active_page) {
|
|
329
|
+
heap_page* meta = allocator->active_page;
|
|
330
|
+
if (meta && meta->occupied + cap_total <= meta->capacity) {
|
|
331
|
+
target_page = allocator->active_page;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (!target_page) {
|
|
336
|
+
heap_page* current = allocator->active_page;
|
|
337
|
+
size_t target_cap;
|
|
338
|
+
|
|
339
|
+
if (!current) {
|
|
340
|
+
target_cap = allocator->autopage_capacity;
|
|
341
|
+
while (target_cap < cap_total + sizeof(heap_page)) {
|
|
342
|
+
target_cap *= 2;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
size_t prev_cap = current->capacity;
|
|
347
|
+
size_t new_cap = prev_cap;
|
|
348
|
+
|
|
349
|
+
if (new_cap < allocator->autopage_capacity) {
|
|
350
|
+
new_cap = allocator->autopage_capacity;
|
|
351
|
+
}
|
|
352
|
+
else if (new_cap < allocator->autopage_capacity_max) {
|
|
353
|
+
new_cap *= 2;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
while (new_cap < cap_total + sizeof(heap_page)) {
|
|
357
|
+
new_cap *= 2;
|
|
358
|
+
}
|
|
359
|
+
target_cap = new_cap;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
target_page = c_heap_allocator_extend(allocator, target_cap, child_lock);
|
|
363
|
+
if (!target_page) {
|
|
364
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
365
|
+
return NULL;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
size_t offset = target_page->occupied;
|
|
370
|
+
heap_memory_block* block = (heap_memory_block*) ((char*) target_page + offset);
|
|
371
|
+
block->capacity = cap_net;
|
|
372
|
+
block->size = size;
|
|
373
|
+
block->next_free = NULL;
|
|
374
|
+
|
|
375
|
+
block->parent_page = target_page;
|
|
376
|
+
block->next_allocated = target_page->allocated;
|
|
377
|
+
target_page->allocated = block;
|
|
378
|
+
|
|
379
|
+
target_page->occupied += cap_total;
|
|
380
|
+
|
|
381
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
382
|
+
|
|
383
|
+
memset(block + 1, 0, cap_net);
|
|
384
|
+
return (void*) block->buffer;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
static inline void c_heap_free(void* ptr, pthread_mutex_t* lock) {
|
|
388
|
+
if (!ptr) {
|
|
389
|
+
errno = EINVAL;
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
heap_memory_block* block = (heap_memory_block*) ((char*) ptr - sizeof(heap_memory_block));
|
|
394
|
+
heap_page* page = block->parent_page;
|
|
395
|
+
if (!page || !page->allocator) {
|
|
396
|
+
errno = EINVAL;
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
heap_allocator* allocator = page->allocator;
|
|
401
|
+
|
|
402
|
+
uint8_t locked = 0;
|
|
403
|
+
if (lock) {
|
|
404
|
+
int ret = pthread_mutex_lock(lock);
|
|
405
|
+
if (ret != 0) {
|
|
406
|
+
errno = ret;
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
locked = 1;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
block->size = 0;
|
|
413
|
+
block->next_free = allocator->free_list;
|
|
414
|
+
allocator->free_list = block;
|
|
415
|
+
|
|
416
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
static inline void c_heap_reclaim(heap_allocator* allocator, pthread_mutex_t* lock) {
|
|
420
|
+
if (!allocator) {
|
|
421
|
+
errno = EINVAL;
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
uint8_t locked = 0;
|
|
426
|
+
if (lock) {
|
|
427
|
+
int ret = pthread_mutex_lock(lock);
|
|
428
|
+
if (ret != 0) {
|
|
429
|
+
errno = ret;
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
locked = 1;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
heap_page* page = allocator->active_page;
|
|
436
|
+
while (page) {
|
|
437
|
+
c_heap_page_reclaim(allocator, page);
|
|
438
|
+
page = page->prev;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
#endif /* AP_HEAP_C_HEAP_ALLOCATOR_H */
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
|
|
2
|
+
cdef extern from "cbase/allocator_protocol/c_heap_allocator.h":
|
|
3
|
+
const size_t AP_HEAP_AUTOPAGE_CAPACITY
|
|
4
|
+
const size_t AP_HEAP_AUTOPAGE_CAPACITY_MAX
|
|
5
|
+
const size_t AP_HEAP_AUTOPAGE_ALIGNMENT
|
|
6
|
+
|
|
7
|
+
ctypedef struct pthread_mutex_t:
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
ctypedef struct heap_memory_block:
|
|
11
|
+
size_t capacity
|
|
12
|
+
size_t size
|
|
13
|
+
heap_memory_block* next_free
|
|
14
|
+
heap_memory_block* next_allocated
|
|
15
|
+
heap_page* parent_page
|
|
16
|
+
char buffer[]
|
|
17
|
+
|
|
18
|
+
ctypedef struct heap_page:
|
|
19
|
+
size_t capacity
|
|
20
|
+
size_t occupied
|
|
21
|
+
heap_allocator* allocator
|
|
22
|
+
heap_page* prev
|
|
23
|
+
heap_memory_block* allocated
|
|
24
|
+
char buffer[]
|
|
25
|
+
|
|
26
|
+
ctypedef struct heap_allocator:
|
|
27
|
+
pthread_mutex_t lock
|
|
28
|
+
size_t mapped_pages
|
|
29
|
+
heap_memory_block* free_list
|
|
30
|
+
heap_page* active_page
|
|
31
|
+
size_t autopage_capacity
|
|
32
|
+
size_t autopage_capacity_max
|
|
33
|
+
size_t autopage_alignment
|
|
34
|
+
|
|
35
|
+
int pthread_mutex_init(pthread_mutex_t* mutex, void* attr) noexcept nogil
|
|
36
|
+
int pthread_mutex_lock(pthread_mutex_t* mutex) noexcept nogil
|
|
37
|
+
int pthread_mutex_unlock(pthread_mutex_t* mutex) noexcept nogil
|
|
38
|
+
int pthread_mutex_destroy(pthread_mutex_t* mutex) noexcept nogil
|
|
39
|
+
|
|
40
|
+
size_t c_heap_page_roundup(heap_allocator* allocator, size_t size) noexcept nogil
|
|
41
|
+
size_t c_heap_block_roundup(size_t size) noexcept nogil
|
|
42
|
+
void c_heap_page_reclaim(heap_allocator* allocator, heap_page* page) noexcept nogil
|
|
43
|
+
|
|
44
|
+
heap_page* c_heap_allocator_extend(heap_allocator* allocator, size_t capacity, pthread_mutex_t* lock) noexcept nogil
|
|
45
|
+
heap_allocator* c_heap_allocator_new() noexcept nogil
|
|
46
|
+
void c_heap_allocator_free(heap_allocator* allocator) noexcept nogil
|
|
47
|
+
void* c_heap_calloc(heap_allocator* allocator, size_t size, pthread_mutex_t* lock) noexcept nogil
|
|
48
|
+
void* c_heap_request(heap_allocator* allocator, size_t size, int scan_all_pages, pthread_mutex_t* lock) noexcept nogil
|
|
49
|
+
void c_heap_free(void* ptr, pthread_mutex_t* lock) noexcept nogil
|
|
50
|
+
void c_heap_reclaim(heap_allocator* allocator, pthread_mutex_t* lock) noexcept nogil
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
cdef class HeapMemoryPage:
|
|
54
|
+
cdef heap_page* page
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
cdef inline HeapMemoryPage c_from_header(heap_page* header)
|
|
58
|
+
|
|
59
|
+
cpdef void reclaim(self)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
cdef class HeapMemoryBlock:
|
|
63
|
+
cdef heap_memory_block* block
|
|
64
|
+
cdef readonly bint owner
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
cdef inline HeapMemoryBlock c_from_header(heap_memory_block* header, bint owner=?)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
cdef class HeapAllocator:
|
|
71
|
+
cdef heap_allocator* allocator
|
|
72
|
+
cdef readonly bint owner
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
cdef HeapAllocator c_from_header(heap_allocator* header, bint owner=?)
|
|
76
|
+
|
|
77
|
+
cdef inline heap_page* c_extend(self, size_t capacity=?, pthread_mutex_t* lock=?)
|
|
78
|
+
|
|
79
|
+
cdef inline void* c_calloc(self, size_t size, pthread_mutex_t* lock=?)
|
|
80
|
+
|
|
81
|
+
cdef inline void* c_request(self, size_t size, int scan_all_pages=?, pthread_mutex_t* lock=?)
|
|
82
|
+
|
|
83
|
+
cdef inline void c_free(self, void* ptr, pthread_mutex_t* lock=?)
|
|
84
|
+
|
|
85
|
+
cpdef HeapMemoryPage extend(self, size_t capacity=?, bint with_lock=?)
|
|
86
|
+
|
|
87
|
+
cpdef HeapMemoryBlock calloc(self, size_t size, bint with_lock=?)
|
|
88
|
+
|
|
89
|
+
cpdef HeapMemoryBlock request(self, size_t size, bint with_lock=?, bint scan_all_pages=?)
|
|
90
|
+
|
|
91
|
+
cpdef void free(self, HeapMemoryBlock buffer, bint with_lock=?)
|
|
92
|
+
|
|
93
|
+
cpdef void reclaim(self, bint with_lock=?)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
cdef HeapAllocator ALLOCATOR
|
|
97
|
+
cdef heap_allocator* C_ALLOCATOR
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
from collections.abc import Generator
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ValueRange:
|
|
9
|
+
lo: int
|
|
10
|
+
hi: int
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
UINTPTR_MAX = ctypes.c_void_p(-1).value
|
|
14
|
+
uintptr_t = Annotated[int, ValueRange(0, UINTPTR_MAX), ctypes.c_void_p]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class HeapMemoryBlock:
|
|
18
|
+
"""Typed wrapper around an allocator block header."""
|
|
19
|
+
|
|
20
|
+
owner: bool
|
|
21
|
+
|
|
22
|
+
def __init__(self, block: uintptr_t = 0, owner: bool = False) -> None: ...
|
|
23
|
+
|
|
24
|
+
def __repr__(self) -> str: ...
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def size(self) -> int:
|
|
28
|
+
"""Requested payload size in bytes (-1 if uninitialized)."""
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def capacity(self) -> int:
|
|
32
|
+
"""Aligned capacity of the block (-1 if uninitialized)."""
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def next_free(self) -> HeapMemoryBlock | None:
|
|
36
|
+
"""Next entry in the allocator free list, if any."""
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def next_allocated(self) -> HeapMemoryBlock | None:
|
|
40
|
+
"""Next entry in the owning page's allocation list, if any."""
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def parent_page(self) -> HeapMemoryPage | None:
|
|
44
|
+
"""Owning page wrapper, or None when detached."""
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def buffer(self) -> memoryview:
|
|
48
|
+
"""Memoryview of the user buffer."""
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def address(self) -> str | None:
|
|
52
|
+
"""Hex string of the buffer address."""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class HeapMemoryPage:
|
|
56
|
+
"""Represents a single heap-managed page."""
|
|
57
|
+
|
|
58
|
+
def __init__(self, page_addr: uintptr_t = 0) -> None: ...
|
|
59
|
+
|
|
60
|
+
def __repr__(self) -> str: ...
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def from_buffer(cls, buffer_addr: uintptr_t) -> HeapMemoryPage:
|
|
64
|
+
"""Reconstruct a page wrapper from one of its block buffers."""
|
|
65
|
+
|
|
66
|
+
def allocated(self) -> Generator[HeapMemoryBlock]:
|
|
67
|
+
"""Iterate allocated blocks newest-first."""
|
|
68
|
+
|
|
69
|
+
def reclaim(self) -> None:
|
|
70
|
+
"""Best-effort reclaim of freed blocks back to unused space."""
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def capacity(self) -> int:
|
|
74
|
+
"""Total payload capacity of the page in bytes."""
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def occupied(self) -> int:
|
|
78
|
+
"""Currently occupied bytes on the page."""
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def address(self) -> str | None:
|
|
82
|
+
"""Hex string of the page buffer address."""
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def allocator(self) -> HeapAllocator | None:
|
|
86
|
+
"""Owning allocator wrapper, or None."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class HeapAllocator:
|
|
90
|
+
"""Top-level heap allocator."""
|
|
91
|
+
|
|
92
|
+
owner: bool
|
|
93
|
+
|
|
94
|
+
def __init__(self) -> None: ...
|
|
95
|
+
|
|
96
|
+
def __repr__(self) -> str: ...
|
|
97
|
+
|
|
98
|
+
def extend(self, capacity: int = 0, with_lock: bool = True) -> HeapMemoryPage:
|
|
99
|
+
"""Add a page (auto-sized when capacity is 0)."""
|
|
100
|
+
|
|
101
|
+
def calloc(self, size: int, with_lock: bool = True) -> HeapMemoryBlock:
|
|
102
|
+
"""Allocate zeroed memory from the active page (auto-extending)."""
|
|
103
|
+
|
|
104
|
+
def request(
|
|
105
|
+
self,
|
|
106
|
+
size: int,
|
|
107
|
+
with_lock: bool = True,
|
|
108
|
+
scan_all_pages: bool = True,
|
|
109
|
+
) -> HeapMemoryBlock:
|
|
110
|
+
"""Request a zeroed block, optionally scanning older pages."""
|
|
111
|
+
|
|
112
|
+
def free(self, buffer: HeapMemoryBlock, with_lock: bool = True) -> None:
|
|
113
|
+
"""Return a block to the allocator free list."""
|
|
114
|
+
|
|
115
|
+
def reclaim(self, with_lock: bool = True) -> None:
|
|
116
|
+
"""Reclaim freed space across all pages."""
|
|
117
|
+
|
|
118
|
+
def pages(self) -> Generator[HeapMemoryPage]:
|
|
119
|
+
"""Iterate mapped pages newest-first."""
|
|
120
|
+
|
|
121
|
+
def allocated(self) -> Generator[HeapMemoryBlock]:
|
|
122
|
+
"""Iterate allocated blocks across all pages."""
|
|
123
|
+
|
|
124
|
+
def free_list(self) -> Generator[HeapMemoryBlock]:
|
|
125
|
+
"""Iterate the allocator-wide free list."""
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def mapped_pages(self) -> int:
|
|
129
|
+
"""Count of pages currently mapped by the allocator."""
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def active_page(self) -> HeapMemoryPage | None:
|
|
133
|
+
"""Most recently mapped page, if any."""
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def autopage_capacity(self) -> int:
|
|
137
|
+
"""Default capacity for auto-sized pages (read/write)."""
|
|
138
|
+
|
|
139
|
+
@autopage_capacity.setter
|
|
140
|
+
def autopage_capacity(self, value: int) -> None: ...
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def autopage_capacity_max(self) -> int:
|
|
144
|
+
"""Maximum capacity a page can grow to (read/write)."""
|
|
145
|
+
|
|
146
|
+
@autopage_capacity_max.setter
|
|
147
|
+
def autopage_capacity_max(self, value: int) -> None: ...
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def autopage_alignment(self) -> int:
|
|
151
|
+
"""Page alignment in bytes (read/write)."""
|
|
152
|
+
|
|
153
|
+
@autopage_alignment.setter
|
|
154
|
+
def autopage_alignment(self, value: int) -> None: ...
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
ALLOCATOR: HeapAllocator
|
|
158
|
+
|
|
159
|
+
DEFAULT_AUTOPAGE_CAPACITY: int
|
|
160
|
+
MAX_AUTOPAGE_CAPACITY: int
|
|
161
|
+
DEFAULT_AUTOPAGE_ALIGNMENT: int
|