knitting 0.1.46 → 0.1.51
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/README.md +326 -95
- package/map.md +52 -8
- package/package.json +4 -3
- package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-x64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-x64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/linux-x64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/linux-x64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/win32-x64/knitting_windows_shared_memory.dll +0 -0
- package/prebuilds/win32-x64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/win32-x64-node-127/knitting_shm.node +0 -0
- package/prebuilds/win32-x64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/win32-x64-node-137/knitting_shm.node +0 -0
- package/scripts/build-native-addons.ts +31 -5
- package/src/api.d.ts +3 -2
- package/src/api.js +135 -34
- package/src/common/task-source.d.ts +1 -0
- package/src/common/task-source.js +5 -0
- package/src/connections/bun.d.ts +2 -0
- package/src/connections/bun.js +64 -9
- package/src/connections/deno.d.ts +2 -0
- package/src/connections/deno.js +64 -9
- package/src/connections/file-descriptor.d.ts +2 -0
- package/src/connections/file-descriptor.js +24 -2
- package/src/connections/node.d.ts +2 -1
- package/src/connections/node.js +17 -14
- package/src/connections/posix.d.ts +1 -0
- package/src/connections/posix.js +6 -0
- package/src/connections/process-shared-buffer.d.ts +3 -1
- package/src/connections/process-shared-buffer.js +19 -13
- package/src/connections/types.d.ts +2 -0
- package/src/connections/windows.d.ts +28 -0
- package/src/connections/windows.js +224 -0
- package/src/knitting_shared_memory.cc +319 -26
- package/src/knitting_windows_shared_memory.cc +156 -0
- package/src/memory/lock.js +8 -168
- package/src/memory/payloadCodec.js +28 -34
- package/src/memory/shared-buffer-io.d.ts +2 -0
- package/src/memory/shared-buffer-io.js +23 -0
- package/src/runtime/inline-executor.d.ts +2 -2
- package/src/runtime/inline-executor.js +15 -3
- package/src/runtime/pool.d.ts +3 -14
- package/src/runtime/pool.js +12 -543
- package/src/runtime/process-worker.d.ts +92 -0
- package/src/runtime/process-worker.js +670 -0
- package/src/runtime/tx-queue.d.ts +1 -1
- package/src/runtime/tx-queue.js +3 -1
- package/src/shared/abortSignal.d.ts +1 -1
- package/src/shared/abortSignal.js +10 -2
- package/src/types.d.ts +67 -8
- package/src/worker/bootstrap.d.ts +5 -0
- package/src/worker/bootstrap.js +78 -0
- package/src/worker/composable-runners.js +0 -8
- package/src/worker/loop.js +23 -156
- package/src/worker/process-worker-bootstrap.d.ts +8 -0
- package/src/worker/process-worker-bootstrap.js +160 -0
- package/src/worker/safety/startup.d.ts +2 -1
- package/src/worker/safety/startup.js +5 -2
- package/src/worker/task-loader.d.ts +2 -1
- package/src/worker/task-loader.js +14 -2
- package/src/worker/timers.js +19 -5
package/src/connections/bun.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { DARWIN_O_CREAT, DARWIN_O_EXCL, DARWIN_SHM_MODE, setCloseOnExec, detectPosixPlatform, encodeCString, getPosixLibcPath, makeDarwinSharedMemoryName, MAP_SHARED, O_RDWR, PROT_READ, PROT_WRITE, } from "./posix.js";
|
|
2
|
-
import { expectFd, expectPositiveSize, readCreateName, readCreateSize, } from "./types.js";
|
|
1
|
+
import { DARWIN_O_CREAT, DARWIN_O_EXCL, DARWIN_SHM_MODE, LINUX_O_CREAT, LINUX_O_EXCL, setCloseOnExec, detectPosixPlatform, encodeCString, getPosixLibcPath, makeDarwinSharedMemoryName, MAP_SHARED, O_RDWR, POSIX_SHM_MODE, PROT_READ, PROT_WRITE, toPosixSharedMemoryName, } from "./posix.js";
|
|
2
|
+
import { expectFd, expectPositiveSize, readCreateName, readCreateMode, readRequiredCreateName, readCreateSize, } from "./types.js";
|
|
3
|
+
import { createBunWindowsConnectionPrimitives, isWindowsRuntime, } from "./windows.js";
|
|
3
4
|
const FFIType = {
|
|
4
5
|
i32: 5,
|
|
5
6
|
i64: 7,
|
|
@@ -65,6 +66,14 @@ const getBunCreateSymbols = (platform = detectPosixPlatform()) => platform === "
|
|
|
65
66
|
args: [FFIType.ptr, FFIType.u32],
|
|
66
67
|
returns: FFIType.i32,
|
|
67
68
|
},
|
|
69
|
+
shm_open: {
|
|
70
|
+
args: [FFIType.ptr, FFIType.i32, FFIType.u32],
|
|
71
|
+
returns: FFIType.i32,
|
|
72
|
+
},
|
|
73
|
+
shm_unlink: {
|
|
74
|
+
args: [FFIType.ptr],
|
|
75
|
+
returns: FFIType.i32,
|
|
76
|
+
},
|
|
68
77
|
};
|
|
69
78
|
const checkResult = (result, message) => {
|
|
70
79
|
if (result < 0)
|
|
@@ -103,11 +112,33 @@ const createBunSharedMemoryFd = (name, platform, libc) => {
|
|
|
103
112
|
throw error;
|
|
104
113
|
}
|
|
105
114
|
};
|
|
115
|
+
const createNamedBunSharedMemoryFd = (name, mode, platform, libc) => {
|
|
116
|
+
const shmOpen = libc.symbols.shm_open;
|
|
117
|
+
if (shmOpen === undefined) {
|
|
118
|
+
throw new Error("shm_open symbol is not available");
|
|
119
|
+
}
|
|
120
|
+
const createFlags = platform === "darwin" ? DARWIN_O_CREAT : LINUX_O_CREAT;
|
|
121
|
+
const exclusiveFlags = platform === "darwin" ? DARWIN_O_EXCL : LINUX_O_EXCL;
|
|
122
|
+
const flags = mode === "create"
|
|
123
|
+
? O_RDWR | createFlags | exclusiveFlags
|
|
124
|
+
: O_RDWR;
|
|
125
|
+
const fd = checkResult(shmOpen(encodeCString(toPosixSharedMemoryName(name)), flags, platform === "darwin" ? DARWIN_SHM_MODE : POSIX_SHM_MODE), "shm_open failed");
|
|
126
|
+
try {
|
|
127
|
+
return setCloseOnExec(libc, fd);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
libc.symbols.close(fd);
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
106
134
|
export const mapBunSharedMemory = (options, libc = openBunLibc()) => {
|
|
107
|
-
const sourceFd = expectFd(options.fd);
|
|
135
|
+
const sourceFd = options.name === undefined ? expectFd(options.fd) : -1;
|
|
108
136
|
const size = expectPositiveSize(options.size);
|
|
109
137
|
let fd = sourceFd;
|
|
110
|
-
if (options.
|
|
138
|
+
if (options.name !== undefined) {
|
|
139
|
+
fd = createNamedBunSharedMemoryFd(options.name, "open", detectPosixPlatform(), libc);
|
|
140
|
+
}
|
|
141
|
+
else if (options.duplicateFd !== false) {
|
|
111
142
|
fd = checkResult(libc.symbols.dup(sourceFd), "dup(fd) failed");
|
|
112
143
|
try {
|
|
113
144
|
setCloseOnExec(libc, fd);
|
|
@@ -127,6 +158,7 @@ export const mapBunSharedMemory = (options, libc = openBunLibc()) => {
|
|
|
127
158
|
return {
|
|
128
159
|
runtime: "bun",
|
|
129
160
|
fd,
|
|
161
|
+
name: options.name,
|
|
130
162
|
size,
|
|
131
163
|
byteLength: arrayBuffer.byteLength,
|
|
132
164
|
buffer: arrayBuffer,
|
|
@@ -141,19 +173,42 @@ export const mapBunSharedMemory = (options, libc = openBunLibc()) => {
|
|
|
141
173
|
};
|
|
142
174
|
export const createBunSharedMemory = (options, libc = openBunLibc()) => {
|
|
143
175
|
const size = expectPositiveSize(readCreateSize(options));
|
|
144
|
-
const
|
|
145
|
-
const
|
|
176
|
+
const mode = readCreateMode(options);
|
|
177
|
+
const name = mode === "anonymous"
|
|
178
|
+
? readCreateName(options, "knitting_shared_memory")
|
|
179
|
+
: readRequiredCreateName(options);
|
|
180
|
+
const platform = detectPosixPlatform();
|
|
181
|
+
const fd = mode === "anonymous"
|
|
182
|
+
? createBunSharedMemoryFd(name, platform, libc)
|
|
183
|
+
: createNamedBunSharedMemoryFd(name, mode, platform, libc);
|
|
146
184
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
185
|
+
if (mode !== "open") {
|
|
186
|
+
checkResult(libc.symbols.ftruncate(fd, BigInt(size)), "ftruncate failed");
|
|
187
|
+
}
|
|
188
|
+
const mapping = mapBunSharedMemory({ fd, size, duplicateFd: false }, libc);
|
|
189
|
+
if (mode !== "anonymous") {
|
|
190
|
+
return { ...mapping, name };
|
|
191
|
+
}
|
|
192
|
+
return mapping;
|
|
149
193
|
}
|
|
150
194
|
catch (error) {
|
|
151
195
|
libc.symbols.close(fd);
|
|
152
196
|
throw error;
|
|
153
197
|
}
|
|
154
198
|
};
|
|
155
|
-
export const
|
|
199
|
+
export const unlinkBunSharedMemory = (name, libc = openBunLibc()) => {
|
|
200
|
+
const shmUnlink = libc.symbols.shm_unlink;
|
|
201
|
+
if (shmUnlink === undefined) {
|
|
202
|
+
throw new Error("shm_unlink symbol is not available");
|
|
203
|
+
}
|
|
204
|
+
return shmUnlink(encodeCString(toPosixSharedMemoryName(name))) === 0;
|
|
205
|
+
};
|
|
206
|
+
export const createBunPosixConnectionPrimitives = (libc = openBunLibc()) => ({
|
|
156
207
|
runtime: "bun",
|
|
157
208
|
createSharedMemory: (options) => createBunSharedMemory(options, libc),
|
|
158
209
|
mapSharedMemory: (options) => mapBunSharedMemory(options, libc),
|
|
210
|
+
unlinkSharedMemory: (name) => unlinkBunSharedMemory(name, libc),
|
|
159
211
|
});
|
|
212
|
+
export const createBunConnectionPrimitives = (libc) => isWindowsRuntime()
|
|
213
|
+
? createBunWindowsConnectionPrimitives()
|
|
214
|
+
: createBunPosixConnectionPrimitives(libc);
|
|
@@ -16,5 +16,7 @@ type DenoLibc = {
|
|
|
16
16
|
export declare const openDenoLibc: () => DenoLibc;
|
|
17
17
|
export declare const mapDenoSharedMemory: (options: MapSharedMemoryOptions, libc?: DenoLibc) => SharedMemoryMapping<ArrayBuffer>;
|
|
18
18
|
export declare const createDenoSharedMemory: (options: number | CreateSharedMemoryOptions, libc?: DenoLibc) => SharedMemoryMapping<ArrayBuffer>;
|
|
19
|
+
export declare const unlinkDenoSharedMemory: (name: string, libc?: DenoLibc) => boolean;
|
|
20
|
+
export declare const createDenoPosixConnectionPrimitives: (libc?: DenoLibc) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
|
|
19
21
|
export declare const createDenoConnectionPrimitives: (libc?: DenoLibc) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
|
|
20
22
|
export {};
|
package/src/connections/deno.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { DARWIN_O_CREAT, DARWIN_O_EXCL, DARWIN_SHM_MODE, setCloseOnExec, detectPosixPlatform, encodeCString, getPosixLibcPath, makeDarwinSharedMemoryName, MAP_SHARED, O_RDWR, PROT_READ, PROT_WRITE, } from "./posix.js";
|
|
2
|
-
import { expectFd, expectPositiveSize, readCreateName, readCreateSize, } from "./types.js";
|
|
1
|
+
import { DARWIN_O_CREAT, DARWIN_O_EXCL, DARWIN_SHM_MODE, LINUX_O_CREAT, LINUX_O_EXCL, setCloseOnExec, detectPosixPlatform, encodeCString, getPosixLibcPath, makeDarwinSharedMemoryName, MAP_SHARED, O_RDWR, POSIX_SHM_MODE, PROT_READ, PROT_WRITE, toPosixSharedMemoryName, } from "./posix.js";
|
|
2
|
+
import { expectFd, expectPositiveSize, readCreateName, readCreateMode, readRequiredCreateName, readCreateSize, } from "./types.js";
|
|
3
|
+
import { createDenoWindowsConnectionPrimitives, isWindowsRuntime, } from "./windows.js";
|
|
3
4
|
const getDeno = () => {
|
|
4
5
|
const deno = globalThis.Deno;
|
|
5
6
|
if (deno === undefined) {
|
|
@@ -50,6 +51,14 @@ const getDenoCreateSymbols = (platform = detectPosixPlatform()) => platform ===
|
|
|
50
51
|
parameters: ["buffer", "u32"],
|
|
51
52
|
result: "i32",
|
|
52
53
|
},
|
|
54
|
+
shm_open: {
|
|
55
|
+
parameters: ["buffer", "i32", "u32"],
|
|
56
|
+
result: "i32",
|
|
57
|
+
},
|
|
58
|
+
shm_unlink: {
|
|
59
|
+
parameters: ["buffer"],
|
|
60
|
+
result: "i32",
|
|
61
|
+
},
|
|
53
62
|
};
|
|
54
63
|
const checkResult = (result, message) => {
|
|
55
64
|
if (result < 0)
|
|
@@ -93,11 +102,33 @@ const createDenoSharedMemoryFd = (name, platform, libc) => {
|
|
|
93
102
|
throw error;
|
|
94
103
|
}
|
|
95
104
|
};
|
|
105
|
+
const createNamedDenoSharedMemoryFd = (name, mode, platform, libc) => {
|
|
106
|
+
const shmOpen = libc.symbols.shm_open;
|
|
107
|
+
if (shmOpen === undefined) {
|
|
108
|
+
throw new Error("shm_open symbol is not available");
|
|
109
|
+
}
|
|
110
|
+
const createFlags = platform === "darwin" ? DARWIN_O_CREAT : LINUX_O_CREAT;
|
|
111
|
+
const exclusiveFlags = platform === "darwin" ? DARWIN_O_EXCL : LINUX_O_EXCL;
|
|
112
|
+
const flags = mode === "create"
|
|
113
|
+
? O_RDWR | createFlags | exclusiveFlags
|
|
114
|
+
: O_RDWR;
|
|
115
|
+
const fd = checkResult(shmOpen(encodeCString(toPosixSharedMemoryName(name)), flags, platform === "darwin" ? DARWIN_SHM_MODE : POSIX_SHM_MODE), "shm_open failed");
|
|
116
|
+
try {
|
|
117
|
+
return setCloseOnExec(libc, fd);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
libc.symbols.close(fd);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
96
124
|
export const mapDenoSharedMemory = (options, libc = openDenoLibc()) => {
|
|
97
|
-
const sourceFd = expectFd(options.fd);
|
|
125
|
+
const sourceFd = options.name === undefined ? expectFd(options.fd) : -1;
|
|
98
126
|
const size = expectPositiveSize(options.size);
|
|
99
127
|
let fd = sourceFd;
|
|
100
|
-
if (options.
|
|
128
|
+
if (options.name !== undefined) {
|
|
129
|
+
fd = createNamedDenoSharedMemoryFd(options.name, "open", detectPosixPlatform(), libc);
|
|
130
|
+
}
|
|
131
|
+
else if (options.duplicateFd !== false) {
|
|
101
132
|
fd = checkResult(libc.symbols.dup(sourceFd), "dup(fd) failed");
|
|
102
133
|
try {
|
|
103
134
|
setCloseOnExec(libc, fd);
|
|
@@ -118,6 +149,7 @@ export const mapDenoSharedMemory = (options, libc = openDenoLibc()) => {
|
|
|
118
149
|
return {
|
|
119
150
|
runtime: "deno",
|
|
120
151
|
fd,
|
|
152
|
+
name: options.name,
|
|
121
153
|
size,
|
|
122
154
|
byteLength: arrayBuffer.byteLength,
|
|
123
155
|
buffer: arrayBuffer,
|
|
@@ -132,19 +164,42 @@ export const mapDenoSharedMemory = (options, libc = openDenoLibc()) => {
|
|
|
132
164
|
};
|
|
133
165
|
export const createDenoSharedMemory = (options, libc = openDenoLibc()) => {
|
|
134
166
|
const size = expectPositiveSize(readCreateSize(options));
|
|
135
|
-
const
|
|
136
|
-
const
|
|
167
|
+
const mode = readCreateMode(options);
|
|
168
|
+
const name = mode === "anonymous"
|
|
169
|
+
? readCreateName(options, "knitting_shared_memory")
|
|
170
|
+
: readRequiredCreateName(options);
|
|
171
|
+
const platform = detectPosixPlatform();
|
|
172
|
+
const fd = mode === "anonymous"
|
|
173
|
+
? createDenoSharedMemoryFd(name, platform, libc)
|
|
174
|
+
: createNamedDenoSharedMemoryFd(name, mode, platform, libc);
|
|
137
175
|
try {
|
|
138
|
-
|
|
139
|
-
|
|
176
|
+
if (mode !== "open") {
|
|
177
|
+
checkResult(libc.symbols.ftruncate(fd, BigInt(size)), "ftruncate failed");
|
|
178
|
+
}
|
|
179
|
+
const mapping = mapDenoSharedMemory({ fd, size, duplicateFd: false }, libc);
|
|
180
|
+
if (mode !== "anonymous") {
|
|
181
|
+
return { ...mapping, name };
|
|
182
|
+
}
|
|
183
|
+
return mapping;
|
|
140
184
|
}
|
|
141
185
|
catch (error) {
|
|
142
186
|
libc.symbols.close(fd);
|
|
143
187
|
throw error;
|
|
144
188
|
}
|
|
145
189
|
};
|
|
146
|
-
export const
|
|
190
|
+
export const unlinkDenoSharedMemory = (name, libc = openDenoLibc()) => {
|
|
191
|
+
const shmUnlink = libc.symbols.shm_unlink;
|
|
192
|
+
if (shmUnlink === undefined) {
|
|
193
|
+
throw new Error("shm_unlink symbol is not available");
|
|
194
|
+
}
|
|
195
|
+
return shmUnlink(encodeCString(toPosixSharedMemoryName(name))) === 0;
|
|
196
|
+
};
|
|
197
|
+
export const createDenoPosixConnectionPrimitives = (libc = openDenoLibc()) => ({
|
|
147
198
|
runtime: "deno",
|
|
148
199
|
createSharedMemory: (options) => createDenoSharedMemory(options, libc),
|
|
149
200
|
mapSharedMemory: (options) => mapDenoSharedMemory(options, libc),
|
|
201
|
+
unlinkSharedMemory: (name) => unlinkDenoSharedMemory(name, libc),
|
|
150
202
|
});
|
|
203
|
+
export const createDenoConnectionPrimitives = (libc) => isWindowsRuntime()
|
|
204
|
+
? createDenoWindowsConnectionPrimitives()
|
|
205
|
+
: createDenoPosixConnectionPrimitives(libc);
|
|
@@ -2,6 +2,7 @@ import { type ConnectionRuntime, type SharedMemoryBuffer, type SharedMemoryConne
|
|
|
2
2
|
export type FileDescriptorMetadata = {
|
|
3
3
|
version: 1;
|
|
4
4
|
fd: number;
|
|
5
|
+
name?: string;
|
|
5
6
|
size: number;
|
|
6
7
|
byteLength: number;
|
|
7
8
|
runtime?: ConnectionRuntime;
|
|
@@ -12,6 +13,7 @@ type FileDescriptorMapper = Pick<SharedMemoryConnectionPrimitives, "mapSharedMem
|
|
|
12
13
|
export declare class FileDescriptor {
|
|
13
14
|
#private;
|
|
14
15
|
readonly fd: number;
|
|
16
|
+
readonly name?: string;
|
|
15
17
|
readonly size: number;
|
|
16
18
|
readonly byteLength: number;
|
|
17
19
|
readonly runtime?: ConnectionRuntime;
|
|
@@ -24,8 +24,20 @@ const readOptionalNumber = (value, label) => {
|
|
|
24
24
|
}
|
|
25
25
|
return Math.trunc(value);
|
|
26
26
|
};
|
|
27
|
+
const readOptionalName = (value) => {
|
|
28
|
+
if (value === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
31
|
+
throw new TypeError("file descriptor name must be a non-empty string when provided");
|
|
32
|
+
}
|
|
33
|
+
if (value.includes("\0")) {
|
|
34
|
+
throw new TypeError("file descriptor name must not contain NUL bytes");
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
27
38
|
export class FileDescriptor {
|
|
28
39
|
fd;
|
|
40
|
+
name;
|
|
29
41
|
size;
|
|
30
42
|
byteLength;
|
|
31
43
|
runtime;
|
|
@@ -34,6 +46,7 @@ export class FileDescriptor {
|
|
|
34
46
|
#mapping;
|
|
35
47
|
constructor(metadata, mapping) {
|
|
36
48
|
this.fd = expectFd(metadata.fd);
|
|
49
|
+
this.name = metadata.name;
|
|
37
50
|
this.size = expectPositiveSize(metadata.size);
|
|
38
51
|
this.byteLength = expectPositiveSize(metadata.byteLength);
|
|
39
52
|
this.runtime = metadata.runtime;
|
|
@@ -45,6 +58,7 @@ export class FileDescriptor {
|
|
|
45
58
|
return new FileDescriptor({
|
|
46
59
|
version: 1,
|
|
47
60
|
fd: mapping.fd,
|
|
61
|
+
name: mapping.name,
|
|
48
62
|
size: mapping.size,
|
|
49
63
|
byteLength: mapping.byteLength,
|
|
50
64
|
runtime: mapping.runtime,
|
|
@@ -59,7 +73,7 @@ export class FileDescriptor {
|
|
|
59
73
|
return FileDescriptor.fromMetadata(serialized);
|
|
60
74
|
}
|
|
61
75
|
toMetadata() {
|
|
62
|
-
|
|
76
|
+
const metadata = {
|
|
63
77
|
version: 1,
|
|
64
78
|
fd: this.fd,
|
|
65
79
|
size: this.size,
|
|
@@ -68,6 +82,9 @@ export class FileDescriptor {
|
|
|
68
82
|
kind: this.kind,
|
|
69
83
|
baseAddressMod64: this.baseAddressMod64,
|
|
70
84
|
};
|
|
85
|
+
if (this.name !== undefined)
|
|
86
|
+
metadata.name = this.name;
|
|
87
|
+
return metadata;
|
|
71
88
|
}
|
|
72
89
|
toJSON() {
|
|
73
90
|
return this.toMetadata();
|
|
@@ -92,6 +109,7 @@ export class FileDescriptor {
|
|
|
92
109
|
map(mapper) {
|
|
93
110
|
const options = {
|
|
94
111
|
fd: this.fd,
|
|
112
|
+
name: this.name,
|
|
95
113
|
size: this.size,
|
|
96
114
|
};
|
|
97
115
|
this.#mapping = mapper.mapSharedMemory(options);
|
|
@@ -125,7 +143,7 @@ export const parseFileDescriptorMetadata = (input) => {
|
|
|
125
143
|
if (value.version !== 1) {
|
|
126
144
|
throw new TypeError("unsupported file descriptor metadata version");
|
|
127
145
|
}
|
|
128
|
-
|
|
146
|
+
const parsed = {
|
|
129
147
|
version: 1,
|
|
130
148
|
fd: expectFd(readOptionalNumber(value.fd, "fd") ?? -1),
|
|
131
149
|
size: expectPositiveSize(readOptionalNumber(value.size, "size") ?? 0),
|
|
@@ -136,4 +154,8 @@ export const parseFileDescriptorMetadata = (input) => {
|
|
|
136
154
|
kind: readOptionalKind(value.kind),
|
|
137
155
|
baseAddressMod64: readOptionalNumber(value.baseAddressMod64, "baseAddressMod64"),
|
|
138
156
|
};
|
|
157
|
+
const name = readOptionalName(value.name);
|
|
158
|
+
if (name !== undefined)
|
|
159
|
+
parsed.name = name;
|
|
160
|
+
return parsed;
|
|
139
161
|
};
|
|
@@ -2,12 +2,13 @@ import { type CreateSharedMemoryOptions, type MapSharedMemoryOptions, type Share
|
|
|
2
2
|
export type NodeSharedMemoryNativeMapping = {
|
|
3
3
|
sab: SharedArrayBuffer;
|
|
4
4
|
fd: number;
|
|
5
|
+
name?: string;
|
|
5
6
|
size: number;
|
|
6
7
|
baseAddressMod64?: number;
|
|
7
8
|
};
|
|
8
9
|
export type NodeSharedMemoryAddon = {
|
|
9
10
|
createSharedMemory: (size: number, name?: string, mode?: CreateSharedMemoryOptions["mode"]) => NodeSharedMemoryNativeMapping;
|
|
10
|
-
mapSharedMemory: (fd: number, size: number) => NodeSharedMemoryNativeMapping;
|
|
11
|
+
mapSharedMemory: (fd: number, size: number, name?: string) => NodeSharedMemoryNativeMapping;
|
|
11
12
|
unlinkSharedMemory?: (name: string) => boolean;
|
|
12
13
|
};
|
|
13
14
|
export type NodeFutexWaitResult = "woken" | "changed" | "interrupted" | "timed-out";
|
package/src/connections/node.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { getNodeBuiltinModule } from "../common/node-compat.js";
|
|
2
2
|
import { loadNodeNativeAddon } from "./node-addons.js";
|
|
3
|
-
import { assertPosixSharedMemoryPlatform } from "./posix.js";
|
|
4
3
|
import { expectFd, expectPositiveSize, readCreateMode, readCreateName, readRequiredCreateName, readCreateSize, } from "./types.js";
|
|
5
4
|
export const DEFAULT_NODE_SHARED_MEMORY_ADDON = "../../build/Release/knitting_shared_memory.node";
|
|
6
5
|
export const DEFAULT_NODE_FUTEX_ADDON = "../../build/Release/knitting_shm.node";
|
|
7
6
|
export const loadNodeSharedMemoryAddon = (specifier) => {
|
|
8
|
-
assertPosixSharedMemoryPlatform("Node native shared memory");
|
|
9
7
|
const nodeModule = getNodeBuiltinModule("node:module");
|
|
10
8
|
if (nodeModule === undefined) {
|
|
11
9
|
throw new Error("Node shared memory addon can only be loaded in Node");
|
|
@@ -14,7 +12,6 @@ export const loadNodeSharedMemoryAddon = (specifier) => {
|
|
|
14
12
|
return loadNodeNativeAddon(require, "knitting_shared_memory", specifier);
|
|
15
13
|
};
|
|
16
14
|
export const loadNodeFutexAddon = (specifier) => {
|
|
17
|
-
assertPosixSharedMemoryPlatform("Node native futex helpers");
|
|
18
15
|
const nodeModule = getNodeBuiltinModule("node:module");
|
|
19
16
|
if (nodeModule === undefined) {
|
|
20
17
|
throw new Error("Node futex addon can only be loaded in Node");
|
|
@@ -22,16 +19,22 @@ export const loadNodeFutexAddon = (specifier) => {
|
|
|
22
19
|
const require = nodeModule.createRequire(import.meta.url);
|
|
23
20
|
return loadNodeNativeAddon(require, "knitting_shm", specifier);
|
|
24
21
|
};
|
|
25
|
-
export const fromNodeNativeMapping = (mapped) =>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
export const fromNodeNativeMapping = (mapped) => {
|
|
23
|
+
const mapping = {
|
|
24
|
+
runtime: "node",
|
|
25
|
+
fd: mapped.fd,
|
|
26
|
+
size: mapped.size,
|
|
27
|
+
byteLength: mapped.sab.byteLength,
|
|
28
|
+
buffer: mapped.sab,
|
|
29
|
+
kind: "shared-array-buffer",
|
|
30
|
+
sab: mapped.sab,
|
|
31
|
+
baseAddressMod64: mapped.baseAddressMod64,
|
|
32
|
+
};
|
|
33
|
+
if (mapped.name !== undefined && mapped.name.length > 0) {
|
|
34
|
+
mapping.name = mapped.name;
|
|
35
|
+
}
|
|
36
|
+
return mapping;
|
|
37
|
+
};
|
|
35
38
|
export const createNodeSharedMemory = (options, addon = loadNodeSharedMemoryAddon()) => {
|
|
36
39
|
const size = expectPositiveSize(readCreateSize(options));
|
|
37
40
|
const mode = readCreateMode(options);
|
|
@@ -43,7 +46,7 @@ export const createNodeSharedMemory = (options, addon = loadNodeSharedMemoryAddo
|
|
|
43
46
|
export const mapNodeSharedMemory = (options, addon = loadNodeSharedMemoryAddon()) => {
|
|
44
47
|
const fd = expectFd(options.fd);
|
|
45
48
|
const size = expectPositiveSize(options.size);
|
|
46
|
-
return fromNodeNativeMapping(addon.mapSharedMemory(fd, size));
|
|
49
|
+
return fromNodeNativeMapping(addon.mapSharedMemory(fd, size, options.name));
|
|
47
50
|
};
|
|
48
51
|
export const createNodeConnectionPrimitives = (addon = loadNodeSharedMemoryAddon()) => ({
|
|
49
52
|
runtime: "node",
|
|
@@ -23,6 +23,7 @@ type FcntlLibc = {
|
|
|
23
23
|
export declare const setCloseOnExec: <T extends FcntlLibc>(libc: T, fd: number) => number;
|
|
24
24
|
export declare const shmOpenCreateFlag: (platform: PosixPlatform) => number;
|
|
25
25
|
export declare const shmOpenExclusiveFlag: (platform: PosixPlatform) => number;
|
|
26
|
+
export declare const POSIX_SHM_MAX_NAME_LEN = 30;
|
|
26
27
|
export declare const toPosixSharedMemoryName: (name: string) => string;
|
|
27
28
|
export declare const detectPosixPlatform: () => PosixPlatform;
|
|
28
29
|
export declare const assertPosixSharedMemoryPlatform: (feature: string) => void;
|
package/src/connections/posix.js
CHANGED
|
@@ -27,6 +27,9 @@ export const setCloseOnExec = (libc, fd) => {
|
|
|
27
27
|
};
|
|
28
28
|
export const shmOpenCreateFlag = (platform) => platform === "darwin" ? DARWIN_O_CREAT : LINUX_O_CREAT;
|
|
29
29
|
export const shmOpenExclusiveFlag = (platform) => platform === "darwin" ? DARWIN_O_EXCL : LINUX_O_EXCL;
|
|
30
|
+
// macOS limits POSIX shared memory names to 31 characters including the
|
|
31
|
+
// leading "/", so the usable name portion is at most 30 characters.
|
|
32
|
+
export const POSIX_SHM_MAX_NAME_LEN = 30;
|
|
30
33
|
export const toPosixSharedMemoryName = (name) => {
|
|
31
34
|
if (name.length === 0) {
|
|
32
35
|
throw new TypeError("shared memory name must be non-empty");
|
|
@@ -38,6 +41,9 @@ export const toPosixSharedMemoryName = (name) => {
|
|
|
38
41
|
if (out.length < 2 || out.slice(1).includes("/")) {
|
|
39
42
|
throw new TypeError("POSIX shared memory name must not contain path separators");
|
|
40
43
|
}
|
|
44
|
+
if (out.length > POSIX_SHM_MAX_NAME_LEN + 1) {
|
|
45
|
+
throw new TypeError(`POSIX shared memory name must be at most ${POSIX_SHM_MAX_NAME_LEN} characters (macOS limit); got ${out.length - 1}`);
|
|
46
|
+
}
|
|
41
47
|
return out;
|
|
42
48
|
};
|
|
43
49
|
export const detectPosixPlatform = () => {
|
|
@@ -26,7 +26,9 @@ export type ProcessSharedBufferRange = {
|
|
|
26
26
|
};
|
|
27
27
|
export type ProcessSharedBufferCreator = Pick<SharedMemoryConnectionPrimitives, "createSharedMemory">;
|
|
28
28
|
export type ProcessSharedBufferMapper = Pick<SharedMemoryConnectionPrimitives, "mapSharedMemory">;
|
|
29
|
-
export type ProcessSharedBufferPrimitives = Pick<SharedMemoryConnectionPrimitives, "createSharedMemory" | "mapSharedMemory"
|
|
29
|
+
export type ProcessSharedBufferPrimitives = Pick<SharedMemoryConnectionPrimitives, "createSharedMemory" | "mapSharedMemory"> & {
|
|
30
|
+
unlinkSharedMemory?: (name: string) => boolean;
|
|
31
|
+
};
|
|
30
32
|
export type ProcessSharedBufferView = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | BigInt64Array | BigUint64Array | Float32Array | Float64Array;
|
|
31
33
|
export type ProcessSharedBufferViewConstructor<View extends ProcessSharedBufferView = ProcessSharedBufferView> = {
|
|
32
34
|
readonly BYTES_PER_ELEMENT: number;
|
|
@@ -4,7 +4,6 @@ import { RUNTIME } from "../common/runtime.js";
|
|
|
4
4
|
import { createBunConnectionPrimitives } from "./bun.js";
|
|
5
5
|
import { createDenoConnectionPrimitives } from "./deno.js";
|
|
6
6
|
import { loadNodeNativeAddon } from "./node-addons.js";
|
|
7
|
-
import { assertPosixSharedMemoryPlatform } from "./posix.js";
|
|
8
7
|
import { expectFd, expectPositiveSize, readCreateMode, readCreateName, readRequiredCreateName, readCreateSize, } from "./types.js";
|
|
9
8
|
export const PROCESS_SHARED_BUFFER_BRAND = Symbol.for("knitting.processSharedBuffer");
|
|
10
9
|
export const PROCESS_SHARED_BUFFER_NUMERIC_TRANSFER = Symbol.for("knitting.processSharedBuffer.numericTransfer");
|
|
@@ -40,16 +39,22 @@ const decodeKind = (value) => {
|
|
|
40
39
|
}
|
|
41
40
|
};
|
|
42
41
|
let defaultPrimitives;
|
|
43
|
-
const fromDefaultNodeNativeMapping = (mapped) =>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
const fromDefaultNodeNativeMapping = (mapped) => {
|
|
43
|
+
const mapping = {
|
|
44
|
+
runtime: "node",
|
|
45
|
+
fd: mapped.fd,
|
|
46
|
+
size: mapped.size,
|
|
47
|
+
byteLength: mapped.sab.byteLength,
|
|
48
|
+
buffer: mapped.sab,
|
|
49
|
+
kind: "shared-array-buffer",
|
|
50
|
+
sab: mapped.sab,
|
|
51
|
+
baseAddressMod64: mapped.baseAddressMod64,
|
|
52
|
+
};
|
|
53
|
+
if (mapped.name !== undefined && mapped.name.length > 0) {
|
|
54
|
+
mapping.name = mapped.name;
|
|
55
|
+
}
|
|
56
|
+
return mapping;
|
|
57
|
+
};
|
|
53
58
|
const createDefaultNodePrimitives = () => {
|
|
54
59
|
const nodeModule = getNodeBuiltinModule("node:module");
|
|
55
60
|
if (nodeModule === undefined) {
|
|
@@ -69,12 +74,11 @@ const createDefaultNodePrimitives = () => {
|
|
|
69
74
|
mapSharedMemory: (options) => {
|
|
70
75
|
const fd = expectFd(options.fd);
|
|
71
76
|
const size = expectPositiveSize(options.size);
|
|
72
|
-
return fromDefaultNodeNativeMapping(addon.mapSharedMemory(fd, size));
|
|
77
|
+
return fromDefaultNodeNativeMapping(addon.mapSharedMemory(fd, size, options.name));
|
|
73
78
|
},
|
|
74
79
|
};
|
|
75
80
|
};
|
|
76
81
|
const createDefaultPrimitives = () => {
|
|
77
|
-
assertPosixSharedMemoryPlatform("ProcessSharedBuffer");
|
|
78
82
|
if (RUNTIME === "bun")
|
|
79
83
|
return createBunConnectionPrimitives();
|
|
80
84
|
if (RUNTIME === "deno")
|
|
@@ -146,6 +150,8 @@ export class ProcessSharedBuffer {
|
|
|
146
150
|
static parse(serialized) {
|
|
147
151
|
return ProcessSharedBuffer.fromMetadata(serialized);
|
|
148
152
|
}
|
|
153
|
+
// Rebuilds from the 8 raw words (no name -> no JSON):
|
|
154
|
+
// fd, size, descByteLength, byteOffset, byteLength, runtime, kind, baseAddressMod64
|
|
149
155
|
static [PROCESS_SHARED_BUFFER_NUMERIC_TRANSFER](metadata) {
|
|
150
156
|
const [fd, size, descriptorByteLength, byteOffset, byteLength, runtime, kind, baseAddressMod64,] = metadata;
|
|
151
157
|
return new ProcessSharedBuffer(new FileDescriptor({
|
|
@@ -6,6 +6,7 @@ export type SharedMemoryCreateMode = "anonymous" | "create" | "open";
|
|
|
6
6
|
export type SharedMemoryMapping<Buffer extends SharedMemoryBuffer = SharedMemoryBuffer> = {
|
|
7
7
|
runtime: ConnectionRuntime;
|
|
8
8
|
fd: number;
|
|
9
|
+
name?: string;
|
|
9
10
|
size: number;
|
|
10
11
|
byteLength: number;
|
|
11
12
|
buffer: Buffer;
|
|
@@ -28,6 +29,7 @@ export type CreateSharedMemoryOptions = {
|
|
|
28
29
|
};
|
|
29
30
|
export type MapSharedMemoryOptions = {
|
|
30
31
|
fd: number;
|
|
32
|
+
name?: string;
|
|
31
33
|
size: number;
|
|
32
34
|
duplicateFd?: boolean;
|
|
33
35
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type CreateSharedMemoryOptions, type MapSharedMemoryOptions, type SharedMemoryConnectionPrimitives, type SharedMemoryMapping } from "./types.js";
|
|
2
|
+
type DenoWindowsLibrary = {
|
|
3
|
+
symbols: {
|
|
4
|
+
knitting_windows_create_shared_memory: (size: bigint, name: Uint16Array, mode: number, out: Uint8Array) => number;
|
|
5
|
+
knitting_windows_map_shared_memory: (handle: bigint, size: bigint, name: Uint16Array, out: Uint8Array) => number;
|
|
6
|
+
knitting_windows_close_shared_memory: (mapping: Uint8Array) => number;
|
|
7
|
+
};
|
|
8
|
+
close: () => void;
|
|
9
|
+
};
|
|
10
|
+
type BunWindowsLibrary = {
|
|
11
|
+
symbols: {
|
|
12
|
+
knitting_windows_create_shared_memory: (size: bigint, name: Uint16Array, mode: number, out: Uint8Array) => number;
|
|
13
|
+
knitting_windows_map_shared_memory: (handle: bigint, size: bigint, name: Uint16Array, out: Uint8Array) => number;
|
|
14
|
+
knitting_windows_close_shared_memory: (mapping: Uint8Array) => number;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare const isWindowsRuntime: () => boolean;
|
|
18
|
+
export declare const windowsSharedMemoryPrebuildPath: () => string;
|
|
19
|
+
export declare const makeWindowsAnonymousSharedMemoryName: (runtime: string) => string;
|
|
20
|
+
export declare const openDenoWindowsSharedMemoryLibrary: () => DenoWindowsLibrary;
|
|
21
|
+
export declare const openBunWindowsSharedMemoryLibrary: () => BunWindowsLibrary;
|
|
22
|
+
export declare const createDenoWindowsSharedMemory: (options: number | CreateSharedMemoryOptions, lib?: DenoWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
|
|
23
|
+
export declare const mapDenoWindowsSharedMemory: (options: MapSharedMemoryOptions, lib?: DenoWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
|
|
24
|
+
export declare const createDenoWindowsConnectionPrimitives: (lib?: DenoWindowsLibrary) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
|
|
25
|
+
export declare const createBunWindowsSharedMemory: (options: number | CreateSharedMemoryOptions, lib?: BunWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
|
|
26
|
+
export declare const mapBunWindowsSharedMemory: (options: MapSharedMemoryOptions, lib?: BunWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
|
|
27
|
+
export declare const createBunWindowsConnectionPrimitives: (lib?: BunWindowsLibrary) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
|
|
28
|
+
export {};
|