PyCyBase 0.1.10__cp315-cp315-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 +31 -0
- cbase/allocator_protocol/__infra__.pxd +65 -0
- cbase/allocator_protocol/__init__.pxd +65 -0
- cbase/allocator_protocol/__init__.py +45 -0
- cbase/allocator_protocol/c_allocator_protocol.c +31874 -0
- cbase/allocator_protocol/c_allocator_protocol.cp315-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_allocator_protocol.h +352 -0
- cbase/allocator_protocol/c_allocator_protocol.pxd +66 -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 +38225 -0
- cbase/allocator_protocol/c_heap_allocator.cp315-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_heap_allocator.h +554 -0
- cbase/allocator_protocol/c_heap_allocator.pxd +105 -0
- cbase/allocator_protocol/c_heap_allocator.pyi +161 -0
- cbase/allocator_protocol/c_heap_allocator.pyx +303 -0
- cbase/allocator_protocol/c_nt_shm_allocator.c +33455 -0
- cbase/allocator_protocol/c_nt_shm_allocator.cp315-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_nt_shm_allocator.h +1105 -0
- cbase/allocator_protocol/c_nt_shm_allocator.pxd +110 -0
- cbase/allocator_protocol/c_nt_shm_allocator.pyx +223 -0
- cbase/allocator_protocol/c_shm_allocator.h +1270 -0
- cbase/allocator_protocol/c_shm_allocator.pxd +150 -0
- cbase/allocator_protocol/c_shm_allocator.pyi +299 -0
- cbase/allocator_protocol/c_shm_allocator.pyx +445 -0
- cbase/allocator_protocol/c_shm_comp.c +4654 -0
- cbase/allocator_protocol/c_shm_comp.cp315-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_shm_comp.h +49 -0
- cbase/allocator_protocol/c_shm_comp.pxd +46 -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 +9965 -0
- cbase/backports/pylong.cp315-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 +52151 -0
- cbase/bytemap/c_bytemap.cp315-win_amd64.pyd +0 -0
- cbase/bytemap/c_bytemap.h +867 -0
- cbase/bytemap/c_bytemap.pxd +370 -0
- cbase/bytemap/c_bytemap.pyx +1760 -0
- cbase/bytemap/xxh3.h +55 -0
- cbase/bytemap/xxhash.c +42 -0
- cbase/bytemap/xxhash.h +7487 -0
- cbase/config_view.c +7253 -0
- cbase/config_view.cp315-win_amd64.pyd +0 -0
- cbase/config_view.pyx +85 -0
- cbase/env.c +11120 -0
- cbase/env.cp315-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 +31874 -0
- cbase/includes/cbase/allocator_protocol/c_allocator_protocol.h +352 -0
- cbase/includes/cbase/allocator_protocol/c_heap_allocator.c +38225 -0
- cbase/includes/cbase/allocator_protocol/c_heap_allocator.h +554 -0
- cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.c +33455 -0
- cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.h +1105 -0
- cbase/includes/cbase/allocator_protocol/c_shm_allocator.h +1270 -0
- cbase/includes/cbase/allocator_protocol/c_shm_comp.c +4654 -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 +9965 -0
- cbase/includes/cbase/backports/pylong.h +79 -0
- cbase/includes/cbase/bytemap/c_bytemap.c +52151 -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/config_view.c +7253 -0
- cbase/includes/cbase/env.c +11120 -0
- cbase/includes/cbase/int128.h +81 -0
- cbase/includes/cbase/intern_string/c_intern_string.c +28138 -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 +13 -0
- cbase/intern_string/__init__.pxd +13 -0
- cbase/intern_string/__init__.py +19 -0
- cbase/intern_string/c_intern_string.c +28138 -0
- cbase/intern_string/c_intern_string.cp315-win_amd64.pyd +0 -0
- cbase/intern_string/c_intern_string.h +614 -0
- cbase/intern_string/c_intern_string.pxd +121 -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.10.dist-info/METADATA +190 -0
- pycybase-0.1.10.dist-info/RECORD +105 -0
- pycybase-0.1.10.dist-info/WHEEL +5 -0
- pycybase-0.1.10.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,554 @@
|
|
|
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
|
+
#include <intrin.h>
|
|
13
|
+
#else
|
|
14
|
+
#include <pthread.h>
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
// ========== Configuration ==========
|
|
18
|
+
|
|
19
|
+
#ifndef AP_HEAP_AUTOPAGE_CAPACITY
|
|
20
|
+
#define AP_HEAP_AUTOPAGE_CAPACITY (64 * 1024) /* 64 KiB */
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
#ifndef AP_HEAP_AUTOPAGE_CAPACITY_MAX
|
|
24
|
+
#define AP_HEAP_AUTOPAGE_CAPACITY_MAX (16 * 1024 * 1024) /* 16 MiB */
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
#ifndef AP_HEAP_AUTOPAGE_ALIGNMENT
|
|
28
|
+
#define AP_HEAP_AUTOPAGE_ALIGNMENT (4 * 1024) /* 4 KiB */
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
/* Size-binned free lists: exact 8-byte-granular bins for capacities up to
|
|
32
|
+
* AP_HEAP_EXACT_BIN_COUNT * 8 bytes, pow2-class bins above. */
|
|
33
|
+
#ifndef AP_HEAP_EXACT_BIN_COUNT
|
|
34
|
+
#define AP_HEAP_EXACT_BIN_COUNT 8192 /* capacity <= 64 KiB gets an exact bin */
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
#ifndef AP_HEAP_LARGE_BIN_COUNT
|
|
38
|
+
#define AP_HEAP_LARGE_BIN_COUNT 9 /* pow2-class bins for capacity > 64 KiB */
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
#define AP_HEAP_BIN_COUNT (AP_HEAP_EXACT_BIN_COUNT + AP_HEAP_LARGE_BIN_COUNT + 1)
|
|
42
|
+
|
|
43
|
+
/* Miss-path page scaling cap: page sizes double from the current page up
|
|
44
|
+
* to this cap; a request larger than the cap forces a bigger page.
|
|
45
|
+
* Used only when AP_HEAP_PAGE_FIT_TO_REQUEST is 0. */
|
|
46
|
+
#ifndef AP_HEAP_PAGE_EXTEND_MAX
|
|
47
|
+
#define AP_HEAP_PAGE_EXTEND_MAX (128 * 1024 * 1024) /* 128 MiB */
|
|
48
|
+
#endif
|
|
49
|
+
|
|
50
|
+
/* Miss-path page policy: 0 (default) = capped power-of-2 page scaling
|
|
51
|
+
* (see AP_HEAP_PAGE_EXTEND_MAX); 1 = fit the page to the request (floor
|
|
52
|
+
* = autopage_capacity) so rare bin misses never extend oversized pages. */
|
|
53
|
+
#ifndef AP_HEAP_PAGE_FIT_TO_REQUEST
|
|
54
|
+
#define AP_HEAP_PAGE_FIT_TO_REQUEST 0
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
/* On an exact-bin miss, probe up to this many LARGER exact bins before
|
|
58
|
+
* the page path. A slightly larger block satisfies the request; on free
|
|
59
|
+
* it returns to its own bin (recycling unaffected), and the fragmentation
|
|
60
|
+
* is bounded by the probe range. 0 disables the probe. */
|
|
61
|
+
#ifndef AP_HEAP_EXACT_BIN_PROBE_COUNT
|
|
62
|
+
#define AP_HEAP_EXACT_BIN_PROBE_COUNT 2
|
|
63
|
+
#endif
|
|
64
|
+
|
|
65
|
+
// ========== Heap Allocator Structs ==========
|
|
66
|
+
|
|
67
|
+
typedef struct heap_memory_block {
|
|
68
|
+
size_t capacity;
|
|
69
|
+
size_t size;
|
|
70
|
+
struct heap_memory_block* next_free;
|
|
71
|
+
struct heap_memory_block* next_allocated;
|
|
72
|
+
struct heap_page* parent_page;
|
|
73
|
+
char buffer[];
|
|
74
|
+
} heap_memory_block;
|
|
75
|
+
|
|
76
|
+
typedef struct heap_page {
|
|
77
|
+
size_t capacity;
|
|
78
|
+
size_t occupied;
|
|
79
|
+
struct heap_allocator* allocator;
|
|
80
|
+
struct heap_page* prev;
|
|
81
|
+
struct heap_memory_block* allocated;
|
|
82
|
+
char buffer[];
|
|
83
|
+
} heap_page;
|
|
84
|
+
|
|
85
|
+
typedef struct heap_allocator {
|
|
86
|
+
pthread_mutex_t lock;
|
|
87
|
+
size_t mapped_pages;
|
|
88
|
+
struct heap_page* active_page;
|
|
89
|
+
size_t autopage_capacity;
|
|
90
|
+
size_t autopage_capacity_max;
|
|
91
|
+
size_t autopage_alignment;
|
|
92
|
+
struct heap_memory_block* bins[AP_HEAP_BIN_COUNT];
|
|
93
|
+
} heap_allocator;
|
|
94
|
+
|
|
95
|
+
// ========== Utility Functions ==========
|
|
96
|
+
|
|
97
|
+
static inline size_t c_heap_page_roundup(heap_allocator* allocator, size_t size) {
|
|
98
|
+
return (size + allocator->autopage_alignment - 1) & ~(allocator->autopage_alignment - 1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
static inline size_t c_heap_block_roundup(size_t size) {
|
|
102
|
+
return (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ceil(log2(v)) for 0 < v <= UINT32_MAX (portable; intrinsics on MSVC/GCC-Clang).
|
|
106
|
+
* 32-bit is sufficient: the bin structure caps block capacities well below
|
|
107
|
+
* 4 GiB, so a narrower parameter type truthfully advertises the domain. */
|
|
108
|
+
static inline size_t c_heap_block_ceil_log2(uint32_t v) {
|
|
109
|
+
size_t floor;
|
|
110
|
+
#if defined(_MSC_VER)
|
|
111
|
+
unsigned long idx = 0;
|
|
112
|
+
_BitScanReverse(&idx, (unsigned long) v);
|
|
113
|
+
floor = (size_t) idx;
|
|
114
|
+
#else
|
|
115
|
+
floor = (size_t) (31u - __builtin_clz((unsigned int) v));
|
|
116
|
+
#endif
|
|
117
|
+
return floor + (v != ((size_t) 1u << floor));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Size bin for a block capacity (always a multiple of 8).
|
|
121
|
+
* Exact bins: index = capacity / 8 (1..AP_HEAP_EXACT_BIN_COUNT), so any
|
|
122
|
+
* block in bin(cap_net) has capacity == cap_net and always fits.
|
|
123
|
+
* Larger capacities: pow2-class bins keyed by ceil(log2(capacity))
|
|
124
|
+
* (indices AP_HEAP_EXACT_BIN_COUNT+1..); the last bin is the overflow
|
|
125
|
+
* class. In-bin first-fit is used there (blocks can be up to one class
|
|
126
|
+
* smaller than the request). */
|
|
127
|
+
static inline size_t c_heap_block_bin(size_t capacity) {
|
|
128
|
+
if (capacity <= (size_t) AP_HEAP_EXACT_BIN_COUNT * 8u) {
|
|
129
|
+
return capacity >> 3;
|
|
130
|
+
}
|
|
131
|
+
size_t idx = (size_t) AP_HEAP_EXACT_BIN_COUNT + (c_heap_block_ceil_log2(capacity) - 16u);
|
|
132
|
+
if (idx > (size_t) AP_HEAP_EXACT_BIN_COUNT + AP_HEAP_LARGE_BIN_COUNT) {
|
|
133
|
+
idx = (size_t) AP_HEAP_EXACT_BIN_COUNT + AP_HEAP_LARGE_BIN_COUNT;
|
|
134
|
+
}
|
|
135
|
+
return idx;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static inline void c_heap_page_reclaim(heap_allocator* allocator, heap_page* page) {
|
|
139
|
+
if (!allocator || !page) {
|
|
140
|
+
errno = EINVAL;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
heap_memory_block** prevp = &page->allocated;
|
|
145
|
+
while (*prevp) {
|
|
146
|
+
heap_memory_block* block = *prevp;
|
|
147
|
+
if (block->size != 0) {
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
*prevp = block->next_allocated;
|
|
152
|
+
block->next_allocated = NULL;
|
|
153
|
+
|
|
154
|
+
heap_memory_block** free_prev = &allocator->bins[c_heap_block_bin(block->capacity)];
|
|
155
|
+
while (*free_prev && *free_prev != block) {
|
|
156
|
+
free_prev = &(*free_prev)->next_free;
|
|
157
|
+
}
|
|
158
|
+
if (*free_prev == block) {
|
|
159
|
+
*free_prev = block->next_free;
|
|
160
|
+
}
|
|
161
|
+
block->next_free = NULL;
|
|
162
|
+
|
|
163
|
+
size_t cap_total = block->capacity + sizeof(heap_memory_block);
|
|
164
|
+
if (page->occupied >= cap_total) {
|
|
165
|
+
page->occupied -= cap_total;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ========== Public API Functions ==========
|
|
171
|
+
|
|
172
|
+
static inline heap_page* c_heap_allocator_extend(heap_allocator* allocator, size_t capacity, pthread_mutex_t* lock) {
|
|
173
|
+
if (!allocator) {
|
|
174
|
+
errno = EINVAL;
|
|
175
|
+
return NULL;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
uint8_t locked = 0;
|
|
179
|
+
|
|
180
|
+
if (lock) {
|
|
181
|
+
int ret = pthread_mutex_lock(lock);
|
|
182
|
+
if (ret != 0) {
|
|
183
|
+
errno = ret;
|
|
184
|
+
return NULL;
|
|
185
|
+
}
|
|
186
|
+
locked = 1;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (capacity == 0) {
|
|
190
|
+
if (!allocator->active_page) {
|
|
191
|
+
capacity = allocator->autopage_capacity;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
size_t prev_cap = allocator->active_page->capacity;
|
|
195
|
+
capacity = prev_cap * 2;
|
|
196
|
+
if (capacity < allocator->autopage_capacity) {
|
|
197
|
+
capacity = allocator->autopage_capacity;
|
|
198
|
+
}
|
|
199
|
+
else if (capacity > allocator->autopage_capacity_max) {
|
|
200
|
+
capacity = allocator->autopage_capacity_max;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
size_t total_capacity = c_heap_page_roundup(allocator, capacity);
|
|
206
|
+
|
|
207
|
+
heap_page* page = (heap_page*) calloc(1, total_capacity);
|
|
208
|
+
|
|
209
|
+
if (!page) {
|
|
210
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
211
|
+
return NULL;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
page->capacity = total_capacity;
|
|
215
|
+
page->occupied = sizeof(heap_page);
|
|
216
|
+
page->allocator = allocator;
|
|
217
|
+
page->allocated = NULL;
|
|
218
|
+
page->prev = allocator->active_page;
|
|
219
|
+
allocator->active_page = page;
|
|
220
|
+
allocator->mapped_pages++;
|
|
221
|
+
|
|
222
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
223
|
+
return page;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
static inline heap_allocator* c_heap_allocator_new() {
|
|
227
|
+
heap_allocator* allocator = (heap_allocator*) calloc(1, sizeof(heap_allocator));
|
|
228
|
+
if (!allocator) {
|
|
229
|
+
return NULL;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (pthread_mutex_init(&allocator->lock, NULL) != 0) {
|
|
233
|
+
free(allocator);
|
|
234
|
+
return NULL;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
allocator->mapped_pages = 0;
|
|
238
|
+
allocator->active_page = NULL;
|
|
239
|
+
allocator->autopage_capacity = AP_HEAP_AUTOPAGE_CAPACITY;
|
|
240
|
+
allocator->autopage_capacity_max = AP_HEAP_AUTOPAGE_CAPACITY_MAX;
|
|
241
|
+
allocator->autopage_alignment = AP_HEAP_AUTOPAGE_ALIGNMENT;
|
|
242
|
+
|
|
243
|
+
return allocator;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static inline void c_heap_allocator_free(heap_allocator* allocator) {
|
|
247
|
+
if (!allocator) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
heap_page* page = allocator->active_page;
|
|
252
|
+
while (page) {
|
|
253
|
+
heap_page* prev = page->prev;
|
|
254
|
+
free(page);
|
|
255
|
+
page = prev;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
pthread_mutex_destroy(&allocator->lock);
|
|
259
|
+
free(allocator);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
static inline void* c_heap_calloc(heap_allocator* allocator, size_t size, pthread_mutex_t* lock) {
|
|
263
|
+
if (!allocator || size == 0) {
|
|
264
|
+
errno = EINVAL;
|
|
265
|
+
return NULL;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
size_t cap_net = c_heap_block_roundup(size);
|
|
269
|
+
size_t overhead = sizeof(heap_memory_block);
|
|
270
|
+
size_t cap_total = cap_net + overhead;
|
|
271
|
+
|
|
272
|
+
uint8_t locked = 0;
|
|
273
|
+
pthread_mutex_t* builtin_lock = &allocator->lock;
|
|
274
|
+
pthread_mutex_t* child_lock = &allocator->lock;
|
|
275
|
+
if (lock) {
|
|
276
|
+
if (lock == builtin_lock) {
|
|
277
|
+
child_lock = NULL;
|
|
278
|
+
}
|
|
279
|
+
int ret = pthread_mutex_lock(lock);
|
|
280
|
+
if (ret != 0) {
|
|
281
|
+
errno = ret;
|
|
282
|
+
return NULL;
|
|
283
|
+
}
|
|
284
|
+
locked = 1;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
child_lock = NULL;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
heap_page* page = allocator->active_page;
|
|
291
|
+
if (!page) {
|
|
292
|
+
size_t target_cap = allocator->autopage_capacity;
|
|
293
|
+
while (target_cap < cap_total + sizeof(heap_page)) {
|
|
294
|
+
target_cap *= 2;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
page = c_heap_allocator_extend(allocator, target_cap, child_lock);
|
|
298
|
+
if (!page) {
|
|
299
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
300
|
+
return NULL;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (page->occupied + cap_total > page->capacity) {
|
|
305
|
+
size_t target_cap = page->capacity;
|
|
306
|
+
|
|
307
|
+
if (target_cap < allocator->autopage_capacity) {
|
|
308
|
+
target_cap = allocator->autopage_capacity;
|
|
309
|
+
}
|
|
310
|
+
else if (target_cap < allocator->autopage_capacity_max) {
|
|
311
|
+
target_cap *= 2;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
while (target_cap < cap_total + sizeof(heap_page)) {
|
|
315
|
+
target_cap *= 2;
|
|
316
|
+
}
|
|
317
|
+
page = c_heap_allocator_extend(allocator, target_cap, child_lock);
|
|
318
|
+
if (!page) {
|
|
319
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
320
|
+
return NULL;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
size_t offset = page->occupied;
|
|
325
|
+
heap_memory_block* block = (heap_memory_block*) ((char*) page + offset);
|
|
326
|
+
block->capacity = cap_net;
|
|
327
|
+
block->size = size;
|
|
328
|
+
block->next_free = NULL;
|
|
329
|
+
|
|
330
|
+
block->parent_page = page;
|
|
331
|
+
block->next_allocated = page->allocated;
|
|
332
|
+
page->allocated = block;
|
|
333
|
+
page->occupied += cap_total;
|
|
334
|
+
|
|
335
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
336
|
+
|
|
337
|
+
memset(block + 1, 0, cap_net);
|
|
338
|
+
return (void*) block->buffer;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
static inline void* c_heap_request(heap_allocator* allocator, size_t size, int scan_all_pages, pthread_mutex_t* lock) {
|
|
342
|
+
if (!allocator || size == 0) {
|
|
343
|
+
errno = EINVAL;
|
|
344
|
+
return NULL;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
size_t cap_net = c_heap_block_roundup(size);
|
|
348
|
+
size_t overhead = sizeof(heap_memory_block);
|
|
349
|
+
size_t cap_total = cap_net + overhead;
|
|
350
|
+
|
|
351
|
+
uint8_t locked = 0;
|
|
352
|
+
pthread_mutex_t* builtin_lock = &allocator->lock;
|
|
353
|
+
pthread_mutex_t* child_lock = &allocator->lock;
|
|
354
|
+
if (lock) {
|
|
355
|
+
if (lock == builtin_lock) {
|
|
356
|
+
child_lock = NULL;
|
|
357
|
+
}
|
|
358
|
+
int ret = pthread_mutex_lock(lock);
|
|
359
|
+
if (ret != 0) {
|
|
360
|
+
errno = ret;
|
|
361
|
+
return NULL;
|
|
362
|
+
}
|
|
363
|
+
locked = 1;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
child_lock = NULL;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* Step 1: size-binned free-list reuse (see c_heap_block_bin).
|
|
370
|
+
* Exact bins always fit (capacity == cap_net) — O(1) head pop.
|
|
371
|
+
* Pow2-class bins use in-bin first-fit: bins are short and same-
|
|
372
|
+
* shaped, so the head is the common hit; larger-capacity blocks in
|
|
373
|
+
* the bin also satisfy smaller requests. */
|
|
374
|
+
size_t bin = c_heap_block_bin(cap_net);
|
|
375
|
+
heap_memory_block* free_blk;
|
|
376
|
+
if (bin <= (size_t) AP_HEAP_EXACT_BIN_COUNT) {
|
|
377
|
+
size_t found = bin;
|
|
378
|
+
free_blk = allocator->bins[bin];
|
|
379
|
+
if (!free_blk && AP_HEAP_EXACT_BIN_PROBE_COUNT > 0) {
|
|
380
|
+
size_t probe_end = bin + (size_t) AP_HEAP_EXACT_BIN_PROBE_COUNT;
|
|
381
|
+
if (probe_end > (size_t) AP_HEAP_EXACT_BIN_COUNT) {
|
|
382
|
+
probe_end = (size_t) AP_HEAP_EXACT_BIN_COUNT;
|
|
383
|
+
}
|
|
384
|
+
for (size_t b = bin + 1; b <= probe_end; b++) {
|
|
385
|
+
free_blk = allocator->bins[b];
|
|
386
|
+
if (free_blk) {
|
|
387
|
+
found = b;
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (free_blk) {
|
|
393
|
+
allocator->bins[found] = free_blk->next_free;
|
|
394
|
+
free_blk->next_free = NULL;
|
|
395
|
+
free_blk->size = size;
|
|
396
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
397
|
+
memset(free_blk + 1, 0, cap_net);
|
|
398
|
+
return (void*) free_blk->buffer;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
heap_memory_block** prevp = &allocator->bins[bin];
|
|
403
|
+
free_blk = *prevp;
|
|
404
|
+
while (free_blk) {
|
|
405
|
+
if (free_blk->capacity >= cap_net) {
|
|
406
|
+
*prevp = free_blk->next_free;
|
|
407
|
+
free_blk->next_free = NULL;
|
|
408
|
+
free_blk->size = size;
|
|
409
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
410
|
+
memset(free_blk + 1, 0, cap_net);
|
|
411
|
+
return (void*) free_blk->buffer;
|
|
412
|
+
}
|
|
413
|
+
prevp = &free_blk->next_free;
|
|
414
|
+
free_blk = free_blk->next_free;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
heap_page* target_page = NULL;
|
|
419
|
+
if (scan_all_pages) {
|
|
420
|
+
heap_page* iter = allocator->active_page;
|
|
421
|
+
while (iter) {
|
|
422
|
+
if (iter->occupied + cap_total <= iter->capacity) {
|
|
423
|
+
target_page = iter;
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
iter = iter->prev;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
else if (allocator->active_page) {
|
|
430
|
+
heap_page* meta = allocator->active_page;
|
|
431
|
+
if (meta && meta->occupied + cap_total <= meta->capacity) {
|
|
432
|
+
target_page = allocator->active_page;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (!target_page) {
|
|
437
|
+
size_t target_cap;
|
|
438
|
+
#if AP_HEAP_PAGE_FIT_TO_REQUEST
|
|
439
|
+
/* Fit the page to the request (floor = autopage_capacity): rare
|
|
440
|
+
* bin misses must not extend oversized pages. */
|
|
441
|
+
target_cap = allocator->autopage_capacity;
|
|
442
|
+
#else
|
|
443
|
+
/* Page scaling with a cap: double from the current page size up to
|
|
444
|
+
* AP_HEAP_PAGE_EXTEND_MAX. A page larger than the cap (e.g. from
|
|
445
|
+
* a huge request) scales back down to the cap. Requests larger
|
|
446
|
+
* than the cap force a bigger page via the fit loop below. */
|
|
447
|
+
heap_page* current = allocator->active_page;
|
|
448
|
+
if (!current) {
|
|
449
|
+
target_cap = allocator->autopage_capacity;
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
target_cap = current->capacity;
|
|
453
|
+
if (target_cap < allocator->autopage_capacity) {
|
|
454
|
+
target_cap = allocator->autopage_capacity;
|
|
455
|
+
}
|
|
456
|
+
else if (target_cap > (size_t) AP_HEAP_PAGE_EXTEND_MAX) {
|
|
457
|
+
target_cap = (size_t) AP_HEAP_PAGE_EXTEND_MAX;
|
|
458
|
+
}
|
|
459
|
+
else if (target_cap < (size_t) AP_HEAP_PAGE_EXTEND_MAX) {
|
|
460
|
+
target_cap *= 2;
|
|
461
|
+
if (target_cap > (size_t) AP_HEAP_PAGE_EXTEND_MAX) {
|
|
462
|
+
target_cap = (size_t) AP_HEAP_PAGE_EXTEND_MAX;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
#endif
|
|
467
|
+
while (target_cap < cap_total + sizeof(heap_page)) {
|
|
468
|
+
target_cap *= 2;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
target_page = c_heap_allocator_extend(allocator, target_cap, child_lock);
|
|
472
|
+
if (!target_page) {
|
|
473
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
474
|
+
return NULL;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
size_t offset = target_page->occupied;
|
|
479
|
+
heap_memory_block* block = (heap_memory_block*) ((char*) target_page + offset);
|
|
480
|
+
block->capacity = cap_net;
|
|
481
|
+
block->size = size;
|
|
482
|
+
block->next_free = NULL;
|
|
483
|
+
|
|
484
|
+
block->parent_page = target_page;
|
|
485
|
+
block->next_allocated = target_page->allocated;
|
|
486
|
+
target_page->allocated = block;
|
|
487
|
+
|
|
488
|
+
target_page->occupied += cap_total;
|
|
489
|
+
|
|
490
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
491
|
+
|
|
492
|
+
memset(block + 1, 0, cap_net);
|
|
493
|
+
return (void*) block->buffer;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
static inline void c_heap_free(void* ptr, pthread_mutex_t* lock) {
|
|
497
|
+
if (!ptr) {
|
|
498
|
+
errno = EINVAL;
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
heap_memory_block* block = (heap_memory_block*) ((char*) ptr - sizeof(heap_memory_block));
|
|
503
|
+
heap_page* page = block->parent_page;
|
|
504
|
+
if (!page || !page->allocator) {
|
|
505
|
+
errno = EINVAL;
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
heap_allocator* allocator = page->allocator;
|
|
510
|
+
|
|
511
|
+
uint8_t locked = 0;
|
|
512
|
+
if (lock) {
|
|
513
|
+
int ret = pthread_mutex_lock(lock);
|
|
514
|
+
if (ret != 0) {
|
|
515
|
+
errno = ret;
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
locked = 1;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
block->size = 0;
|
|
522
|
+
size_t bin = c_heap_block_bin(block->capacity);
|
|
523
|
+
block->next_free = allocator->bins[bin];
|
|
524
|
+
allocator->bins[bin] = block;
|
|
525
|
+
|
|
526
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
static inline void c_heap_reclaim(heap_allocator* allocator, pthread_mutex_t* lock) {
|
|
530
|
+
if (!allocator) {
|
|
531
|
+
errno = EINVAL;
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
uint8_t locked = 0;
|
|
536
|
+
if (lock) {
|
|
537
|
+
int ret = pthread_mutex_lock(lock);
|
|
538
|
+
if (ret != 0) {
|
|
539
|
+
errno = ret;
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
locked = 1;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
heap_page* page = allocator->active_page;
|
|
546
|
+
while (page) {
|
|
547
|
+
c_heap_page_reclaim(allocator, page);
|
|
548
|
+
page = page->prev;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
#endif /* AP_HEAP_C_HEAP_ALLOCATOR_H */
|