knitting 0.1.46
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.
- package/LICENSE +202 -0
- package/README.md +632 -0
- package/knitting.d.ts +4 -0
- package/knitting.js +5 -0
- package/map.md +264 -0
- package/package.json +77 -0
- package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-arm64-node-127/knitting_shm.node +0 -0
- package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-arm64-node-137/knitting_shm.node +0 -0
- package/prebuilds/darwin-x64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-x64-node-127/knitting_shm.node +0 -0
- package/prebuilds/darwin-x64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-x64-node-137/knitting_shm.node +0 -0
- package/prebuilds/linux-x64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/linux-x64-node-127/knitting_shm.node +0 -0
- package/prebuilds/linux-x64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/linux-x64-node-137/knitting_shm.node +0 -0
- package/process-shared-buffer.d.ts +1 -0
- package/process-shared-buffer.js +1 -0
- package/scripts/build-native-addons.ts +295 -0
- package/src/api.d.ts +55 -0
- package/src/api.js +384 -0
- package/src/common/envelope.d.ts +11 -0
- package/src/common/envelope.js +8 -0
- package/src/common/module-url.d.ts +1 -0
- package/src/common/module-url.js +24 -0
- package/src/common/node-compat.d.ts +20 -0
- package/src/common/node-compat.js +24 -0
- package/src/common/path-canonical.d.ts +6 -0
- package/src/common/path-canonical.js +41 -0
- package/src/common/runtime.d.ts +15 -0
- package/src/common/runtime.js +91 -0
- package/src/common/shared-buffer-region.d.ts +11 -0
- package/src/common/shared-buffer-region.js +21 -0
- package/src/common/shared-buffer-text.d.ts +16 -0
- package/src/common/shared-buffer-text.js +65 -0
- package/src/common/task-source.d.ts +2 -0
- package/src/common/task-source.js +79 -0
- package/src/common/task-symbol.d.ts +1 -0
- package/src/common/task-symbol.js +1 -0
- package/src/common/with-resolvers.d.ts +9 -0
- package/src/common/with-resolvers.js +23 -0
- package/src/common/worker-runtime.d.ts +40 -0
- package/src/common/worker-runtime.js +52 -0
- package/src/connections/bun.d.ts +20 -0
- package/src/connections/bun.js +159 -0
- package/src/connections/deno.d.ts +20 -0
- package/src/connections/deno.js +150 -0
- package/src/connections/file-descriptor.d.ts +37 -0
- package/src/connections/file-descriptor.js +139 -0
- package/src/connections/index.d.ts +3 -0
- package/src/connections/index.js +3 -0
- package/src/connections/node-addons.d.ts +5 -0
- package/src/connections/node-addons.js +43 -0
- package/src/connections/node.d.ts +29 -0
- package/src/connections/node.js +59 -0
- package/src/connections/posix.d.ts +31 -0
- package/src/connections/posix.js +71 -0
- package/src/connections/process-shared-buffer.d.ts +67 -0
- package/src/connections/process-shared-buffer.js +267 -0
- package/src/connections/types.d.ts +48 -0
- package/src/connections/types.js +37 -0
- package/src/error.d.ts +13 -0
- package/src/error.js +49 -0
- package/src/ipc/tools/ring-queue.d.ts +33 -0
- package/src/ipc/tools/ring-queue.js +159 -0
- package/src/ipc/transport/shared-memory.d.ts +25 -0
- package/src/ipc/transport/shared-memory.js +35 -0
- package/src/knitting_shared_memory.cc +436 -0
- package/src/knitting_shm.cc +476 -0
- package/src/memory/byte-carpet.d.ts +73 -0
- package/src/memory/byte-carpet.js +157 -0
- package/src/memory/lock.d.ts +190 -0
- package/src/memory/lock.js +856 -0
- package/src/memory/payload-config.d.ts +22 -0
- package/src/memory/payload-config.js +67 -0
- package/src/memory/payloadCodec.d.ts +46 -0
- package/src/memory/payloadCodec.js +1157 -0
- package/src/memory/regionRegistry.d.ts +17 -0
- package/src/memory/regionRegistry.js +285 -0
- package/src/memory/shared-buffer-io.d.ts +53 -0
- package/src/memory/shared-buffer-io.js +380 -0
- package/src/permission/index.d.ts +2 -0
- package/src/permission/index.js +2 -0
- package/src/permission/protocol.d.ts +166 -0
- package/src/permission/protocol.js +640 -0
- package/src/runtime/balancer.d.ts +19 -0
- package/src/runtime/balancer.js +149 -0
- package/src/runtime/dispatcher.d.ts +34 -0
- package/src/runtime/dispatcher.js +142 -0
- package/src/runtime/inline-executor.d.ts +10 -0
- package/src/runtime/inline-executor.js +270 -0
- package/src/runtime/pool.d.ts +43 -0
- package/src/runtime/pool.js +922 -0
- package/src/runtime/tx-queue.d.ts +25 -0
- package/src/runtime/tx-queue.js +144 -0
- package/src/shared/abortSignal.d.ts +23 -0
- package/src/shared/abortSignal.js +126 -0
- package/src/types.d.ts +283 -0
- package/src/types.js +2 -0
- package/src/worker/composable-runners.d.ts +12 -0
- package/src/worker/composable-runners.js +105 -0
- package/src/worker/loop.d.ts +2 -0
- package/src/worker/loop.js +453 -0
- package/src/worker/rx-queue.d.ts +22 -0
- package/src/worker/rx-queue.js +124 -0
- package/src/worker/safety/index.d.ts +4 -0
- package/src/worker/safety/index.js +4 -0
- package/src/worker/safety/performance.d.ts +1 -0
- package/src/worker/safety/performance.js +17 -0
- package/src/worker/safety/process.d.ts +2 -0
- package/src/worker/safety/process.js +79 -0
- package/src/worker/safety/startup.d.ts +16 -0
- package/src/worker/safety/startup.js +30 -0
- package/src/worker/safety/worker-data.d.ts +2 -0
- package/src/worker/safety/worker-data.js +36 -0
- package/src/worker/task-loader.d.ts +26 -0
- package/src/worker/task-loader.js +66 -0
- package/src/worker/timers.d.ts +18 -0
- package/src/worker/timers.js +97 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
|
2
|
+
#define _GNU_SOURCE
|
|
3
|
+
#endif
|
|
4
|
+
|
|
5
|
+
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
|
|
6
|
+
#error "knitting_shared_memory.cc currently supports Linux, macOS, and Windows."
|
|
7
|
+
#endif
|
|
8
|
+
|
|
9
|
+
#include <node.h>
|
|
10
|
+
#include <v8.h>
|
|
11
|
+
|
|
12
|
+
#include <atomic>
|
|
13
|
+
#include <cerrno>
|
|
14
|
+
#include <cstdio>
|
|
15
|
+
#include <cstdint>
|
|
16
|
+
#include <cstring>
|
|
17
|
+
#include <memory>
|
|
18
|
+
#include <string>
|
|
19
|
+
|
|
20
|
+
#ifdef _WIN32
|
|
21
|
+
#define WIN32_LEAN_AND_MEAN
|
|
22
|
+
#include <windows.h>
|
|
23
|
+
|
|
24
|
+
#include <mutex>
|
|
25
|
+
#include <unordered_map>
|
|
26
|
+
#else
|
|
27
|
+
#include <fcntl.h>
|
|
28
|
+
#include <sys/mman.h>
|
|
29
|
+
#include <sys/stat.h>
|
|
30
|
+
#ifdef __linux__
|
|
31
|
+
#include <sys/syscall.h>
|
|
32
|
+
#endif
|
|
33
|
+
#include <unistd.h>
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
#ifndef MFD_CLOEXEC
|
|
37
|
+
#define MFD_CLOEXEC 0x0001U
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
namespace knitting_shared_memory {
|
|
41
|
+
|
|
42
|
+
constexpr size_t CACHE_LINE_SIZE = 64;
|
|
43
|
+
|
|
44
|
+
// Owns the OS resources behind one V8 SharedArrayBuffer. The JavaScript object
|
|
45
|
+
// keeps the V8 backing store alive; when it is collected, this mapping is
|
|
46
|
+
// unmapped and its per-view OS resource is closed.
|
|
47
|
+
struct SharedMapping {
|
|
48
|
+
#ifdef _WIN32
|
|
49
|
+
HANDLE handle = nullptr;
|
|
50
|
+
#else
|
|
51
|
+
int fd = -1;
|
|
52
|
+
#endif
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
size_t AlignUp(size_t value, size_t alignment) {
|
|
56
|
+
return (value + alignment - 1) & ~(alignment - 1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#ifndef _WIN32
|
|
60
|
+
bool SetCloseOnExec(int fd) {
|
|
61
|
+
int flags = fcntl(fd, F_GETFD);
|
|
62
|
+
if (flags == -1) return false;
|
|
63
|
+
return fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
int CreateSharedMemoryFd(const char* name) {
|
|
67
|
+
#ifdef __linux__
|
|
68
|
+
return static_cast<int>(syscall(SYS_memfd_create, name, MFD_CLOEXEC));
|
|
69
|
+
#else
|
|
70
|
+
(void)name;
|
|
71
|
+
static std::atomic<unsigned long> counter{0};
|
|
72
|
+
char shm_name[128];
|
|
73
|
+
|
|
74
|
+
for (int attempt = 0; attempt < 16; attempt++) {
|
|
75
|
+
unsigned long next = counter.fetch_add(1);
|
|
76
|
+
std::snprintf(
|
|
77
|
+
shm_name,
|
|
78
|
+
sizeof(shm_name),
|
|
79
|
+
"/knit_n_%05lx_%06lx_%02d",
|
|
80
|
+
static_cast<unsigned long>(getpid()) & 0xfffffUL,
|
|
81
|
+
next & 0xffffffUL,
|
|
82
|
+
attempt
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
int fd = shm_open(shm_name, O_CREAT | O_EXCL | O_RDWR, 0600);
|
|
86
|
+
if (fd >= 0) {
|
|
87
|
+
shm_unlink(shm_name);
|
|
88
|
+
if (SetCloseOnExec(fd)) return fd;
|
|
89
|
+
|
|
90
|
+
int saved = errno;
|
|
91
|
+
close(fd);
|
|
92
|
+
errno = saved;
|
|
93
|
+
return -1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (errno != EEXIST) return -1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
errno = EEXIST;
|
|
100
|
+
return -1;
|
|
101
|
+
#endif
|
|
102
|
+
}
|
|
103
|
+
#endif
|
|
104
|
+
|
|
105
|
+
void ThrowErrno(v8::Isolate* isolate, const char* message, int err = errno) {
|
|
106
|
+
std::string full = std::string(message) + ": " + std::strerror(err);
|
|
107
|
+
isolate->ThrowException(v8::Exception::Error(
|
|
108
|
+
v8::String::NewFromUtf8(isolate, full.c_str()).ToLocalChecked()
|
|
109
|
+
));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#ifdef _WIN32
|
|
113
|
+
void ThrowWindowsError(
|
|
114
|
+
v8::Isolate* isolate,
|
|
115
|
+
const char* message,
|
|
116
|
+
DWORD err = GetLastError()
|
|
117
|
+
) {
|
|
118
|
+
char* raw = nullptr;
|
|
119
|
+
DWORD len = FormatMessageA(
|
|
120
|
+
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
121
|
+
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
122
|
+
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
123
|
+
nullptr,
|
|
124
|
+
err,
|
|
125
|
+
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
126
|
+
reinterpret_cast<char*>(&raw),
|
|
127
|
+
0,
|
|
128
|
+
nullptr
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
std::string detail = len > 0 && raw != nullptr
|
|
132
|
+
? std::string(raw, len)
|
|
133
|
+
: "Windows error " + std::to_string(static_cast<unsigned long>(err));
|
|
134
|
+
if (raw != nullptr) LocalFree(raw);
|
|
135
|
+
|
|
136
|
+
while (!detail.empty() && (detail.back() == '\n' || detail.back() == '\r')) {
|
|
137
|
+
detail.pop_back();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
std::string full = std::string(message) + ": " + detail;
|
|
141
|
+
isolate->ThrowException(v8::Exception::Error(
|
|
142
|
+
v8::String::NewFromUtf8(isolate, full.c_str()).ToLocalChecked()
|
|
143
|
+
));
|
|
144
|
+
}
|
|
145
|
+
#endif
|
|
146
|
+
|
|
147
|
+
void ThrowType(v8::Isolate* isolate, const char* message) {
|
|
148
|
+
isolate->ThrowException(v8::Exception::TypeError(
|
|
149
|
+
v8::String::NewFromUtf8(isolate, message).ToLocalChecked()
|
|
150
|
+
));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void ThrowRange(v8::Isolate* isolate, const char* message) {
|
|
154
|
+
isolate->ThrowException(v8::Exception::RangeError(
|
|
155
|
+
v8::String::NewFromUtf8(isolate, message).ToLocalChecked()
|
|
156
|
+
));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#ifdef _WIN32
|
|
160
|
+
std::atomic<int> next_mapping_id{1};
|
|
161
|
+
std::mutex registry_mutex;
|
|
162
|
+
std::unordered_map<int, HANDLE> registry_handles;
|
|
163
|
+
|
|
164
|
+
bool DuplicateHandleInCurrentProcess(HANDLE source, HANDLE* out) {
|
|
165
|
+
return DuplicateHandle(
|
|
166
|
+
GetCurrentProcess(),
|
|
167
|
+
source,
|
|
168
|
+
GetCurrentProcess(),
|
|
169
|
+
out,
|
|
170
|
+
0,
|
|
171
|
+
FALSE,
|
|
172
|
+
DUPLICATE_SAME_ACCESS
|
|
173
|
+
) != 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
int RegisterPublicMappingHandle(HANDLE handle) {
|
|
177
|
+
HANDLE public_handle = nullptr;
|
|
178
|
+
if (!DuplicateHandleInCurrentProcess(handle, &public_handle)) {
|
|
179
|
+
return -1;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
int id = next_mapping_id.fetch_add(1);
|
|
183
|
+
if (id <= 0) {
|
|
184
|
+
CloseHandle(public_handle);
|
|
185
|
+
return -1;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
std::lock_guard<std::mutex> lock(registry_mutex);
|
|
189
|
+
registry_handles.emplace(id, public_handle);
|
|
190
|
+
return id;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
HANDLE DuplicateRegisteredMappingHandle(int id) {
|
|
194
|
+
HANDLE source = nullptr;
|
|
195
|
+
{
|
|
196
|
+
std::lock_guard<std::mutex> lock(registry_mutex);
|
|
197
|
+
auto found = registry_handles.find(id);
|
|
198
|
+
if (found == registry_handles.end()) return nullptr;
|
|
199
|
+
source = found->second;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
HANDLE duplicate = nullptr;
|
|
203
|
+
if (!DuplicateHandleInCurrentProcess(source, &duplicate)) {
|
|
204
|
+
return nullptr;
|
|
205
|
+
}
|
|
206
|
+
return duplicate;
|
|
207
|
+
}
|
|
208
|
+
#endif
|
|
209
|
+
|
|
210
|
+
void MappingDeleter(void* data, size_t length, void* deleter_data) {
|
|
211
|
+
#ifdef _WIN32
|
|
212
|
+
if (data != nullptr) {
|
|
213
|
+
UnmapViewOfFile(data);
|
|
214
|
+
}
|
|
215
|
+
#else
|
|
216
|
+
if (data != nullptr && length > 0) {
|
|
217
|
+
munmap(data, length);
|
|
218
|
+
}
|
|
219
|
+
#endif
|
|
220
|
+
|
|
221
|
+
SharedMapping* mapping = static_cast<SharedMapping*>(deleter_data);
|
|
222
|
+
if (mapping != nullptr) {
|
|
223
|
+
#ifdef _WIN32
|
|
224
|
+
if (mapping->handle != nullptr) CloseHandle(mapping->handle);
|
|
225
|
+
#else
|
|
226
|
+
if (mapping->fd >= 0) close(mapping->fd);
|
|
227
|
+
#endif
|
|
228
|
+
delete mapping;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
void SetValue(
|
|
233
|
+
v8::Isolate* isolate,
|
|
234
|
+
v8::Local<v8::Context> context,
|
|
235
|
+
v8::Local<v8::Object> object,
|
|
236
|
+
const char* key,
|
|
237
|
+
v8::Local<v8::Value> value
|
|
238
|
+
) {
|
|
239
|
+
object->Set(
|
|
240
|
+
context,
|
|
241
|
+
v8::String::NewFromUtf8(isolate, key).ToLocalChecked(),
|
|
242
|
+
value
|
|
243
|
+
).Check();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
void ReturnMappedRegion(
|
|
247
|
+
const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
248
|
+
#ifdef _WIN32
|
|
249
|
+
HANDLE handle,
|
|
250
|
+
int fd,
|
|
251
|
+
#else
|
|
252
|
+
int fd,
|
|
253
|
+
#endif
|
|
254
|
+
size_t size
|
|
255
|
+
) {
|
|
256
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
257
|
+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
258
|
+
|
|
259
|
+
#ifdef _WIN32
|
|
260
|
+
void* mapped = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, size);
|
|
261
|
+
if (mapped == nullptr) {
|
|
262
|
+
DWORD saved = GetLastError();
|
|
263
|
+
CloseHandle(handle);
|
|
264
|
+
ThrowWindowsError(isolate, "MapViewOfFile failed", saved);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
#else
|
|
268
|
+
void* mapped = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
269
|
+
if (mapped == MAP_FAILED) {
|
|
270
|
+
int saved = errno;
|
|
271
|
+
close(fd);
|
|
272
|
+
ThrowErrno(isolate, "mmap failed", saved);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
#endif
|
|
276
|
+
|
|
277
|
+
auto* mapping = new SharedMapping();
|
|
278
|
+
#ifdef _WIN32
|
|
279
|
+
mapping->handle = handle;
|
|
280
|
+
#else
|
|
281
|
+
mapping->fd = fd;
|
|
282
|
+
#endif
|
|
283
|
+
|
|
284
|
+
auto backing = v8::SharedArrayBuffer::NewBackingStore(
|
|
285
|
+
mapped,
|
|
286
|
+
size,
|
|
287
|
+
MappingDeleter,
|
|
288
|
+
mapping
|
|
289
|
+
);
|
|
290
|
+
auto shared = std::shared_ptr<v8::BackingStore>(std::move(backing));
|
|
291
|
+
v8::Local<v8::SharedArrayBuffer> sab =
|
|
292
|
+
v8::SharedArrayBuffer::New(isolate, shared);
|
|
293
|
+
|
|
294
|
+
v8::Local<v8::Object> out = v8::Object::New(isolate);
|
|
295
|
+
SetValue(isolate, context, out, "sab", sab);
|
|
296
|
+
SetValue(isolate, context, out, "fd", v8::Integer::New(isolate, fd));
|
|
297
|
+
SetValue(
|
|
298
|
+
isolate,
|
|
299
|
+
context,
|
|
300
|
+
out,
|
|
301
|
+
"size",
|
|
302
|
+
v8::Number::New(isolate, static_cast<double>(size))
|
|
303
|
+
);
|
|
304
|
+
SetValue(
|
|
305
|
+
isolate,
|
|
306
|
+
context,
|
|
307
|
+
out,
|
|
308
|
+
"baseAddressMod64",
|
|
309
|
+
v8::Integer::New(
|
|
310
|
+
isolate,
|
|
311
|
+
static_cast<int>(reinterpret_cast<uintptr_t>(mapped) % CACHE_LINE_SIZE)
|
|
312
|
+
)
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
args.GetReturnValue().Set(out);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
void CreateSharedMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
319
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
320
|
+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
321
|
+
|
|
322
|
+
if (args.Length() < 1 || !args[0]->IsNumber()) {
|
|
323
|
+
ThrowType(isolate, "createSharedMemory(size) requires size");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
v8::Maybe<int64_t> maybe_size = args[0]->IntegerValue(context);
|
|
328
|
+
if (maybe_size.IsNothing() || maybe_size.FromJust() <= 0) {
|
|
329
|
+
ThrowRange(isolate, "size must be positive");
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
size_t size = AlignUp(static_cast<size_t>(maybe_size.FromJust()), CACHE_LINE_SIZE);
|
|
334
|
+
|
|
335
|
+
#ifdef _WIN32
|
|
336
|
+
uint64_t wide_size = static_cast<uint64_t>(size);
|
|
337
|
+
HANDLE handle = CreateFileMappingW(
|
|
338
|
+
INVALID_HANDLE_VALUE,
|
|
339
|
+
nullptr,
|
|
340
|
+
PAGE_READWRITE,
|
|
341
|
+
static_cast<DWORD>(wide_size >> 32),
|
|
342
|
+
static_cast<DWORD>(wide_size & 0xffffffffULL),
|
|
343
|
+
nullptr
|
|
344
|
+
);
|
|
345
|
+
if (handle == nullptr) {
|
|
346
|
+
ThrowWindowsError(isolate, "CreateFileMappingW failed");
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
int fd = RegisterPublicMappingHandle(handle);
|
|
351
|
+
if (fd < 0) {
|
|
352
|
+
DWORD saved = GetLastError();
|
|
353
|
+
CloseHandle(handle);
|
|
354
|
+
ThrowWindowsError(isolate, "DuplicateHandle failed", saved);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
ReturnMappedRegion(args, handle, fd, size);
|
|
359
|
+
#else
|
|
360
|
+
int fd = CreateSharedMemoryFd("knitting_shared_memory");
|
|
361
|
+
if (fd == -1) {
|
|
362
|
+
ThrowErrno(isolate, "shared memory fd create failed");
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (ftruncate(fd, static_cast<off_t>(size)) == -1) {
|
|
367
|
+
int saved = errno;
|
|
368
|
+
close(fd);
|
|
369
|
+
ThrowErrno(isolate, "ftruncate failed", saved);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
ReturnMappedRegion(args, fd, size);
|
|
374
|
+
#endif
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
void MapSharedMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
378
|
+
v8::Isolate* isolate = args.GetIsolate();
|
|
379
|
+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
380
|
+
|
|
381
|
+
if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) {
|
|
382
|
+
ThrowType(isolate, "mapSharedMemory(fd, size) requires fd and size");
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
v8::Maybe<int32_t> maybe_fd = args[0]->Int32Value(context);
|
|
387
|
+
v8::Maybe<int64_t> maybe_size = args[1]->IntegerValue(context);
|
|
388
|
+
if (
|
|
389
|
+
maybe_fd.IsNothing() ||
|
|
390
|
+
maybe_size.IsNothing() ||
|
|
391
|
+
maybe_fd.FromJust() < 0 ||
|
|
392
|
+
maybe_size.FromJust() <= 0
|
|
393
|
+
) {
|
|
394
|
+
ThrowRange(isolate, "fd and size must be positive");
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
size_t size = AlignUp(static_cast<size_t>(maybe_size.FromJust()), CACHE_LINE_SIZE);
|
|
399
|
+
|
|
400
|
+
#ifdef _WIN32
|
|
401
|
+
int fd = maybe_fd.FromJust();
|
|
402
|
+
HANDLE handle = DuplicateRegisteredMappingHandle(fd);
|
|
403
|
+
if (handle == nullptr) {
|
|
404
|
+
ThrowWindowsError(isolate, "DuplicateHandle failed");
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
ReturnMappedRegion(args, handle, fd, size);
|
|
409
|
+
#else
|
|
410
|
+
// Duplicate so each returned SAB owns exactly one fd. The caller can keep
|
|
411
|
+
// using or transferring its original descriptor independently.
|
|
412
|
+
int fd = dup(maybe_fd.FromJust());
|
|
413
|
+
if (fd == -1) {
|
|
414
|
+
ThrowErrno(isolate, "dup(fd) failed");
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (!SetCloseOnExec(fd)) {
|
|
419
|
+
int saved = errno;
|
|
420
|
+
close(fd);
|
|
421
|
+
ThrowErrno(isolate, "fcntl(F_SETFD) failed", saved);
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
ReturnMappedRegion(args, fd, size);
|
|
426
|
+
#endif
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
void Initialize(v8::Local<v8::Object> exports) {
|
|
430
|
+
NODE_SET_METHOD(exports, "createSharedMemory", CreateSharedMemory);
|
|
431
|
+
NODE_SET_METHOD(exports, "mapSharedMemory", MapSharedMemory);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
|
|
435
|
+
|
|
436
|
+
} // namespace knitting_shared_memory
|