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.
Files changed (62) hide show
  1. package/README.md +326 -95
  2. package/map.md +52 -8
  3. package/package.json +4 -3
  4. package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
  5. package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
  6. package/prebuilds/darwin-x64-node-127/knitting_shared_memory.node +0 -0
  7. package/prebuilds/darwin-x64-node-137/knitting_shared_memory.node +0 -0
  8. package/prebuilds/linux-x64-node-127/knitting_shared_memory.node +0 -0
  9. package/prebuilds/linux-x64-node-137/knitting_shared_memory.node +0 -0
  10. package/prebuilds/win32-x64/knitting_windows_shared_memory.dll +0 -0
  11. package/prebuilds/win32-x64-node-127/knitting_shared_memory.node +0 -0
  12. package/prebuilds/win32-x64-node-127/knitting_shm.node +0 -0
  13. package/prebuilds/win32-x64-node-137/knitting_shared_memory.node +0 -0
  14. package/prebuilds/win32-x64-node-137/knitting_shm.node +0 -0
  15. package/scripts/build-native-addons.ts +31 -5
  16. package/src/api.d.ts +3 -2
  17. package/src/api.js +135 -34
  18. package/src/common/task-source.d.ts +1 -0
  19. package/src/common/task-source.js +5 -0
  20. package/src/connections/bun.d.ts +2 -0
  21. package/src/connections/bun.js +64 -9
  22. package/src/connections/deno.d.ts +2 -0
  23. package/src/connections/deno.js +64 -9
  24. package/src/connections/file-descriptor.d.ts +2 -0
  25. package/src/connections/file-descriptor.js +24 -2
  26. package/src/connections/node.d.ts +2 -1
  27. package/src/connections/node.js +17 -14
  28. package/src/connections/posix.d.ts +1 -0
  29. package/src/connections/posix.js +6 -0
  30. package/src/connections/process-shared-buffer.d.ts +3 -1
  31. package/src/connections/process-shared-buffer.js +19 -13
  32. package/src/connections/types.d.ts +2 -0
  33. package/src/connections/windows.d.ts +28 -0
  34. package/src/connections/windows.js +224 -0
  35. package/src/knitting_shared_memory.cc +319 -26
  36. package/src/knitting_windows_shared_memory.cc +156 -0
  37. package/src/memory/lock.js +8 -168
  38. package/src/memory/payloadCodec.js +28 -34
  39. package/src/memory/shared-buffer-io.d.ts +2 -0
  40. package/src/memory/shared-buffer-io.js +23 -0
  41. package/src/runtime/inline-executor.d.ts +2 -2
  42. package/src/runtime/inline-executor.js +15 -3
  43. package/src/runtime/pool.d.ts +3 -14
  44. package/src/runtime/pool.js +12 -543
  45. package/src/runtime/process-worker.d.ts +92 -0
  46. package/src/runtime/process-worker.js +670 -0
  47. package/src/runtime/tx-queue.d.ts +1 -1
  48. package/src/runtime/tx-queue.js +3 -1
  49. package/src/shared/abortSignal.d.ts +1 -1
  50. package/src/shared/abortSignal.js +10 -2
  51. package/src/types.d.ts +67 -8
  52. package/src/worker/bootstrap.d.ts +5 -0
  53. package/src/worker/bootstrap.js +78 -0
  54. package/src/worker/composable-runners.js +0 -8
  55. package/src/worker/loop.js +23 -156
  56. package/src/worker/process-worker-bootstrap.d.ts +8 -0
  57. package/src/worker/process-worker-bootstrap.js +160 -0
  58. package/src/worker/safety/startup.d.ts +2 -1
  59. package/src/worker/safety/startup.js +5 -2
  60. package/src/worker/task-loader.d.ts +2 -1
  61. package/src/worker/task-loader.js +14 -2
  62. package/src/worker/timers.js +19 -5
@@ -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.duplicateFd !== false) {
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 name = readCreateName(options, "knitting_shared_memory");
145
- const fd = createBunSharedMemoryFd(name, detectPosixPlatform(), libc);
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
- checkResult(libc.symbols.ftruncate(fd, BigInt(size)), "ftruncate failed");
148
- return mapBunSharedMemory({ fd, size, duplicateFd: false }, libc);
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 createBunConnectionPrimitives = (libc = openBunLibc()) => ({
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 {};
@@ -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.duplicateFd !== false) {
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 name = readCreateName(options, "knitting_shared_memory");
136
- const fd = createDenoSharedMemoryFd(name, detectPosixPlatform(), libc);
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
- checkResult(libc.symbols.ftruncate(fd, BigInt(size)), "ftruncate failed");
139
- return mapDenoSharedMemory({ fd, size, duplicateFd: false }, libc);
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 createDenoConnectionPrimitives = (libc = openDenoLibc()) => ({
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
- return {
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
- return {
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";
@@ -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
- runtime: "node",
27
- fd: mapped.fd,
28
- size: mapped.size,
29
- byteLength: mapped.sab.byteLength,
30
- buffer: mapped.sab,
31
- kind: "shared-array-buffer",
32
- sab: mapped.sab,
33
- baseAddressMod64: mapped.baseAddressMod64,
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;
@@ -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
- 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
- });
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 {};