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
|
@@ -0,0 +1,996 @@
|
|
|
1
|
+
#ifndef AP_SHM_C_NT_SHM_ALLOCATOR_H
|
|
2
|
+
#define AP_SHM_C_NT_SHM_ALLOCATOR_H
|
|
3
|
+
|
|
4
|
+
#ifndef _WIN32
|
|
5
|
+
#error "c_nt_shm_allocator.h is intended for Windows builds only"
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#ifndef WIN32_LEAN_AND_MEAN
|
|
9
|
+
#define WIN32_LEAN_AND_MEAN
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
#include <errno.h>
|
|
13
|
+
#include <stddef.h>
|
|
14
|
+
#include <stdint.h>
|
|
15
|
+
#include <stdio.h>
|
|
16
|
+
#include <stdlib.h>
|
|
17
|
+
#include <string.h>
|
|
18
|
+
#include <windows.h>
|
|
19
|
+
|
|
20
|
+
#include "cbase/nt/pthread_nt_compat.h"
|
|
21
|
+
|
|
22
|
+
// ========== Configuration ==========
|
|
23
|
+
|
|
24
|
+
#ifndef AP_SHM_AUTOPAGE_CAPACITY
|
|
25
|
+
#define AP_SHM_AUTOPAGE_CAPACITY (64 * 1024) /* 64 KiB */
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
#ifndef AP_SHM_AUTOPAGE_CAPACITY_MAX
|
|
29
|
+
#define AP_SHM_AUTOPAGE_CAPACITY_MAX (16 * 1024 * 1024) /* 16 MiB */
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
#ifndef AP_SHM_AUTOPAGE_ALIGNMENT
|
|
33
|
+
#define AP_SHM_AUTOPAGE_ALIGNMENT (4 * 1024) /* 4 KiB */
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
#ifndef AP_SHM_ALLOCATOR_PREFIX
|
|
37
|
+
#define AP_SHM_ALLOCATOR_PREFIX "/c_cbase_shm"
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
#ifndef AP_SHM_NAME_LEN
|
|
41
|
+
#define AP_SHM_NAME_LEN 256
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
#ifndef AP_SHM_PREFIX_MAX
|
|
45
|
+
#define AP_SHM_PREFIX_MAX 64
|
|
46
|
+
#endif
|
|
47
|
+
|
|
48
|
+
#ifndef AP_SHM_ALLOCATOR_DEFAULT_REGION_SIZE
|
|
49
|
+
#define AP_SHM_ALLOCATOR_DEFAULT_REGION_SIZE (128ULL << 30) /* 128 GiB */
|
|
50
|
+
#endif
|
|
51
|
+
|
|
52
|
+
// ========== Structs ==========
|
|
53
|
+
|
|
54
|
+
typedef struct nt_shm_page {
|
|
55
|
+
size_t capacity;
|
|
56
|
+
size_t occupied;
|
|
57
|
+
size_t offset;
|
|
58
|
+
struct nt_shm_allocator* allocator;
|
|
59
|
+
struct nt_shm_memory_block* allocated;
|
|
60
|
+
char shm_name[AP_SHM_NAME_LEN];
|
|
61
|
+
char prev_name[AP_SHM_NAME_LEN];
|
|
62
|
+
} nt_shm_page;
|
|
63
|
+
|
|
64
|
+
typedef struct nt_shm_page_ctx {
|
|
65
|
+
nt_shm_page* shm_page;
|
|
66
|
+
HANDLE handle;
|
|
67
|
+
char* buffer;
|
|
68
|
+
struct nt_shm_page_ctx* prev;
|
|
69
|
+
} nt_shm_page_ctx;
|
|
70
|
+
|
|
71
|
+
typedef struct nt_shm_memory_block {
|
|
72
|
+
size_t capacity;
|
|
73
|
+
size_t size;
|
|
74
|
+
struct nt_shm_memory_block* next_free;
|
|
75
|
+
struct nt_shm_memory_block* next_allocated;
|
|
76
|
+
nt_shm_page* parent_page;
|
|
77
|
+
char buffer[];
|
|
78
|
+
} nt_shm_memory_block;
|
|
79
|
+
|
|
80
|
+
typedef struct nt_shm_allocator {
|
|
81
|
+
char shm_name[AP_SHM_NAME_LEN];
|
|
82
|
+
size_t pid;
|
|
83
|
+
char lock_name[AP_SHM_NAME_LEN];
|
|
84
|
+
size_t mapped_size;
|
|
85
|
+
char active_page[AP_SHM_NAME_LEN];
|
|
86
|
+
size_t mapped_pages;
|
|
87
|
+
nt_shm_memory_block* free_list;
|
|
88
|
+
size_t autopage_capacity;
|
|
89
|
+
size_t autopage_capacity_max;
|
|
90
|
+
size_t autopage_alignment;
|
|
91
|
+
char shm_prefix[AP_SHM_PREFIX_MAX];
|
|
92
|
+
pthread_mutex_t lock; // dummy; present for c_allocator_protocol.h compat
|
|
93
|
+
} nt_shm_allocator;
|
|
94
|
+
|
|
95
|
+
typedef struct nt_shm_allocator_ctx {
|
|
96
|
+
nt_shm_allocator* shm_allocator;
|
|
97
|
+
HANDLE shm_handle;
|
|
98
|
+
HANDLE lock_handle;
|
|
99
|
+
nt_shm_page_ctx* active_page;
|
|
100
|
+
} nt_shm_allocator_ctx;
|
|
101
|
+
|
|
102
|
+
// ========== Internal Helpers ==========
|
|
103
|
+
|
|
104
|
+
static const size_t c_nt_shm_page_overhead = (sizeof(nt_shm_page) + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
|
|
105
|
+
static const size_t c_nt_shm_block_overhead = (sizeof(nt_shm_memory_block) + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @brief Convert a UTF-8 name to a wide-char name with "Global\\" prefix.
|
|
109
|
+
* @param utf8_name UTF-8 input name (e.g. "/c_cbase_shm_ac_1234_7f...").
|
|
110
|
+
* @param wide_out Output buffer for wide-char name (must be at least AP_SHM_NAME_LEN WCHARs).
|
|
111
|
+
* @return Number of WCHARs written (excluding null terminator), or 0 on error.
|
|
112
|
+
*/
|
|
113
|
+
static inline int c_nt_shm_to_wide(const char* utf8_name, wchar_t* wide_out) {
|
|
114
|
+
if (!utf8_name || !wide_out) return 0;
|
|
115
|
+
|
|
116
|
+
// Skip leading '/' in POSIX-style names
|
|
117
|
+
const char* src = utf8_name;
|
|
118
|
+
if (src[0] == '/') src++;
|
|
119
|
+
|
|
120
|
+
// Prepend "Global\\"
|
|
121
|
+
wchar_t* dst = wide_out;
|
|
122
|
+
wcscpy(dst, L"Global\\");
|
|
123
|
+
dst += 7;
|
|
124
|
+
|
|
125
|
+
// Convert ASCII to wide chars
|
|
126
|
+
int count = 7;
|
|
127
|
+
while (*src && count < AP_SHM_NAME_LEN - 1) {
|
|
128
|
+
*dst++ = (wchar_t) (unsigned char) *src++;
|
|
129
|
+
count++;
|
|
130
|
+
}
|
|
131
|
+
*dst = L'\0';
|
|
132
|
+
return count;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @brief Lock the allocator via the cached named mutex handle.
|
|
137
|
+
*/
|
|
138
|
+
static inline int c_nt_shm_lock(nt_shm_allocator_ctx* ctx) {
|
|
139
|
+
if (!ctx || !ctx->lock_handle) return -1;
|
|
140
|
+
DWORD result = WaitForSingleObject(ctx->lock_handle, INFINITE);
|
|
141
|
+
return (result == WAIT_OBJECT_0) ? 0 : -1;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @brief Unlock the allocator via the cached named mutex handle.
|
|
146
|
+
*/
|
|
147
|
+
static inline void c_nt_shm_unlock(nt_shm_allocator_ctx* ctx) {
|
|
148
|
+
if (ctx && ctx->lock_handle) {
|
|
149
|
+
ReleaseMutex(ctx->lock_handle);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ========== Utility Functions ==========
|
|
154
|
+
|
|
155
|
+
static inline size_t c_nt_shm_page_roundup(nt_shm_allocator* allocator, size_t size) {
|
|
156
|
+
return (size + allocator->autopage_alignment - 1) & ~(allocator->autopage_alignment - 1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static inline size_t c_nt_shm_block_roundup(size_t size) {
|
|
160
|
+
return (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
static inline void c_nt_shm_allocator_name(const char* shm_prefix, char* out) {
|
|
164
|
+
DWORD pid = GetCurrentProcessId();
|
|
165
|
+
snprintf(out, AP_SHM_NAME_LEN, "%s_ac_%lx", shm_prefix, (unsigned long) pid);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static inline void c_nt_shm_page_name(nt_shm_allocator* allocator, char* out) {
|
|
169
|
+
DWORD pid = GetCurrentProcessId();
|
|
170
|
+
size_t page_idx = allocator->mapped_pages;
|
|
171
|
+
snprintf(out, AP_SHM_NAME_LEN, "%s_pg_%lx_%lx_%zx", allocator->shm_prefix, (unsigned long) pid, (unsigned long) (uintptr_t) allocator, page_idx);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static inline void c_nt_shm_mutex_name(const char* shm_prefix, char* out) {
|
|
175
|
+
DWORD pid = GetCurrentProcessId();
|
|
176
|
+
snprintf(out, AP_SHM_NAME_LEN, "%s_mtx_%lx", shm_prefix, (unsigned long) pid);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ========== Scan / Dangling ==========
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @brief Try to open a file mapping with the given name pattern.
|
|
183
|
+
*
|
|
184
|
+
* Iterates through candidate PIDs to find a matching file mapping.
|
|
185
|
+
* Uses the naming convention: {prefix}_{suffix}_{pid}
|
|
186
|
+
*
|
|
187
|
+
* @param prefix UTF-8 prefix (e.g. "/c_cbase_shm_ac").
|
|
188
|
+
* @param out Output buffer to receive the found UTF-8 name.
|
|
189
|
+
* @param out_len Size of output buffer.
|
|
190
|
+
* @return 0 on success, -1 with errno set otherwise.
|
|
191
|
+
*/
|
|
192
|
+
static inline int c_nt_shm_scan(const char* prefix, const char* suffix, char* out, size_t out_len) {
|
|
193
|
+
if (!prefix || !out || !out_len) {
|
|
194
|
+
errno = EINVAL;
|
|
195
|
+
return -1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Skip leading '/'
|
|
199
|
+
const char* pfx = prefix;
|
|
200
|
+
if (pfx[0] == '/') pfx++;
|
|
201
|
+
|
|
202
|
+
// The full prefix is {prefix}_{suffix}
|
|
203
|
+
char full_prefix[AP_SHM_NAME_LEN];
|
|
204
|
+
if (suffix) {
|
|
205
|
+
snprintf(full_prefix, sizeof(full_prefix), "%s_%s", pfx, suffix);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
strncpy(full_prefix, pfx, sizeof(full_prefix) - 1);
|
|
209
|
+
full_prefix[sizeof(full_prefix) - 1] = '\0';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Build wide prefix: "Global\\{full_prefix}_"
|
|
213
|
+
wchar_t wide_prefix[AP_SHM_NAME_LEN];
|
|
214
|
+
int prefix_len = swprintf(wide_prefix, AP_SHM_NAME_LEN, L"Global\\%hs_", full_prefix);
|
|
215
|
+
if (prefix_len < 0) {
|
|
216
|
+
errno = EINVAL;
|
|
217
|
+
return -1;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Try current process and a range of nearby PIDs
|
|
221
|
+
DWORD current_pid = GetCurrentProcessId();
|
|
222
|
+
for (DWORD offset = 0; offset < 65536; offset++) {
|
|
223
|
+
DWORD try_pid = (current_pid + offset) % 65536;
|
|
224
|
+
if (try_pid == 0) continue;
|
|
225
|
+
|
|
226
|
+
wchar_t wide_name[AP_SHM_NAME_LEN];
|
|
227
|
+
swprintf(wide_name, AP_SHM_NAME_LEN, L"Global\\%hs_%lx", full_prefix, (unsigned long) try_pid);
|
|
228
|
+
|
|
229
|
+
HANDLE h = OpenFileMappingW(FILE_MAP_READ, FALSE, wide_name);
|
|
230
|
+
if (h != NULL) {
|
|
231
|
+
CloseHandle(h);
|
|
232
|
+
// Convert back to UTF-8
|
|
233
|
+
int ret = WideCharToMultiByte(CP_UTF8, 0, wide_name, -1, out, (int) out_len, NULL, NULL);
|
|
234
|
+
if (ret > 0) {
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
errno = ENOENT;
|
|
241
|
+
return -1;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @brief Scan for an allocator SHM name (appends "_ac" to prefix).
|
|
246
|
+
*/
|
|
247
|
+
static inline int c_nt_shm_scan_allocator(const char* shm_prefix, char* out) {
|
|
248
|
+
if (!shm_prefix) shm_prefix = AP_SHM_ALLOCATOR_PREFIX;
|
|
249
|
+
return c_nt_shm_scan(shm_prefix, "ac", out, AP_SHM_NAME_LEN);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* @brief Scan for a page SHM name (appends "_pg" to prefix).
|
|
254
|
+
*/
|
|
255
|
+
static inline int c_nt_shm_scan_page(const char* shm_prefix, char* out) {
|
|
256
|
+
if (!shm_prefix) shm_prefix = AP_SHM_ALLOCATOR_PREFIX;
|
|
257
|
+
return c_nt_shm_scan(shm_prefix, "pg", out, AP_SHM_NAME_LEN);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* @brief Extract pid embedded in allocator/page SHM name.
|
|
262
|
+
*/
|
|
263
|
+
static inline DWORD c_nt_shm_pid(const char* shm_name) {
|
|
264
|
+
if (!shm_name) {
|
|
265
|
+
errno = EINVAL;
|
|
266
|
+
return 0;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const char* base = shm_name;
|
|
270
|
+
// Skip "Global\" prefix if present
|
|
271
|
+
if (strncmp(base, "Global\\", 7) == 0) base += 7;
|
|
272
|
+
if (base[0] == '/') base++;
|
|
273
|
+
|
|
274
|
+
// Name format: {prefix}_{pid_hex}_{suffix} or {prefix}_{pid_hex}
|
|
275
|
+
const char* suffix_us = strrchr(base, '_');
|
|
276
|
+
if (!suffix_us) {
|
|
277
|
+
errno = EINVAL;
|
|
278
|
+
return 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const char* pid_us = NULL;
|
|
282
|
+
for (const char* p = base; p < suffix_us; p++) {
|
|
283
|
+
if (*p == '_') pid_us = p;
|
|
284
|
+
}
|
|
285
|
+
if (!pid_us) {
|
|
286
|
+
errno = EINVAL;
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const char* pid_start = pid_us + 1;
|
|
291
|
+
size_t pid_len = (size_t) (suffix_us - pid_start);
|
|
292
|
+
if (pid_len == 0 || pid_len >= 32) {
|
|
293
|
+
errno = EINVAL;
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
char pidbuf[32];
|
|
298
|
+
memcpy(pidbuf, pid_start, pid_len);
|
|
299
|
+
pidbuf[pid_len] = '\0';
|
|
300
|
+
|
|
301
|
+
errno = 0;
|
|
302
|
+
char* endptr = NULL;
|
|
303
|
+
unsigned long v = strtoul(pidbuf, &endptr, 16);
|
|
304
|
+
if (errno != 0 || endptr == pidbuf || *endptr != '\0') {
|
|
305
|
+
errno = EINVAL;
|
|
306
|
+
return 0;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return (DWORD) v;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* @brief Check if a process is still running.
|
|
314
|
+
*/
|
|
315
|
+
static inline int c_nt_shm_process_alive(DWORD pid) {
|
|
316
|
+
if (pid == 0) return 0;
|
|
317
|
+
HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
|
318
|
+
if (!h) return 0;
|
|
319
|
+
DWORD exit_code;
|
|
320
|
+
BOOL ok = GetExitCodeProcess(h, &exit_code);
|
|
321
|
+
CloseHandle(h);
|
|
322
|
+
return ok && exit_code == STILL_ACTIVE;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @brief Find and map a dangling allocator (whose creator pid is gone).
|
|
327
|
+
*/
|
|
328
|
+
static inline nt_shm_allocator* c_nt_shm_allocator_dangling(const char* shm_prefix, char* shm_name) {
|
|
329
|
+
if (!shm_name) {
|
|
330
|
+
errno = EINVAL;
|
|
331
|
+
return NULL;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (!shm_prefix) shm_prefix = AP_SHM_ALLOCATOR_PREFIX;
|
|
335
|
+
|
|
336
|
+
// Build wide prefix: "Global\\{shm_prefix}_ac_"
|
|
337
|
+
const char* pfx = shm_prefix;
|
|
338
|
+
if (pfx[0] == '/') pfx++;
|
|
339
|
+
|
|
340
|
+
wchar_t wide_prefix[AP_SHM_NAME_LEN];
|
|
341
|
+
swprintf(wide_prefix, AP_SHM_NAME_LEN, L"Global\\%hs_ac_", pfx);
|
|
342
|
+
|
|
343
|
+
// Scan PIDs
|
|
344
|
+
DWORD current_pid = GetCurrentProcessId();
|
|
345
|
+
for (DWORD offset = 0; offset < 65536; offset++) {
|
|
346
|
+
DWORD try_pid = (current_pid + offset) % 65536;
|
|
347
|
+
if (try_pid == 0) continue;
|
|
348
|
+
|
|
349
|
+
wchar_t wide_name[AP_SHM_NAME_LEN];
|
|
350
|
+
swprintf(wide_name, AP_SHM_NAME_LEN, L"Global\\%hs_ac_%lx", pfx, (unsigned long) try_pid);
|
|
351
|
+
|
|
352
|
+
if (c_nt_shm_process_alive(try_pid)) continue;
|
|
353
|
+
|
|
354
|
+
HANDLE h = OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, wide_name);
|
|
355
|
+
if (!h) continue;
|
|
356
|
+
|
|
357
|
+
void* map = MapViewOfFile(h, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(nt_shm_allocator));
|
|
358
|
+
if (!map) {
|
|
359
|
+
CloseHandle(h);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Convert wide name back to UTF-8 for output
|
|
364
|
+
WideCharToMultiByte(CP_UTF8, 0, wide_name, -1, shm_name, AP_SHM_NAME_LEN, NULL, NULL);
|
|
365
|
+
return (nt_shm_allocator*) map;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
errno = ENOENT;
|
|
369
|
+
return NULL;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* @brief Unlink all dangling allocator/page SHM objects.
|
|
374
|
+
*
|
|
375
|
+
* On Windows, file mappings are destroyed when all handles are closed.
|
|
376
|
+
* This function attempts to open and close any dangling objects, but
|
|
377
|
+
* the actual cleanup happens when the last handle is closed.
|
|
378
|
+
*/
|
|
379
|
+
static inline void c_nt_shm_clear_dangling(const char* shm_prefix) {
|
|
380
|
+
if (!shm_prefix) shm_prefix = AP_SHM_ALLOCATOR_PREFIX;
|
|
381
|
+
|
|
382
|
+
const char* pfx = shm_prefix;
|
|
383
|
+
if (pfx[0] == '/') pfx++;
|
|
384
|
+
|
|
385
|
+
const char* suffixes[] = {"ac", "pg"};
|
|
386
|
+
size_t suffix_count = 2;
|
|
387
|
+
|
|
388
|
+
for (DWORD offset = 0; offset < 65536; offset++) {
|
|
389
|
+
DWORD try_pid = (GetCurrentProcessId() + offset) % 65536;
|
|
390
|
+
if (try_pid == 0) continue;
|
|
391
|
+
|
|
392
|
+
if (c_nt_shm_process_alive(try_pid)) continue;
|
|
393
|
+
|
|
394
|
+
for (size_t i = 0; i < suffix_count; i++) {
|
|
395
|
+
wchar_t wide_name[AP_SHM_NAME_LEN];
|
|
396
|
+
swprintf(wide_name, AP_SHM_NAME_LEN, L"Global\\%hs_%hs_%lx", pfx, suffixes[i], (unsigned long) try_pid);
|
|
397
|
+
|
|
398
|
+
HANDLE h = OpenFileMappingW(FILE_MAP_READ, FALSE, wide_name);
|
|
399
|
+
if (h) CloseHandle(h); // Closing our handle helps destroy the mapping
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// ========== Page Management ==========
|
|
405
|
+
|
|
406
|
+
static inline nt_shm_page_ctx* c_nt_shm_page_new(nt_shm_allocator* allocator, size_t page_capacity) {
|
|
407
|
+
nt_shm_page_ctx* ctx = (nt_shm_page_ctx*) calloc(1, sizeof(nt_shm_page_ctx));
|
|
408
|
+
if (!ctx) return NULL;
|
|
409
|
+
|
|
410
|
+
nt_shm_page* meta = (nt_shm_page*) calloc(1, c_nt_shm_page_overhead);
|
|
411
|
+
if (!meta) {
|
|
412
|
+
free(ctx);
|
|
413
|
+
return NULL;
|
|
414
|
+
}
|
|
415
|
+
ctx->shm_page = meta;
|
|
416
|
+
|
|
417
|
+
meta->capacity = page_capacity;
|
|
418
|
+
meta->occupied = c_nt_shm_page_overhead;
|
|
419
|
+
meta->offset = 0;
|
|
420
|
+
|
|
421
|
+
c_nt_shm_page_name(allocator, meta->shm_name);
|
|
422
|
+
|
|
423
|
+
// Create named file mapping for the page
|
|
424
|
+
wchar_t wide_name[AP_SHM_NAME_LEN];
|
|
425
|
+
if (c_nt_shm_to_wide(meta->shm_name, wide_name) == 0) {
|
|
426
|
+
free(meta);
|
|
427
|
+
free(ctx);
|
|
428
|
+
return NULL;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
DWORD size_high = (DWORD) (page_capacity >> 32);
|
|
432
|
+
DWORD size_low = (DWORD) (page_capacity & 0xFFFFFFFF);
|
|
433
|
+
|
|
434
|
+
HANDLE hMapping = CreateFileMappingW(
|
|
435
|
+
INVALID_HANDLE_VALUE,
|
|
436
|
+
NULL,
|
|
437
|
+
PAGE_READWRITE,
|
|
438
|
+
size_high,
|
|
439
|
+
size_low,
|
|
440
|
+
wide_name
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
if (!hMapping) {
|
|
444
|
+
free(meta);
|
|
445
|
+
free(ctx);
|
|
446
|
+
return NULL;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
ctx->shm_page = meta;
|
|
450
|
+
ctx->handle = hMapping;
|
|
451
|
+
ctx->buffer = NULL;
|
|
452
|
+
ctx->prev = NULL;
|
|
453
|
+
|
|
454
|
+
return ctx;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
static inline int c_nt_shm_page_map(nt_shm_allocator* allocator, nt_shm_page_ctx* page_ctx) {
|
|
458
|
+
if (!allocator || !page_ctx || !page_ctx->shm_page || !page_ctx->handle) {
|
|
459
|
+
errno = EINVAL;
|
|
460
|
+
return -1;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
size_t page_capacity = page_ctx->shm_page->capacity;
|
|
464
|
+
size_t offset = allocator->mapped_size;
|
|
465
|
+
|
|
466
|
+
// Map view of the file mapping
|
|
467
|
+
void* mapped = MapViewOfFile(page_ctx->handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, page_capacity);
|
|
468
|
+
if (!mapped) {
|
|
469
|
+
return -1;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Copy metadata to start of mapped page
|
|
473
|
+
nt_shm_page* page_meta = (nt_shm_page*) mapped;
|
|
474
|
+
memcpy(page_meta, page_ctx->shm_page, c_nt_shm_page_overhead);
|
|
475
|
+
free(page_ctx->shm_page);
|
|
476
|
+
page_ctx->shm_page = page_meta;
|
|
477
|
+
page_ctx->buffer = (char*) mapped;
|
|
478
|
+
|
|
479
|
+
// Set correct offset and linkage
|
|
480
|
+
page_meta->offset = offset;
|
|
481
|
+
page_meta->allocator = allocator;
|
|
482
|
+
|
|
483
|
+
if (allocator->mapped_pages == 0) {
|
|
484
|
+
page_meta->prev_name[0] = '\0';
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
memcpy(page_meta->prev_name, allocator->active_page, AP_SHM_NAME_LEN);
|
|
488
|
+
page_meta->prev_name[AP_SHM_NAME_LEN - 1] = '\0';
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
allocator->mapped_size += page_capacity;
|
|
492
|
+
memcpy(allocator->active_page, page_meta->shm_name, AP_SHM_NAME_LEN);
|
|
493
|
+
allocator->active_page[AP_SHM_NAME_LEN - 1] = '\0';
|
|
494
|
+
allocator->mapped_pages++;
|
|
495
|
+
|
|
496
|
+
return 0;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
static inline void c_nt_shm_page_reclaim(nt_shm_allocator* allocator, nt_shm_page_ctx* page_ctx) {
|
|
500
|
+
if (!allocator || !page_ctx || !page_ctx->shm_page) {
|
|
501
|
+
errno = EINVAL;
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
nt_shm_page* page = page_ctx->shm_page;
|
|
506
|
+
|
|
507
|
+
nt_shm_memory_block** prevp = &page->allocated;
|
|
508
|
+
while (*prevp) {
|
|
509
|
+
nt_shm_memory_block* block = *prevp;
|
|
510
|
+
if (block->size != 0) break;
|
|
511
|
+
|
|
512
|
+
*prevp = block->next_allocated;
|
|
513
|
+
block->next_allocated = NULL;
|
|
514
|
+
|
|
515
|
+
nt_shm_memory_block** free_prev = &allocator->free_list;
|
|
516
|
+
while (*free_prev && *free_prev != block) {
|
|
517
|
+
free_prev = &(*free_prev)->next_free;
|
|
518
|
+
}
|
|
519
|
+
if (*free_prev == block) {
|
|
520
|
+
*free_prev = block->next_free;
|
|
521
|
+
}
|
|
522
|
+
block->next_free = NULL;
|
|
523
|
+
|
|
524
|
+
size_t cap_total = block->capacity + c_nt_shm_block_overhead;
|
|
525
|
+
if (page->occupied >= cap_total) {
|
|
526
|
+
page->occupied -= cap_total;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ========== Public API ==========
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* @brief Extend allocator with a new page, locking via pthread_mutex if provided.
|
|
535
|
+
*/
|
|
536
|
+
static inline nt_shm_page_ctx* c_nt_shm_allocator_extend(nt_shm_allocator_ctx* ctx, size_t capacity, pthread_mutex_t* lock) {
|
|
537
|
+
if (!ctx || !ctx->shm_allocator) {
|
|
538
|
+
errno = EINVAL;
|
|
539
|
+
return NULL;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
nt_shm_allocator* allocator = ctx->shm_allocator;
|
|
543
|
+
uint8_t locked = 0;
|
|
544
|
+
|
|
545
|
+
if (lock) {
|
|
546
|
+
int ret = pthread_mutex_lock(lock);
|
|
547
|
+
if (ret != 0) {
|
|
548
|
+
errno = ret;
|
|
549
|
+
return NULL;
|
|
550
|
+
}
|
|
551
|
+
locked = 1;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Determine new page capacity
|
|
555
|
+
if (capacity == 0) {
|
|
556
|
+
if (!ctx->active_page) {
|
|
557
|
+
capacity = allocator->autopage_capacity;
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
size_t prev_cap = ctx->active_page->shm_page->capacity;
|
|
561
|
+
capacity = prev_cap * 2;
|
|
562
|
+
if (capacity < allocator->autopage_capacity) {
|
|
563
|
+
capacity = allocator->autopage_capacity;
|
|
564
|
+
}
|
|
565
|
+
else if (capacity > allocator->autopage_capacity_max) {
|
|
566
|
+
capacity = allocator->autopage_capacity_max;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
size_t aligned_capacity = c_nt_shm_page_roundup(allocator, capacity);
|
|
572
|
+
|
|
573
|
+
// Create new page
|
|
574
|
+
nt_shm_page_ctx* page_ctx = c_nt_shm_page_new(allocator, aligned_capacity);
|
|
575
|
+
if (!page_ctx) {
|
|
576
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
577
|
+
return NULL;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Map new page
|
|
581
|
+
if (c_nt_shm_page_map(allocator, page_ctx) != 0) {
|
|
582
|
+
CloseHandle(page_ctx->handle);
|
|
583
|
+
free(page_ctx->shm_page);
|
|
584
|
+
free(page_ctx);
|
|
585
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
586
|
+
return NULL;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Update context
|
|
590
|
+
page_ctx->prev = ctx->active_page;
|
|
591
|
+
ctx->active_page = page_ctx;
|
|
592
|
+
|
|
593
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
594
|
+
return page_ctx;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* @brief Create a new NT SHM allocator.
|
|
599
|
+
* @param region_size Ignored on NT (pages are independently mapped).
|
|
600
|
+
* @param shm_prefix Custom SHM name prefix (NULL for compile-time default).
|
|
601
|
+
* @return Allocator context or NULL on failure.
|
|
602
|
+
*/
|
|
603
|
+
static inline nt_shm_allocator_ctx* c_nt_shm_allocator_new(size_t region_size, const char* shm_prefix) {
|
|
604
|
+
(void) region_size; // Not used on NT -- pages are independently mapped
|
|
605
|
+
|
|
606
|
+
nt_shm_allocator_ctx* ctx = (nt_shm_allocator_ctx*) calloc(1, sizeof(nt_shm_allocator_ctx));
|
|
607
|
+
if (!ctx) return NULL;
|
|
608
|
+
|
|
609
|
+
if (!shm_prefix) shm_prefix = AP_SHM_ALLOCATOR_PREFIX;
|
|
610
|
+
|
|
611
|
+
size_t prefix_len = strnlen(shm_prefix, AP_SHM_PREFIX_MAX);
|
|
612
|
+
if (prefix_len >= AP_SHM_PREFIX_MAX) {
|
|
613
|
+
fprintf(stderr, "c_nt_shm_allocator_new: shm_prefix exceeds AP_SHM_PREFIX_MAX (%zu)\n", (size_t) AP_SHM_PREFIX_MAX);
|
|
614
|
+
abort();
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Step 1: Create named file mapping for allocator metadata
|
|
618
|
+
char meta_shm_name[AP_SHM_NAME_LEN];
|
|
619
|
+
c_nt_shm_allocator_name(shm_prefix, meta_shm_name);
|
|
620
|
+
|
|
621
|
+
wchar_t wide_meta_name[AP_SHM_NAME_LEN];
|
|
622
|
+
if (c_nt_shm_to_wide(meta_shm_name, wide_meta_name) == 0) {
|
|
623
|
+
free(ctx);
|
|
624
|
+
return NULL;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
HANDLE meta_hMapping = CreateFileMappingW(
|
|
628
|
+
INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
|
629
|
+
0, sizeof(nt_shm_allocator), wide_meta_name
|
|
630
|
+
);
|
|
631
|
+
|
|
632
|
+
if (!meta_hMapping) {
|
|
633
|
+
free(ctx);
|
|
634
|
+
return NULL;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Step 2: Map allocator metadata into memory
|
|
638
|
+
nt_shm_allocator* meta = (nt_shm_allocator*) MapViewOfFile(
|
|
639
|
+
meta_hMapping, FILE_MAP_READ | FILE_MAP_WRITE,
|
|
640
|
+
0, 0, sizeof(nt_shm_allocator)
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
if (!meta) {
|
|
644
|
+
CloseHandle(meta_hMapping);
|
|
645
|
+
free(ctx);
|
|
646
|
+
return NULL;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Step 3: Initialize metadata in shared memory
|
|
650
|
+
memset(meta, 0, sizeof(nt_shm_allocator));
|
|
651
|
+
|
|
652
|
+
size_t name_len = strnlen(meta_shm_name, AP_SHM_NAME_LEN - 1);
|
|
653
|
+
memcpy(meta->shm_name, meta_shm_name, name_len);
|
|
654
|
+
meta->shm_name[name_len] = '\0';
|
|
655
|
+
meta->pid = (size_t) GetCurrentProcessId();
|
|
656
|
+
meta->mapped_size = 0;
|
|
657
|
+
meta->mapped_pages = 0;
|
|
658
|
+
meta->active_page[0] = '\0';
|
|
659
|
+
meta->autopage_capacity = AP_SHM_AUTOPAGE_CAPACITY;
|
|
660
|
+
meta->autopage_capacity_max = AP_SHM_AUTOPAGE_CAPACITY_MAX;
|
|
661
|
+
meta->autopage_alignment = AP_SHM_AUTOPAGE_ALIGNMENT;
|
|
662
|
+
|
|
663
|
+
memcpy(meta->shm_prefix, shm_prefix, prefix_len);
|
|
664
|
+
meta->shm_prefix[prefix_len] = '\0';
|
|
665
|
+
|
|
666
|
+
// Step 4: Create named mutex for inter-process synchronization
|
|
667
|
+
c_nt_shm_mutex_name(shm_prefix, meta->lock_name);
|
|
668
|
+
meta->lock_name[AP_SHM_NAME_LEN - 1] = '\0';
|
|
669
|
+
|
|
670
|
+
wchar_t wide_mutex_name[AP_SHM_NAME_LEN];
|
|
671
|
+
if (c_nt_shm_to_wide(meta->lock_name, wide_mutex_name) == 0) {
|
|
672
|
+
UnmapViewOfFile(meta);
|
|
673
|
+
CloseHandle(meta_hMapping);
|
|
674
|
+
free(ctx);
|
|
675
|
+
return NULL;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
HANDLE lock_handle = CreateMutexW(NULL, FALSE, wide_mutex_name);
|
|
679
|
+
if (!lock_handle) {
|
|
680
|
+
UnmapViewOfFile(meta);
|
|
681
|
+
CloseHandle(meta_hMapping);
|
|
682
|
+
free(ctx);
|
|
683
|
+
return NULL;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Step 5: Initialize intra-process mutex (CRITICAL_SECTION via pthread compat)
|
|
687
|
+
if (pthread_mutex_init(&meta->lock, NULL) != 0) {
|
|
688
|
+
CloseHandle(lock_handle);
|
|
689
|
+
UnmapViewOfFile(meta);
|
|
690
|
+
CloseHandle(meta_hMapping);
|
|
691
|
+
free(ctx);
|
|
692
|
+
return NULL;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Step 6: Fill context
|
|
696
|
+
ctx->shm_allocator = meta;
|
|
697
|
+
ctx->shm_handle = meta_hMapping;
|
|
698
|
+
ctx->lock_handle = lock_handle;
|
|
699
|
+
ctx->active_page = NULL;
|
|
700
|
+
|
|
701
|
+
return ctx;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* @brief Tear down allocator, unmapping pages and closing handles.
|
|
706
|
+
*/
|
|
707
|
+
static inline void c_nt_shm_allocator_free(nt_shm_allocator_ctx* ctx) {
|
|
708
|
+
if (!ctx) return;
|
|
709
|
+
|
|
710
|
+
// Step 1: Unmap all pages
|
|
711
|
+
nt_shm_page_ctx* page_ctx = ctx->active_page;
|
|
712
|
+
while (page_ctx) {
|
|
713
|
+
nt_shm_page_ctx* prev = page_ctx->prev;
|
|
714
|
+
nt_shm_page* page_meta = page_ctx->shm_page;
|
|
715
|
+
|
|
716
|
+
if (page_meta) {
|
|
717
|
+
UnmapViewOfFile((void*) page_meta);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
if (page_ctx->handle) {
|
|
721
|
+
CloseHandle(page_ctx->handle);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
free(page_ctx);
|
|
725
|
+
page_ctx = prev;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Step 2: Unmap allocator metadata
|
|
729
|
+
nt_shm_allocator* allocator = ctx->shm_allocator;
|
|
730
|
+
if (allocator) {
|
|
731
|
+
pthread_mutex_destroy(&allocator->lock);
|
|
732
|
+
UnmapViewOfFile((void*) allocator);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Step 3: Close handles
|
|
736
|
+
if (ctx->shm_handle) CloseHandle(ctx->shm_handle);
|
|
737
|
+
if (ctx->lock_handle) CloseHandle(ctx->lock_handle);
|
|
738
|
+
|
|
739
|
+
// Step 4: Free context
|
|
740
|
+
free(ctx);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
static inline void* c_nt_shm_calloc(nt_shm_allocator_ctx* ctx, size_t size, pthread_mutex_t* lock) {
|
|
744
|
+
if (!ctx || !ctx->shm_allocator || size == 0) {
|
|
745
|
+
errno = EINVAL;
|
|
746
|
+
return NULL;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
size_t cap_net = c_nt_shm_block_roundup(size);
|
|
750
|
+
size_t cap_total = cap_net + c_nt_shm_block_overhead;
|
|
751
|
+
nt_shm_allocator* allocator = ctx->shm_allocator;
|
|
752
|
+
|
|
753
|
+
uint8_t locked = 0;
|
|
754
|
+
pthread_mutex_t* builtin_lock = &allocator->lock;
|
|
755
|
+
pthread_mutex_t* child_lock = &allocator->lock;
|
|
756
|
+
if (lock) {
|
|
757
|
+
if (lock == builtin_lock) child_lock = NULL;
|
|
758
|
+
int ret = pthread_mutex_lock(lock);
|
|
759
|
+
if (ret != 0) {
|
|
760
|
+
errno = ret;
|
|
761
|
+
return NULL;
|
|
762
|
+
}
|
|
763
|
+
locked = 1;
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
child_lock = NULL;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Ensure there's an active page with space
|
|
770
|
+
nt_shm_page_ctx* page_ctx = ctx->active_page;
|
|
771
|
+
if (!page_ctx) {
|
|
772
|
+
size_t target_cap = allocator->autopage_capacity;
|
|
773
|
+
while (target_cap < cap_total + c_nt_shm_page_overhead) {
|
|
774
|
+
target_cap *= 2;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
page_ctx = c_nt_shm_allocator_extend(ctx, target_cap, child_lock);
|
|
778
|
+
if (!page_ctx) {
|
|
779
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
780
|
+
return NULL;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
nt_shm_page* page_meta = page_ctx->shm_page;
|
|
785
|
+
|
|
786
|
+
if (page_meta->occupied + cap_total > page_meta->capacity) {
|
|
787
|
+
size_t target_cap = page_meta->capacity;
|
|
788
|
+
if (target_cap < allocator->autopage_capacity) {
|
|
789
|
+
target_cap = allocator->autopage_capacity;
|
|
790
|
+
}
|
|
791
|
+
else if (target_cap < allocator->autopage_capacity_max) {
|
|
792
|
+
target_cap *= 2;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
while (target_cap < cap_total + c_nt_shm_page_overhead) {
|
|
796
|
+
target_cap *= 2;
|
|
797
|
+
}
|
|
798
|
+
page_ctx = c_nt_shm_allocator_extend(ctx, target_cap, child_lock);
|
|
799
|
+
if (!page_ctx) {
|
|
800
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
801
|
+
return NULL;
|
|
802
|
+
}
|
|
803
|
+
page_meta = page_ctx->shm_page;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Allocate from active page
|
|
807
|
+
size_t offset = page_meta->occupied;
|
|
808
|
+
nt_shm_memory_block* block = (nt_shm_memory_block*) (page_ctx->buffer + offset);
|
|
809
|
+
block->capacity = cap_net;
|
|
810
|
+
block->size = size;
|
|
811
|
+
block->next_free = NULL;
|
|
812
|
+
block->parent_page = page_meta;
|
|
813
|
+
block->next_allocated = page_meta->allocated;
|
|
814
|
+
page_meta->allocated = block;
|
|
815
|
+
page_meta->occupied += cap_total;
|
|
816
|
+
|
|
817
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
818
|
+
|
|
819
|
+
memset(block + 1, 0, cap_net);
|
|
820
|
+
return (void*) block->buffer;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static inline void* c_nt_shm_request(nt_shm_allocator_ctx* ctx, size_t size, int scan_all_pages, pthread_mutex_t* lock) {
|
|
824
|
+
if (!ctx || !ctx->shm_allocator || size == 0) {
|
|
825
|
+
errno = EINVAL;
|
|
826
|
+
return NULL;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
size_t cap_net = c_nt_shm_block_roundup(size);
|
|
830
|
+
size_t cap_total = cap_net + c_nt_shm_block_overhead;
|
|
831
|
+
nt_shm_allocator* allocator = ctx->shm_allocator;
|
|
832
|
+
|
|
833
|
+
uint8_t locked = 0;
|
|
834
|
+
pthread_mutex_t* builtin_lock = &allocator->lock;
|
|
835
|
+
pthread_mutex_t* child_lock = &allocator->lock;
|
|
836
|
+
if (lock) {
|
|
837
|
+
if (lock == builtin_lock) child_lock = NULL;
|
|
838
|
+
int ret = pthread_mutex_lock(lock);
|
|
839
|
+
if (ret != 0) {
|
|
840
|
+
errno = ret;
|
|
841
|
+
return NULL;
|
|
842
|
+
}
|
|
843
|
+
locked = 1;
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
child_lock = NULL;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Step 1: Try free list reuse
|
|
850
|
+
nt_shm_memory_block** prevp = &allocator->free_list;
|
|
851
|
+
nt_shm_memory_block* free_blk = allocator->free_list;
|
|
852
|
+
while (free_blk) {
|
|
853
|
+
if (free_blk->capacity >= cap_net) {
|
|
854
|
+
*prevp = free_blk->next_free;
|
|
855
|
+
free_blk->next_free = NULL;
|
|
856
|
+
free_blk->size = size;
|
|
857
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
858
|
+
memset(free_blk + 1, 0, cap_net);
|
|
859
|
+
return (void*) free_blk->buffer;
|
|
860
|
+
}
|
|
861
|
+
prevp = &free_blk->next_free;
|
|
862
|
+
free_blk = free_blk->next_free;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Step 2: Locate a page with enough space
|
|
866
|
+
nt_shm_page_ctx* target_ctx = NULL;
|
|
867
|
+
if (scan_all_pages) {
|
|
868
|
+
nt_shm_page_ctx* iter = ctx->active_page;
|
|
869
|
+
while (iter) {
|
|
870
|
+
nt_shm_page* meta = iter->shm_page;
|
|
871
|
+
if (meta && meta->occupied + cap_total <= meta->capacity) {
|
|
872
|
+
target_ctx = iter;
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
iter = iter->prev;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
else if (ctx->active_page) {
|
|
879
|
+
nt_shm_page* meta = ctx->active_page->shm_page;
|
|
880
|
+
if (meta && meta->occupied + cap_total <= meta->capacity) {
|
|
881
|
+
target_ctx = ctx->active_page;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Step 3: Extend if no page fits
|
|
886
|
+
if (!target_ctx) {
|
|
887
|
+
nt_shm_page_ctx* current = ctx->active_page;
|
|
888
|
+
size_t target_cap;
|
|
889
|
+
|
|
890
|
+
if (!current) {
|
|
891
|
+
target_cap = allocator->autopage_capacity;
|
|
892
|
+
while (target_cap < cap_total + c_nt_shm_page_overhead) {
|
|
893
|
+
target_cap *= 2;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
size_t prev_cap = current->shm_page->capacity;
|
|
898
|
+
size_t new_cap = prev_cap;
|
|
899
|
+
|
|
900
|
+
if (new_cap < allocator->autopage_capacity) {
|
|
901
|
+
new_cap = allocator->autopage_capacity;
|
|
902
|
+
}
|
|
903
|
+
else if (new_cap < allocator->autopage_capacity_max) {
|
|
904
|
+
new_cap *= 2;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
while (new_cap < cap_total + c_nt_shm_page_overhead) {
|
|
908
|
+
new_cap *= 2;
|
|
909
|
+
}
|
|
910
|
+
target_cap = new_cap;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
target_ctx = c_nt_shm_allocator_extend(ctx, target_cap, child_lock);
|
|
914
|
+
if (!target_ctx) {
|
|
915
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
916
|
+
return NULL;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// Step 4: Allocate from target page
|
|
921
|
+
nt_shm_page* page_meta = target_ctx->shm_page;
|
|
922
|
+
size_t offset = page_meta->occupied;
|
|
923
|
+
nt_shm_memory_block* block = (nt_shm_memory_block*) (target_ctx->buffer + offset);
|
|
924
|
+
block->capacity = cap_net;
|
|
925
|
+
block->size = size;
|
|
926
|
+
block->next_free = NULL;
|
|
927
|
+
block->parent_page = page_meta;
|
|
928
|
+
block->next_allocated = page_meta->allocated;
|
|
929
|
+
page_meta->allocated = block;
|
|
930
|
+
page_meta->occupied += cap_total;
|
|
931
|
+
|
|
932
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
933
|
+
|
|
934
|
+
memset(block + 1, 0, cap_net);
|
|
935
|
+
return (void*) block->buffer;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
static inline void c_nt_shm_free(void* ptr, pthread_mutex_t* lock) {
|
|
939
|
+
if (!ptr) {
|
|
940
|
+
errno = EINVAL;
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
nt_shm_memory_block* block = (nt_shm_memory_block*) ((char*) ptr - c_nt_shm_block_overhead);
|
|
945
|
+
nt_shm_page* page = block->parent_page;
|
|
946
|
+
if (!page || !page->allocator) {
|
|
947
|
+
errno = EINVAL;
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
nt_shm_allocator* allocator = page->allocator;
|
|
952
|
+
|
|
953
|
+
uint8_t locked = 0;
|
|
954
|
+
if (lock) {
|
|
955
|
+
int ret = pthread_mutex_lock(lock);
|
|
956
|
+
if (ret != 0) {
|
|
957
|
+
errno = ret;
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
locked = 1;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
block->size = 0;
|
|
964
|
+
block->next_free = allocator->free_list;
|
|
965
|
+
allocator->free_list = block;
|
|
966
|
+
|
|
967
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
static inline void c_nt_shm_reclaim(nt_shm_allocator_ctx* ctx, pthread_mutex_t* lock) {
|
|
971
|
+
if (!ctx || !ctx->shm_allocator) {
|
|
972
|
+
errno = EINVAL;
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
uint8_t locked = 0;
|
|
977
|
+
if (lock) {
|
|
978
|
+
int ret = pthread_mutex_lock(lock);
|
|
979
|
+
if (ret != 0) {
|
|
980
|
+
errno = ret;
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
locked = 1;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
nt_shm_allocator* allocator = ctx->shm_allocator;
|
|
987
|
+
nt_shm_page_ctx* page_ctx = ctx->active_page;
|
|
988
|
+
while (page_ctx) {
|
|
989
|
+
c_nt_shm_page_reclaim(allocator, page_ctx);
|
|
990
|
+
page_ctx = page_ctx->prev;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (locked) pthread_mutex_unlock(lock);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
#endif // AP_SHM_C_NT_SHM_ALLOCATOR_H
|