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,70 +1,19 @@
1
- // main.ts
2
- import { fileURLToPath as fileURLToPathCompat } from "node:url";
3
1
  import { createHostTxQueue } from "./tx-queue.js";
2
+ import { cleanupProcessWorkerMemoryQuietly, createProcessSharedMemoryAllocator, createProcessWorkerMemoryLayout, createProcessWorkerNativeSignalNotifier, readProcessSharedMemorySettings, readProcessWorkerCommandPrefix, readProcessWorkerRuntime, serializeWorkerBootstrapData, spawnProcessWorker, terminateWorkerQuietly, toProcessWorkerBootPayload, toWorkerCompatExecArgv, toWorkerSafeExecArgv, } from "./process-worker.js";
4
3
  import { createSharedMemoryTransport, TRANSPORT_SIGNAL_BYTES, } from "../ipc/transport/shared-memory.js";
5
4
  import { ChannelHandler, hostDispatcherLoop } from "./dispatcher.js";
6
5
  import { HEADER_SLOT_STRIDE_U32, lock2, LOCK_SECTOR_BYTE_LENGTH, LockBound, } from "../memory/lock.js";
7
6
  import "../worker/loop.js";
8
- import { createSharedArrayBuffer, createWasmSharedArrayBuffer, RUNTIME, } from "../common/runtime.js";
9
- import { HAS_NODE_WORKER_THREADS, RUNTIME_PROCESS_WORKER_BOOT_ENV, RUNTIME_PROCESS_WORKER_BOOT_VERSION, RUNTIME_PROCESS_WORKER_ENV, RUNTIME_WORKER, } from "../common/worker-runtime.js";
10
- import { toSharedBufferRegion, } from "../common/shared-buffer-region.js";
7
+ import { createSharedArrayBuffer, createWasmSharedArrayBuffer, } from "../common/runtime.js";
8
+ import { HAS_NODE_WORKER_THREADS, RUNTIME_WORKER, } from "../common/worker-runtime.js";
11
9
  import { probeLockBufferTextCompat } from "../common/shared-buffer-text.js";
12
10
  import { signalAbortFactory } from "../shared/abortSignal.js";
13
- import { createByteCarpet, createLockControlCarpet, getHeaderBlockByteLength, makeSharedBufferRegion, } from "../memory/byte-carpet.js";
11
+ import { createLockControlCarpet } from "../memory/byte-carpet.js";
14
12
  import { resolvePayloadBufferOptions, } from "../memory/payload-config.js";
15
- import { getNodeBuiltinModule, getNodeProcess, } from "../common/node-compat.js";
16
- import { createBunConnectionPrimitives } from "../connections/bun.js";
17
- import { createDenoConnectionPrimitives } from "../connections/deno.js";
18
- import { FileDescriptor, ProcessSharedBuffer, } from "../connections/index.js";
19
- import { createNodeConnectionPrimitives, loadNodeFutexAddon, } from "../connections/node.js";
20
- import { loadNodeNativeAddon } from "../connections/node-addons.js";
21
- import { assertPosixSharedMemoryPlatform, detectPosixPlatform, } from "../connections/posix.js";
22
13
  const WORKER_FATAL_MESSAGE_KEY = "__knittingWorkerFatal";
23
- const execFlagKey = (flag) => flag.split("=", 1)[0];
24
- const NODE_PERMISSION_EXEC_FLAGS = new Set([
25
- "--permission",
26
- "--experimental-permission",
27
- "--allow-fs-read",
28
- "--allow-fs-write",
29
- "--allow-worker",
30
- "--allow-child-process",
31
- "--allow-addons",
32
- "--allow-wasi",
33
- ]);
34
- const NODE_WORKER_SAFE_EXEC_FLAGS = new Set([
35
- "--experimental-transform-types",
36
- "--expose-gc",
37
- "--no-warnings",
38
- ...NODE_PERMISSION_EXEC_FLAGS,
39
- ]);
40
14
  const isWorkerFatalMessage = (value) => !!value &&
41
15
  typeof value === "object" &&
42
16
  typeof value[WORKER_FATAL_MESSAGE_KEY] === "string";
43
- const isNodeWorkerSafeExecFlag = (flag) => NODE_WORKER_SAFE_EXEC_FLAGS.has(execFlagKey(flag));
44
- const isNodePermissionExecFlag = (flag) => NODE_PERMISSION_EXEC_FLAGS.has(execFlagKey(flag));
45
- const toWorkerSafeExecArgv = (flags) => {
46
- if (!flags || flags.length === 0)
47
- return undefined;
48
- const filtered = flags.filter(isNodeWorkerSafeExecFlag);
49
- if (filtered.length === 0)
50
- return undefined;
51
- const seen = new Set();
52
- const deduped = [];
53
- for (const flag of filtered) {
54
- if (seen.has(flag))
55
- continue;
56
- seen.add(flag);
57
- deduped.push(flag);
58
- }
59
- return deduped;
60
- };
61
- const toWorkerCompatExecArgv = (flags) => {
62
- const safe = toWorkerSafeExecArgv(flags);
63
- if (!safe || safe.length === 0)
64
- return undefined;
65
- const compat = safe.filter((flag) => !isNodePermissionExecFlag(flag));
66
- return compat.length > 0 ? compat : undefined;
67
- };
68
17
  // Keep idle workers self-healing if an Atomics.notify wake is missed.
69
18
  const DEFAULT_WORKER_PARK_MS = 1;
70
19
  const withDefaultWorkerTimers = (options) => {
@@ -79,508 +28,25 @@ const withDefaultWorkerTimers = (options) => {
79
28
  },
80
29
  };
81
30
  };
82
- const toProcessSharedMemorySize = (byteLength) => {
83
- if (!Number.isFinite(byteLength) || byteLength <= 0) {
84
- throw new RangeError("process shared memory byteLength must be positive");
85
- }
86
- const size = Math.trunc(byteLength);
87
- return size + ((64 - (size % 64)) % 64);
88
- };
89
- const createProcessSharedMemoryAllocator = (debug) => {
90
- if (RUNTIME !== "node")
91
- return undefined;
92
- try {
93
- assertPosixSharedMemoryPlatform("Process-shared memory allocator");
94
- }
95
- catch {
96
- return undefined;
97
- }
98
- let addon;
99
- try {
100
- const nodeModule = getNodeBuiltinModule("node:module");
101
- if (nodeModule === undefined)
102
- return undefined;
103
- const require = nodeModule.createRequire(import.meta.url);
104
- addon = loadNodeNativeAddon(require, "knitting_shared_memory");
105
- }
106
- catch (error) {
107
- if (debug?.extras === true) {
108
- console.warn("Process-shared memory allocator unavailable; falling back to SharedArrayBuffer.", error);
109
- }
110
- return undefined;
111
- }
112
- const backings = [];
113
- return {
114
- backings,
115
- createBuffer: (byteLength) => {
116
- const mapping = addon.createSharedMemory(toProcessSharedMemorySize(byteLength));
117
- backings.push({
118
- ...mapping,
119
- runtime: "node",
120
- buffer: mapping.sab,
121
- kind: "shared-array-buffer",
122
- byteLength: mapping.sab.byteLength,
123
- });
124
- return mapping.sab;
125
- },
126
- };
127
- };
128
- const PROCESS_WORKER_CHILD_FD = 0;
129
- const DEFAULT_BUN_BINARY = "bun";
130
- const DEFAULT_DENO_BINARY = "deno";
131
- const DEFAULT_NODE_BINARY = "node";
132
- const DENO_PROCESS_WORKER_BOOT_ENV_ALLOW = [
133
- RUNTIME_PROCESS_WORKER_ENV,
134
- RUNTIME_PROCESS_WORKER_BOOT_ENV,
135
- ].join(",");
136
- const DENO_PROCESS_WORKER_INTERNAL_FLAGS = [
137
- `--allow-env=${DENO_PROCESS_WORKER_BOOT_ENV_ALLOW}`,
138
- "--allow-ffi",
139
- ];
140
- const NODE_PROCESS_WORKER_EXEC_ARGV = [
141
- "--no-warnings",
142
- "--experimental-transform-types",
143
- ];
144
31
  const withFixedPayloadConfig = (config) => ({
145
32
  ...config,
146
33
  mode: "fixed",
147
34
  payloadInitialBytes: config.payloadMaxByteLength,
148
35
  });
149
- const getProcessWorkerSharedMemoryPrimitives = () => {
150
- assertPosixSharedMemoryPlatform("Process worker runtime");
151
- switch (RUNTIME) {
152
- case "bun":
153
- return createBunConnectionPrimitives();
154
- case "deno":
155
- return createDenoConnectionPrimitives();
156
- case "node":
157
- return createNodeConnectionPrimitives();
158
- default:
159
- throw new Error("process worker runtime needs Node, Deno, or Bun shared memory primitives");
160
- }
161
- };
162
- const createProcessWorkerMemoryLayout = ({ signalBytes, abortBytes, payloadBytes, thread, }) => {
163
- const carpet = createByteCarpet();
164
- const signalsSlice = carpet.take("signals", signalBytes);
165
- const requestLockSlice = carpet.take("requestLockSector", LOCK_SECTOR_BYTE_LENGTH);
166
- const returnLockSlice = carpet.take("returnLockSector", LOCK_SECTOR_BYTE_LENGTH);
167
- const requestHeadersSlice = carpet.take("requestHeaders", getHeaderBlockByteLength({
168
- slotCount: LockBound.slots,
169
- slotStrideU32: HEADER_SLOT_STRIDE_U32,
170
- alignTo: 64,
171
- }));
172
- const returnHeadersSlice = carpet.take("returnHeaders", getHeaderBlockByteLength({
173
- slotCount: LockBound.slots,
174
- slotStrideU32: HEADER_SLOT_STRIDE_U32,
175
- alignTo: 64,
176
- }));
177
- const abortSignalsSlice = carpet.take("abortSignals", abortBytes);
178
- const requestPayloadSlice = carpet.take("requestPayload", payloadBytes);
179
- const returnPayloadSlice = carpet.take("returnPayload", payloadBytes);
180
- const primitives = getProcessWorkerSharedMemoryPrimitives();
181
- const mapping = primitives.createSharedMemory({
182
- size: carpet.byteLength(),
183
- name: `knitting_process_worker_${thread}`,
184
- });
185
- const buffer = mapping.buffer;
186
- const bind = (slice) => makeSharedBufferRegion(buffer, slice.byteOffset, slice.byteLength);
187
- const controlLayout = {
188
- controlSAB: buffer,
189
- signals: bind(signalsSlice),
190
- abortSignals: bind(abortSignalsSlice),
191
- lock: {
192
- headers: bind(requestHeadersSlice),
193
- headerSlotStrideU32: HEADER_SLOT_STRIDE_U32,
194
- lockSector: bind(requestLockSlice),
195
- payloadSector: bind(requestLockSlice),
196
- },
197
- returnLock: {
198
- headers: bind(returnHeadersSlice),
199
- headerSlotStrideU32: HEADER_SLOT_STRIDE_U32,
200
- lockSector: bind(returnLockSlice),
201
- payloadSector: bind(returnLockSlice),
202
- },
203
- slices: carpet.slices,
204
- };
205
- return {
206
- mapping,
207
- descriptor: FileDescriptor.fromMapping(mapping),
208
- controlLayout,
209
- lockPayload: bind(requestPayloadSlice),
210
- returnPayload: bind(returnPayloadSlice),
211
- };
212
- };
213
- const toChildProcessSharedBufferMetadata = (source, descriptor) => {
214
- const region = toSharedBufferRegion(source);
215
- return ProcessSharedBuffer.fromDescriptor(new FileDescriptor({
216
- ...descriptor.toMetadata(),
217
- fd: PROCESS_WORKER_CHILD_FD,
218
- }), {
219
- byteOffset: region.byteOffset,
220
- byteLength: region.byteLength,
221
- }).toMetadata();
222
- };
223
- const toProcessWorkerWireLockBuffers = (lock, descriptor) => ({
224
- ...lock,
225
- headers: toChildProcessSharedBufferMetadata(lock.headers, descriptor),
226
- lockSector: toChildProcessSharedBufferMetadata(lock.lockSector, descriptor),
227
- payload: toChildProcessSharedBufferMetadata(lock.payload, descriptor),
228
- payloadSector: toChildProcessSharedBufferMetadata(lock.payloadSector, descriptor),
229
- });
230
- const toProcessWorkerBootPayload = (workerData, memory) => ({
231
- version: RUNTIME_PROCESS_WORKER_BOOT_VERSION,
232
- workerData: {
233
- ...workerData,
234
- sab: toChildProcessSharedBufferMetadata(workerData.sab, memory.descriptor),
235
- abortSignalSAB: workerData.abortSignalSAB === undefined
236
- ? undefined
237
- : toChildProcessSharedBufferMetadata(workerData.abortSignalSAB, memory.descriptor),
238
- lock: toProcessWorkerWireLockBuffers(workerData.lock, memory.descriptor),
239
- returnLock: toProcessWorkerWireLockBuffers(workerData.returnLock, memory.descriptor),
240
- },
241
- });
242
- const toProcessWorkerPath = (specifier) => {
243
- const value = specifier instanceof URL ? specifier.href : specifier;
244
- if (value.startsWith("file:"))
245
- return fileURLToPathCompat(value);
246
- return value;
247
- };
248
- const readProcessWorkerRuntime = (options) => {
249
- const runtime = options?.processRuntime ?? "bun";
250
- if (runtime === "bun" || runtime === "deno" || runtime === "node") {
251
- return runtime;
252
- }
253
- throw new TypeError(`Unsupported process worker runtime: ${String(runtime)}`);
254
- };
255
- const readProcessWorkerCommandPrefix = (options) => {
256
- const prefix = options?.processCommandPrefix;
257
- if (prefix === undefined)
258
- return undefined;
259
- if (!Array.isArray(prefix)) {
260
- throw new TypeError("processCommandPrefix must be an argv array");
261
- }
262
- if (prefix.length === 0)
263
- return undefined;
264
- const out = [];
265
- for (const [index, value] of prefix.entries()) {
266
- if (typeof value !== "string" || value.length === 0) {
267
- throw new TypeError(`processCommandPrefix[${index}] must be a non-empty string`);
268
- }
269
- out.push(value);
270
- }
271
- return out;
272
- };
273
- const currentProcessEnv = () => ({
274
- ...getNodeProcess()?.env,
275
- });
276
- const processWorkerEnv = (extra) => ({
277
- ...currentProcessEnv(),
278
- [RUNTIME_PROCESS_WORKER_ENV]: "1",
279
- ...extra,
280
- });
281
- const processWorkerBootEnv = (bootPayload) => processWorkerEnv({
282
- [RUNTIME_PROCESS_WORKER_BOOT_ENV]: JSON.stringify(bootPayload),
283
- });
284
- const stringProcessEnv = (input) => {
285
- const out = {};
286
- for (const [key, value] of Object.entries(input)) {
287
- if (value !== undefined)
288
- out[key] = value;
289
- }
290
- return out;
291
- };
292
- const processWorkerBunBinary = (bun) => getNodeProcess()?.env?.BUN_BINARY ??
293
- bun?.argv?.[0] ??
294
- DEFAULT_BUN_BINARY;
295
- const processWorkerDenoBinary = (deno) => getNodeProcess()?.env?.DENO_BINARY ??
296
- deno?.execPath?.() ??
297
- DEFAULT_DENO_BINARY;
298
- const processWorkerDenoFlags = (permission) => {
299
- if (permission?.enabled !== true || permission.unsafe === true) {
300
- return ["-A"];
301
- }
302
- return [
303
- ...DENO_PROCESS_WORKER_INTERNAL_FLAGS,
304
- ...permission.deno.flags,
305
- ];
306
- };
307
- const processWorkerNodeBinary = () => {
308
- const nodeProcess = getNodeProcess();
309
- return nodeProcess?.env?.NODE_BINARY ??
310
- (RUNTIME === "node" ? nodeProcess?.execPath : undefined) ??
311
- DEFAULT_NODE_BINARY;
312
- };
313
- const processWorkerNodeExecArgv = () => {
314
- const out = [];
315
- const seen = new Set();
316
- const add = (flag) => {
317
- if (seen.has(flag))
318
- return;
319
- seen.add(flag);
320
- out.push(flag);
321
- };
322
- for (const flag of toWorkerCompatExecArgv(getNodeProcess()?.execArgv) ?? []) {
323
- add(flag);
324
- }
325
- for (const flag of NODE_PROCESS_WORKER_EXEC_ARGV)
326
- add(flag);
327
- return out;
328
- };
329
- const processWorkerCommand = ({ processRuntime, workerUrl, bun, deno, commandPrefix, permission, }) => {
330
- const workerPath = toProcessWorkerPath(workerUrl);
331
- let command;
332
- if (processRuntime === "deno") {
333
- command = [
334
- processWorkerDenoBinary(deno),
335
- "run",
336
- ...processWorkerDenoFlags(permission),
337
- workerPath,
338
- ];
339
- }
340
- else if (processRuntime === "node") {
341
- command = [
342
- processWorkerNodeBinary(),
343
- ...processWorkerNodeExecArgv(),
344
- workerPath,
345
- ];
346
- }
347
- else {
348
- command = [processWorkerBunBinary(bun), workerPath];
349
- }
350
- return commandPrefix === undefined
351
- ? command
352
- : [...commandPrefix, ...command];
353
- };
354
- const createProcessWorkerNativeSignalNotifier = ({ processRuntime, signal, }) => {
355
- if (RUNTIME !== "node" || processRuntime !== "node")
356
- return undefined;
357
- try {
358
- const futex = loadNodeFutexAddon();
359
- return () => {
360
- futex.wakeU32(signal.buffer, signal.byteOffset, 1);
361
- };
362
- }
363
- catch {
364
- return undefined;
365
- }
366
- };
367
- const createProcessWorkerEventHub = () => {
368
- const messageHandlers = [];
369
- const errorHandlers = [];
370
- const exitHandlers = [];
371
- return {
372
- emitMessage: (message) => {
373
- for (const handler of messageHandlers)
374
- handler(message);
375
- },
376
- emitError: (error) => {
377
- for (const handler of errorHandlers)
378
- handler(error);
379
- },
380
- emitExit: (code) => {
381
- for (const handler of exitHandlers)
382
- handler(code);
383
- },
384
- on: (event, listener) => {
385
- if (event === "message")
386
- messageHandlers.push(listener);
387
- if (event === "error")
388
- errorHandlers.push(listener);
389
- if (event === "exit")
390
- exitHandlers.push(listener);
391
- },
392
- };
393
- };
394
- const spawnBunHostedProcessWorker = ({ workerUrl, bootPayload, memory, processRuntime, commandPrefix, permission, }) => {
395
- const bun = globalThis.Bun;
396
- if (typeof bun?.spawn !== "function") {
397
- throw new Error("Bun.spawn is not available for process workers");
398
- }
399
- const events = createProcessWorkerEventHub();
400
- const nodeProcess = getNodeProcess();
401
- const useIpcBoot = processRuntime === "bun" && commandPrefix === undefined;
402
- const spawnOptions = {
403
- cmd: processWorkerCommand({
404
- processRuntime,
405
- workerUrl,
406
- bun,
407
- commandPrefix,
408
- permission,
409
- }),
410
- cwd: nodeProcess?.cwd?.(),
411
- env: useIpcBoot
412
- ? processWorkerEnv()
413
- : processWorkerBootEnv(bootPayload),
414
- stdin: memory.mapping.fd,
415
- stdout: "inherit",
416
- stderr: "inherit",
417
- onExit: (_subprocess, exitCode, _signalCode, error) => {
418
- if (error !== undefined)
419
- events.emitError(error);
420
- events.emitExit(exitCode ?? -1);
421
- },
422
- };
423
- if (useIpcBoot) {
424
- spawnOptions.serialization = "advanced";
425
- spawnOptions.ipc = (message) => {
426
- events.emitMessage(message);
427
- };
428
- }
429
- const child = bun.spawn(spawnOptions);
430
- if (useIpcBoot) {
431
- queueMicrotask(() => child.send?.(bootPayload));
432
- }
433
- child.exited.catch((error) => {
434
- events.emitError(error);
435
- });
436
- return {
437
- terminate: () => {
438
- child.kill();
439
- return child.exited.catch(() => undefined);
440
- },
441
- on: events.on,
442
- };
443
- };
444
- const spawnNodeHostedProcessWorker = ({ workerUrl, bootPayload, memory, processRuntime, commandPrefix, permission, }) => {
445
- const childProcess = getNodeBuiltinModule("node:child_process");
446
- if (typeof childProcess?.spawn !== "function") {
447
- throw new Error("node:child_process.spawn is not available");
448
- }
449
- const events = createProcessWorkerEventHub();
450
- const useIpcBoot = processRuntime === "bun" && commandPrefix === undefined;
451
- const [command, ...args] = processWorkerCommand({
452
- processRuntime,
453
- workerUrl,
454
- commandPrefix,
455
- permission,
456
- });
457
- const child = childProcess.spawn(command, args, {
458
- cwd: getNodeProcess()?.cwd?.(),
459
- env: useIpcBoot
460
- ? processWorkerEnv()
461
- : processWorkerBootEnv(bootPayload),
462
- stdio: useIpcBoot
463
- ? [memory.mapping.fd, "inherit", "inherit", "ipc"]
464
- : [memory.mapping.fd, "inherit", "inherit"],
465
- });
466
- if (useIpcBoot) {
467
- child.on("message", events.emitMessage);
468
- queueMicrotask(() => child.send?.(bootPayload));
469
- }
470
- child.on("error", events.emitError);
471
- child.on("exit", (code) => events.emitExit(code ?? -1));
472
- return {
473
- terminate: () => child.kill(),
474
- unref: () => child.unref?.(),
475
- on: events.on,
476
- };
477
- };
478
- const getDenoRuntime = () => globalThis.Deno;
479
- const denoFileRid = (file) => {
480
- for (const symbol of Object.getOwnPropertySymbols(file)) {
481
- if (String(symbol) === "Symbol(Deno.internal.rid)") {
482
- const rid = file[symbol];
483
- if (typeof rid === "number")
484
- return rid;
485
- }
486
- }
487
- throw new Error("Deno FsFile resource id is not available");
488
- };
489
- const openDenoInheritedFd = (fd) => {
490
- const deno = getDenoRuntime();
491
- if (typeof deno?.openSync !== "function") {
492
- throw new Error("Deno.openSync is not available for process workers");
493
- }
494
- const fdPath = detectPosixPlatform() === "linux"
495
- ? `/proc/self/fd/${fd}`
496
- : `/dev/fd/${fd}`;
497
- return deno.openSync(fdPath, { read: true, write: true });
498
- };
499
- const spawnDenoHostedProcessWorker = ({ workerUrl, bootPayload, memory, processRuntime, commandPrefix, permission, }) => {
500
- const deno = getDenoRuntime();
501
- if (typeof deno?.Command !== "function") {
502
- throw new Error("Deno.Command is not available for process workers");
503
- }
504
- const inheritedFd = openDenoInheritedFd(memory.mapping.fd);
505
- const events = createProcessWorkerEventHub();
506
- const [command, ...args] = processWorkerCommand({
507
- processRuntime,
508
- workerUrl,
509
- deno,
510
- commandPrefix,
511
- permission,
512
- });
513
- const child = new deno.Command(command, {
514
- args,
515
- cwd: deno.cwd?.(),
516
- env: stringProcessEnv(processWorkerBootEnv(bootPayload)),
517
- stdin: denoFileRid(inheritedFd),
518
- stdout: "inherit",
519
- stderr: "inherit",
520
- }).spawn();
521
- const closeInheritedFd = () => {
522
- try {
523
- inheritedFd.close?.();
524
- }
525
- catch {
526
- }
527
- };
528
- child.status.then((status) => {
529
- closeInheritedFd();
530
- events.emitExit(status.code);
531
- }, (error) => {
532
- closeInheritedFd();
533
- events.emitError(error);
534
- events.emitExit(-1);
535
- });
536
- return {
537
- terminate: () => {
538
- try {
539
- child.kill("SIGTERM");
540
- }
541
- catch {
542
- }
543
- return child.status.finally(closeInheritedFd);
544
- },
545
- on: events.on,
546
- };
547
- };
548
- const spawnProcessWorker = (options) => {
549
- switch (RUNTIME) {
550
- case "bun":
551
- return spawnBunHostedProcessWorker(options);
552
- case "node":
553
- return spawnNodeHostedProcessWorker(options);
554
- case "deno":
555
- return spawnDenoHostedProcessWorker(options);
556
- default:
557
- throw new Error("process worker runtime is only available in Node, Deno, or Bun");
558
- }
559
- };
560
- const terminateWorkerQuietly = (worker) => {
561
- try {
562
- // Runaway worker termination can be slow or stuck on some runtimes; once the
563
- // pool is closing it must not keep the host process alive.
564
- worker.unref?.();
565
- void Promise.resolve(worker.terminate()).catch(() => { });
566
- }
567
- catch {
568
- }
569
- };
570
- export const spawnWorkerContext = ({ list, ids, sab, thread, debug, totalNumberOfThread, source, at, workerOptions, workerExecArgv, permission, host, payload, payloadInitialBytes, payloadMaxBytes, bufferMode, maxPayloadBytes, abortSignalCapacity, usesAbortSignal, }) => {
36
+ export const spawnWorkerContext = ({ list, ids, names, sab, thread, debug, totalNumberOfThread, source, at, workerOptions, workerExecArgv, permission, host, payload, payloadInitialBytes, payloadMaxBytes, bufferMode, maxPayloadBytes, abortSignalCapacity, usesAbortSignal, }) => {
571
37
  const tsFileUrl = new URL(import.meta.url);
572
38
  const poliWorker = RUNTIME_WORKER;
573
- const resolvedWorkerOptions = withDefaultWorkerTimers(workerOptions);
39
+ const resolvedWorkerOptions = serializeWorkerBootstrapData(withDefaultWorkerTimers(workerOptions));
574
40
  const useProcessWorkerRuntime = resolvedWorkerOptions.runtime === "process";
575
- if (useProcessWorkerRuntime) {
576
- assertPosixSharedMemoryPlatform("Process worker runtime");
577
- }
578
41
  const processWorkerRuntime = useProcessWorkerRuntime
579
42
  ? readProcessWorkerRuntime(resolvedWorkerOptions)
580
43
  : undefined;
581
44
  const processWorkerCommandPrefix = useProcessWorkerRuntime
582
45
  ? readProcessWorkerCommandPrefix(resolvedWorkerOptions)
583
46
  : undefined;
47
+ const processSharedMemorySettings = useProcessWorkerRuntime
48
+ ? readProcessSharedMemorySettings(resolvedWorkerOptions)
49
+ : undefined;
584
50
  if (debug?.logHref === true) {
585
51
  console.log(tsFileUrl);
586
52
  }
@@ -627,6 +93,7 @@ export const spawnWorkerContext = ({ list, ids, sab, thread, debug, totalNumberO
627
93
  abortBytes,
628
94
  payloadBytes: resolvedPayloadConfig.payloadMaxByteLength,
629
95
  thread,
96
+ sharedMemory: processSharedMemorySettings,
630
97
  })
631
98
  : undefined;
632
99
  const processSharedMemory = processWorkerMemory === undefined
@@ -750,6 +217,7 @@ export const spawnWorkerContext = ({ list, ids, sab, thread, debug, totalNumberO
750
217
  : undefined,
751
218
  list,
752
219
  ids,
220
+ names,
753
221
  at,
754
222
  thread,
755
223
  debug,
@@ -914,6 +382,7 @@ export const spawnWorkerContext = ({ list, ids, sab, thread, debug, totalNumberO
914
382
  kills: async () => {
915
383
  markWorkerClosed("Thread closed");
916
384
  terminateWorkerQuietly(worker);
385
+ cleanupProcessWorkerMemoryQuietly(processWorkerMemory);
917
386
  },
918
387
  lock,
919
388
  processSharedMemoryBackings: processSharedMemory?.backings,