knitting 0.1.56 → 0.1.60
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 +254 -40
- package/knitting.d.ts +3 -2
- package/knitting.js +3 -3
- package/map.md +21 -9
- package/package.json +7 -1
- package/scripts/build-compiled-worker.ts +276 -0
- package/scripts/compiled-worker/porffor.d.ts +5 -0
- package/scripts/compiled-worker/runtime.ts +529 -0
- package/scripts/compiled-worker/task-shim.ts +32 -0
- package/src/api.d.ts +24 -1
- package/src/api.js +199 -20
- package/src/common/module-url.d.ts +1 -0
- package/src/common/module-url.js +30 -2
- package/src/common/node-compat.d.ts +2 -0
- package/src/common/path-canonical.js +20 -6
- package/src/common/runtime.d.ts +2 -1
- package/src/common/runtime.js +18 -4
- package/src/common/task-source.d.ts +2 -0
- package/src/common/task-source.js +17 -1
- package/src/common/worker-runtime.js +16 -7
- package/src/connections/buffer-reference-native.js +25 -1
- package/src/connections/buffer-reference.d.ts +23 -2
- package/src/connections/buffer-reference.js +143 -29
- package/src/connections/bun.d.ts +1 -1
- package/src/connections/bun.js +25 -14
- package/src/connections/deno.d.ts +3 -1
- package/src/connections/deno.js +35 -14
- package/src/connections/external-array-buffer.d.ts +2 -0
- package/src/connections/external-array-buffer.js +33 -0
- package/src/connections/node-addons.d.ts +11 -0
- package/src/connections/node-addons.js +49 -1
- package/src/connections/node-ffi-api.d.ts +19 -0
- package/src/connections/node-ffi-api.js +28 -0
- package/src/connections/node-ffi.d.ts +27 -0
- package/src/connections/node-ffi.js +262 -0
- package/src/connections/node.d.ts +1 -1
- package/src/connections/node.js +20 -20
- package/src/connections/package-assets.js +25 -15
- package/src/connections/posix.d.ts +42 -0
- package/src/connections/posix.js +101 -0
- package/src/connections/process-shared-buffer.d.ts +1 -0
- package/src/connections/process-shared-buffer.js +11 -45
- package/src/connections/types.d.ts +4 -0
- package/src/connections/windows.d.ts +19 -10
- package/src/connections/windows.js +87 -66
- package/src/error.d.ts +7 -6
- package/src/error.js +8 -7
- package/src/memory/lock.d.ts +87 -77
- package/src/memory/lock.js +103 -84
- package/src/memory/payloadCodec.d.ts +11 -2
- package/src/memory/payloadCodec.js +127 -31
- package/src/permission/compatibility.d.ts +28 -0
- package/src/permission/compatibility.js +239 -0
- package/src/permission/index.d.ts +2 -0
- package/src/permission/index.js +1 -0
- package/src/permission/protocol.d.ts +1 -0
- package/src/permission/protocol.js +54 -14
- package/src/runtime/compiled-artifact.d.ts +21 -0
- package/src/runtime/compiled-artifact.js +260 -0
- package/src/runtime/compiled-builder.d.ts +8 -0
- package/src/runtime/compiled-builder.js +42 -0
- package/src/runtime/compiled-worker.d.ts +27 -0
- package/src/runtime/compiled-worker.js +562 -0
- package/src/runtime/inline-executor.js +27 -15
- package/src/runtime/pool.d.ts +7 -2
- package/src/runtime/pool.js +74 -6
- package/src/runtime/process-worker.d.ts +1 -1
- package/src/runtime/process-worker.js +48 -8
- package/src/runtime/tx-queue.d.ts +3 -1
- package/src/runtime/tx-queue.js +4 -1
- package/src/types.d.ts +48 -6
- package/src/worker/composable-runners.js +3 -2
- package/src/worker/loop.d.ts +1 -0
- package/src/worker/loop.js +25 -12
- package/src/worker/task-loader.d.ts +5 -4
- package/src/worker/task-loader.js +13 -7
- package/src/worker/timers.js +8 -6
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
import { withResolvers } from "../common/with-resolvers.js";
|
|
2
2
|
import RingQueue from "../ipc/tools/ring-queue.js";
|
|
3
3
|
import { createRuntimeMessageChannel } from "../common/worker-runtime.js";
|
|
4
|
+
// const objects, not `enum`s: Andromeda's Nova engine can't parse `enum`. Same
|
|
5
|
+
// values and emit on Node/Deno/Bun.
|
|
6
|
+
const SlotStateMacro = {
|
|
7
|
+
Free: -1,
|
|
8
|
+
Pending: 0,
|
|
9
|
+
};
|
|
10
|
+
const TimeoutKind = {
|
|
11
|
+
Reject: 0,
|
|
12
|
+
Resolve: 1,
|
|
13
|
+
};
|
|
4
14
|
const normalizeTimeout = (timeout) => {
|
|
5
15
|
if (timeout == null)
|
|
6
16
|
return undefined;
|
|
7
17
|
if (typeof timeout === "number") {
|
|
8
18
|
return timeout >= 0
|
|
9
|
-
? { ms: timeout, kind:
|
|
19
|
+
? { ms: timeout, kind: TimeoutKind.Reject, value: new Error("Task timeout") }
|
|
10
20
|
: undefined;
|
|
11
21
|
}
|
|
12
22
|
const ms = timeout.time;
|
|
13
23
|
if (!(ms >= 0))
|
|
14
24
|
return undefined;
|
|
15
25
|
if ("default" in timeout) {
|
|
16
|
-
return { ms, kind:
|
|
26
|
+
return { ms, kind: TimeoutKind.Resolve, value: timeout.default };
|
|
17
27
|
}
|
|
18
28
|
if (timeout.maybe === true) {
|
|
19
|
-
return { ms, kind:
|
|
29
|
+
return { ms, kind: TimeoutKind.Resolve, value: undefined };
|
|
20
30
|
}
|
|
21
31
|
if ("error" in timeout) {
|
|
22
|
-
return { ms, kind:
|
|
32
|
+
return { ms, kind: TimeoutKind.Reject, value: timeout.error };
|
|
23
33
|
}
|
|
24
|
-
return { ms, kind:
|
|
34
|
+
return { ms, kind: TimeoutKind.Reject, value: new Error("Task timeout") };
|
|
25
35
|
};
|
|
26
36
|
const raceTimeout = (promise, spec) => new Promise((resolve, reject) => {
|
|
27
37
|
let done = false;
|
|
@@ -29,7 +39,7 @@ const raceTimeout = (promise, spec) => new Promise((resolve, reject) => {
|
|
|
29
39
|
if (done)
|
|
30
40
|
return;
|
|
31
41
|
done = true;
|
|
32
|
-
if (spec.kind ===
|
|
42
|
+
if (spec.kind === TimeoutKind.Resolve) {
|
|
33
43
|
resolve(spec.value);
|
|
34
44
|
}
|
|
35
45
|
else {
|
|
@@ -52,8 +62,10 @@ const raceTimeout = (promise, spec) => new Promise((resolve, reject) => {
|
|
|
52
62
|
});
|
|
53
63
|
const INLINE_ABORT_TOOLKIT = (() => {
|
|
54
64
|
const hasAborted = () => false;
|
|
65
|
+
const now = () => performance.now();
|
|
55
66
|
return {
|
|
56
67
|
hasAborted,
|
|
68
|
+
now,
|
|
57
69
|
};
|
|
58
70
|
})();
|
|
59
71
|
const composeInlineCallable = (fn, timeout, useAbortToolkit = false) => {
|
|
@@ -86,7 +98,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
86
98
|
});
|
|
87
99
|
const initCap = 16;
|
|
88
100
|
let fnByIndex = new Int32Array(initCap);
|
|
89
|
-
let stateByIndex = new Int8Array(initCap).fill(
|
|
101
|
+
let stateByIndex = new Int8Array(initCap).fill(SlotStateMacro.Free);
|
|
90
102
|
let argsByIndex = new Array(initCap);
|
|
91
103
|
let taskIdByIndex = new Array(initCap).fill(-1);
|
|
92
104
|
let deferredByIndex = new Array(initCap);
|
|
@@ -126,13 +138,13 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
126
138
|
send();
|
|
127
139
|
};
|
|
128
140
|
const enqueueIfCurrent = (index, taskID) => {
|
|
129
|
-
if (stateByIndex[index] !==
|
|
141
|
+
if (stateByIndex[index] !== SlotStateMacro.Pending ||
|
|
130
142
|
taskIdByIndex[index] !== taskID)
|
|
131
143
|
return;
|
|
132
144
|
enqueue(index);
|
|
133
145
|
};
|
|
134
146
|
const settleIfCurrent = (index, taskID, isError, value) => {
|
|
135
|
-
if (stateByIndex[index] !==
|
|
147
|
+
if (stateByIndex[index] !== SlotStateMacro.Pending ||
|
|
136
148
|
taskIdByIndex[index] !== taskID)
|
|
137
149
|
return;
|
|
138
150
|
const deferred = deferredByIndex[index];
|
|
@@ -153,7 +165,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
153
165
|
nextFnByIndex.set(fnByIndex);
|
|
154
166
|
fnByIndex = nextFnByIndex;
|
|
155
167
|
const nextStateByIndex = new Int8Array(newCap);
|
|
156
|
-
nextStateByIndex.fill(
|
|
168
|
+
nextStateByIndex.fill(SlotStateMacro.Free);
|
|
157
169
|
nextStateByIndex.set(stateByIndex);
|
|
158
170
|
stateByIndex = nextStateByIndex;
|
|
159
171
|
argsByIndex.length = newCap;
|
|
@@ -172,7 +184,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
172
184
|
if (maybeIndex === undefined)
|
|
173
185
|
break;
|
|
174
186
|
const index = maybeIndex | 0;
|
|
175
|
-
if (stateByIndex[index] !==
|
|
187
|
+
if (stateByIndex[index] !== SlotStateMacro.Pending)
|
|
176
188
|
continue;
|
|
177
189
|
const taskID = taskIdByIndex[index];
|
|
178
190
|
try {
|
|
@@ -213,7 +225,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
213
225
|
}
|
|
214
226
|
function cleanup(index) {
|
|
215
227
|
working--;
|
|
216
|
-
stateByIndex[index] =
|
|
228
|
+
stateByIndex[index] = SlotStateMacro.Free;
|
|
217
229
|
fnByIndex[index] = 0;
|
|
218
230
|
taskIdByIndex[index] = -1;
|
|
219
231
|
argsByIndex[index] = undefined;
|
|
@@ -230,7 +242,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
230
242
|
argsByIndex[index] = args;
|
|
231
243
|
fnByIndex[index] = fnNumber | 0;
|
|
232
244
|
deferredByIndex[index] = deferred;
|
|
233
|
-
stateByIndex[index] =
|
|
245
|
+
stateByIndex[index] = SlotStateMacro.Pending;
|
|
234
246
|
working++;
|
|
235
247
|
if (args instanceof Promise) {
|
|
236
248
|
args.then((value) => {
|
|
@@ -250,7 +262,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
250
262
|
return {
|
|
251
263
|
kills: async () => {
|
|
252
264
|
for (let index = 0; index < stateByIndex.length; index++) {
|
|
253
|
-
if (stateByIndex[index] !==
|
|
265
|
+
if (stateByIndex[index] !== SlotStateMacro.Pending)
|
|
254
266
|
continue;
|
|
255
267
|
try {
|
|
256
268
|
deferredByIndex[index]?.reject("Thread closed");
|
|
@@ -271,7 +283,7 @@ export const createInlineExecutor = ({ tasks, genTaskID, batchSize, }) => {
|
|
|
271
283
|
taskIdByIndex.fill(-1);
|
|
272
284
|
deferredByIndex.fill(undefined);
|
|
273
285
|
fnByIndex.fill(0);
|
|
274
|
-
stateByIndex.fill(
|
|
286
|
+
stateByIndex.fill(SlotStateMacro.Free);
|
|
275
287
|
working = 0;
|
|
276
288
|
isInMacro = false;
|
|
277
289
|
isInMicro = false;
|
package/src/runtime/pool.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type ProcessSharedMemoryBacking } from "./process-worker.js";
|
|
|
2
2
|
import { type Sab } from "../ipc/transport/shared-memory.js";
|
|
3
3
|
import { ChannelHandler, type DispatcherCheck } from "./dispatcher.js";
|
|
4
4
|
import { lock2 } from "../memory/lock.js";
|
|
5
|
+
import "../memory/payloadCodec.js";
|
|
5
6
|
import type { DebugOptions, DispatcherSettings, WorkerContext, WorkerData, WorkerSettings } from "../types.js";
|
|
6
7
|
import "../worker/loop.js";
|
|
7
8
|
import { type PayloadBufferOptions } from "../memory/payload-config.js";
|
|
@@ -29,11 +30,15 @@ export declare const spawnWorkerContext: ({ list, ids, names, sab, thread, debug
|
|
|
29
30
|
* macro channel that runs all lane checks.
|
|
30
31
|
*/
|
|
31
32
|
sharedChannelHandler?: ChannelHandler;
|
|
32
|
-
}) => WorkerContext & {
|
|
33
|
+
}) => (WorkerContext & {
|
|
34
|
+
dispatcherCheck?: never;
|
|
35
|
+
laneWake?: never;
|
|
36
|
+
bindSend?: never;
|
|
37
|
+
}) | (WorkerContext & {
|
|
33
38
|
lock: ReturnType<typeof lock2>;
|
|
34
39
|
processSharedMemoryBackings?: readonly ProcessSharedMemoryBacking[];
|
|
35
40
|
dispatcherCheck?: DispatcherCheck;
|
|
36
41
|
laneWake?: () => void;
|
|
37
42
|
bindSend?: (fn: () => void) => void;
|
|
38
|
-
};
|
|
43
|
+
});
|
|
39
44
|
export type CreateContext = WorkerContext;
|
package/src/runtime/pool.js
CHANGED
|
@@ -3,6 +3,9 @@ import { cleanupProcessWorkerMemoryQuietly, createProcessSharedMemoryAllocator,
|
|
|
3
3
|
import { createSharedMemoryTransport, TRANSPORT_SIGNAL_BYTES, } from "../ipc/transport/shared-memory.js";
|
|
4
4
|
import { ChannelHandler, hostDispatcherLoop, } from "./dispatcher.js";
|
|
5
5
|
import { HEADER_SLOT_STRIDE_U32, lock2, LOCK_SECTOR_BYTE_LENGTH, LockBound, } from "../memory/lock.js";
|
|
6
|
+
// Side-effect import: registers the payload codec (cycle break for Andromeda;
|
|
7
|
+
// see lock.ts). Must run before any lock2() call.
|
|
8
|
+
import "../memory/payloadCodec.js";
|
|
6
9
|
import "../worker/loop.js";
|
|
7
10
|
import { createSharedArrayBuffer, createWasmSharedArrayBuffer, } from "../common/runtime.js";
|
|
8
11
|
import { HAS_NODE_WORKER_THREADS, RUNTIME_WORKER, } from "../common/worker-runtime.js";
|
|
@@ -10,7 +13,8 @@ import { probeLockBufferTextCompat } from "../common/shared-buffer-text.js";
|
|
|
10
13
|
import { signalAbortFactory } from "../shared/abortSignal.js";
|
|
11
14
|
import { createLockControlCarpet } from "../memory/byte-carpet.js";
|
|
12
15
|
import { resolvePayloadBufferOptions, } from "../memory/payload-config.js";
|
|
13
|
-
import { createBufferReferenceReturnReleaseMessage } from "../connections/buffer-reference.js";
|
|
16
|
+
import { createBufferReferenceReturnReleaseMessage, detachArrayBufferBestEffort, } from "../connections/buffer-reference.js";
|
|
17
|
+
import { spawnCompiledWorkerContext } from "./compiled-worker.js";
|
|
14
18
|
const WORKER_FATAL_MESSAGE_KEY = "__knittingWorkerFatal";
|
|
15
19
|
const isWorkerFatalMessage = (value) => !!value &&
|
|
16
20
|
typeof value === "object" &&
|
|
@@ -35,6 +39,16 @@ const withFixedPayloadConfig = (config) => ({
|
|
|
35
39
|
payloadInitialBytes: config.payloadMaxByteLength,
|
|
36
40
|
});
|
|
37
41
|
export const spawnWorkerContext = ({ list, ids, names, sab, thread, debug, hostDebug, totalNumberOfThread, source, at, workerOptions, workerExecArgv, permission, host, payload, bufferReferenceReturn, abortSignalCapacity, usesAbortSignal, sharedChannelHandler, }) => {
|
|
42
|
+
if (workerOptions?.runtime === "compiled") {
|
|
43
|
+
return spawnCompiledWorkerContext({
|
|
44
|
+
list,
|
|
45
|
+
names,
|
|
46
|
+
workerOptions,
|
|
47
|
+
hostDebug,
|
|
48
|
+
abortSignalCapacity,
|
|
49
|
+
usesAbortSignal,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
38
52
|
const tsFileUrl = new URL(import.meta.url);
|
|
39
53
|
const poliWorker = RUNTIME_WORKER;
|
|
40
54
|
const resolvedWorkerOptions = serializeWorkerBootstrapData(withDefaultWorkerTimers(workerOptions));
|
|
@@ -144,6 +158,7 @@ export const spawnWorkerContext = ({ list, ids, names, sab, thread, debug, hostD
|
|
|
144
158
|
payloadSector: lockBuffers.payloadSector,
|
|
145
159
|
payloadConfig: resolvedPayloadConfig,
|
|
146
160
|
textCompat: lockBuffers.textCompat,
|
|
161
|
+
processBoundary: useProcessWorkerRuntime,
|
|
147
162
|
});
|
|
148
163
|
const returnLock = lock2({
|
|
149
164
|
headers: returnLockBuffers.headers,
|
|
@@ -153,6 +168,7 @@ export const spawnWorkerContext = ({ list, ids, names, sab, thread, debug, hostD
|
|
|
153
168
|
payloadSector: returnLockBuffers.payloadSector,
|
|
154
169
|
payloadConfig: resolvedPayloadConfig,
|
|
155
170
|
textCompat: returnLockBuffers.textCompat,
|
|
171
|
+
processBoundary: useProcessWorkerRuntime,
|
|
156
172
|
});
|
|
157
173
|
const abortSignalSAB = usesAbortSignal === true
|
|
158
174
|
? controlLayout.abortSignals
|
|
@@ -178,13 +194,61 @@ export const spawnWorkerContext = ({ list, ids, names, sab, thread, debug, hostD
|
|
|
178
194
|
processRuntime: processWorkerRuntime,
|
|
179
195
|
signal: signalBox.opView,
|
|
180
196
|
});
|
|
197
|
+
const outstandingBorrowedReturns = bufferReferenceReturn === "borrow" && typeof WeakRef === "function"
|
|
198
|
+
? new Map()
|
|
199
|
+
: undefined;
|
|
200
|
+
const releaseBorrowedReturnToken = (token) => {
|
|
201
|
+
outstandingBorrowedReturns?.delete(token);
|
|
202
|
+
worker?.postMessage?.(createBufferReferenceReturnReleaseMessage(token));
|
|
203
|
+
};
|
|
204
|
+
const revokeOutstandingBorrowedReturns = (copyBytes) => {
|
|
205
|
+
if (outstandingBorrowedReturns === undefined)
|
|
206
|
+
return;
|
|
207
|
+
for (const [token, record] of outstandingBorrowedReturns) {
|
|
208
|
+
try {
|
|
209
|
+
const ref = record.ref.deref();
|
|
210
|
+
if (ref !== undefined) {
|
|
211
|
+
ref.revokeBorrow(copyBytes);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const aliasBuffer = record.aliasBuffer?.deref();
|
|
215
|
+
if (aliasBuffer !== undefined &&
|
|
216
|
+
detachArrayBufferBestEffort(record.runtime, aliasBuffer) &&
|
|
217
|
+
copyBytes) {
|
|
218
|
+
releaseBorrowedReturnToken(token);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// best effort
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
outstandingBorrowedReturns.clear();
|
|
226
|
+
};
|
|
181
227
|
const queue = createHostTxQueue({
|
|
182
228
|
lock,
|
|
183
229
|
returnLock,
|
|
184
230
|
abortSignals,
|
|
185
231
|
releaseBufferReferenceReturn: bufferReferenceReturn === "borrow"
|
|
186
|
-
?
|
|
187
|
-
|
|
232
|
+
? {
|
|
233
|
+
release: releaseBorrowedReturnToken,
|
|
234
|
+
track: (ref, token, aliasBuffer) => {
|
|
235
|
+
if (outstandingBorrowedReturns === undefined)
|
|
236
|
+
return;
|
|
237
|
+
const record = outstandingBorrowedReturns.get(token);
|
|
238
|
+
if (record !== undefined) {
|
|
239
|
+
if (aliasBuffer !== undefined) {
|
|
240
|
+
record.aliasBuffer = new WeakRef(aliasBuffer);
|
|
241
|
+
}
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
outstandingBorrowedReturns.set(token, {
|
|
245
|
+
ref: new WeakRef(ref),
|
|
246
|
+
aliasBuffer: aliasBuffer === undefined
|
|
247
|
+
? undefined
|
|
248
|
+
: new WeakRef(aliasBuffer),
|
|
249
|
+
runtime: ref.runtime,
|
|
250
|
+
});
|
|
251
|
+
},
|
|
188
252
|
}
|
|
189
253
|
: undefined,
|
|
190
254
|
});
|
|
@@ -325,17 +389,21 @@ export const spawnWorkerContext = ({ list, ids, names, sab, thread, debug, hostD
|
|
|
325
389
|
worker.postMessage?.(workerDataPayload);
|
|
326
390
|
}
|
|
327
391
|
let closedReason;
|
|
328
|
-
|
|
392
|
+
// `workerBytesReadable`: while the worker is still alive its pinned bytes
|
|
393
|
+
// can be copied out; after a crash/exit they are gone and borrows are
|
|
394
|
+
// detached so stale reads fail loud instead of aliasing freed memory.
|
|
395
|
+
const markWorkerClosed = (reason, workerBytesReadable = false) => {
|
|
329
396
|
if (closedReason)
|
|
330
397
|
return;
|
|
331
398
|
closedReason = reason;
|
|
399
|
+
revokeOutstandingBorrowedReturns(workerBytesReadable);
|
|
332
400
|
rejectAll(reason);
|
|
333
401
|
channelHandler?.close();
|
|
334
402
|
};
|
|
335
403
|
const onWorkerMessage = (message) => {
|
|
336
404
|
if (!isWorkerFatalMessage(message))
|
|
337
405
|
return;
|
|
338
|
-
markWorkerClosed(`Worker startup failed: ${message[WORKER_FATAL_MESSAGE_KEY]}
|
|
406
|
+
markWorkerClosed(`Worker startup failed: ${message[WORKER_FATAL_MESSAGE_KEY]}`, true);
|
|
339
407
|
terminateWorkerQuietly(worker);
|
|
340
408
|
};
|
|
341
409
|
const onWorkerError = (error) => {
|
|
@@ -388,7 +456,7 @@ export const spawnWorkerContext = ({ list, ids, names, sab, thread, debug, hostD
|
|
|
388
456
|
txIdle,
|
|
389
457
|
call,
|
|
390
458
|
kills: async () => {
|
|
391
|
-
markWorkerClosed("Thread closed");
|
|
459
|
+
markWorkerClosed("Thread closed", true);
|
|
392
460
|
terminateWorkerQuietly(worker);
|
|
393
461
|
cleanupProcessWorkerMemoryQuietly(processWorkerMemory);
|
|
394
462
|
},
|
|
@@ -36,7 +36,7 @@ export type ProcessWorkerMemoryLayout = {
|
|
|
36
36
|
returnPayload: SharedBufferSource;
|
|
37
37
|
cleanup: () => void;
|
|
38
38
|
};
|
|
39
|
-
export type ProcessWorkerRuntime =
|
|
39
|
+
export type ProcessWorkerRuntime = "bun" | "deno" | "node";
|
|
40
40
|
export type ProcessWorkerCommandPrefix = NonNullable<WorkerSettings["processCommandPrefix"]>;
|
|
41
41
|
export type ResolvedProcessSharedMemorySettings = {
|
|
42
42
|
mode: "inherit" | "named";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as fileURLToPathCompat } from "node:url";
|
|
2
1
|
import { HEADER_SLOT_STRIDE_U32, LOCK_SECTOR_BYTE_LENGTH, LockBound, } from "../memory/lock.js";
|
|
3
2
|
import { createByteCarpet, getHeaderBlockByteLength, makeSharedBufferRegion, } from "../memory/byte-carpet.js";
|
|
4
3
|
import { RUNTIME } from "../common/runtime.js";
|
|
@@ -12,6 +11,15 @@ import { FileDescriptor, ProcessSharedBuffer, } from "../connections/index.js";
|
|
|
12
11
|
import { createNodeConnectionPrimitives, loadNodeFutexAddon, } from "../connections/node.js";
|
|
13
12
|
import { loadNodeNativeAddon } from "../connections/node-addons.js";
|
|
14
13
|
import { detectPosixPlatform } from "../connections/posix.js";
|
|
14
|
+
// `node:url` resolved lazily so this module evaluates on runtimes without it
|
|
15
|
+
// (e.g. Andromeda); process workers aren't used there, so it never runs.
|
|
16
|
+
const fileURLToPathCompat = (value) => {
|
|
17
|
+
const url = getNodeBuiltinModule("node:url");
|
|
18
|
+
if (url === undefined) {
|
|
19
|
+
throw new Error("node:url is not available in this runtime");
|
|
20
|
+
}
|
|
21
|
+
return url.fileURLToPath(value);
|
|
22
|
+
};
|
|
15
23
|
const execFlagKey = (flag) => flag.split("=", 1)[0];
|
|
16
24
|
const NODE_PERMISSION_EXEC_FLAGS = new Set([
|
|
17
25
|
"--permission",
|
|
@@ -20,10 +28,13 @@ const NODE_PERMISSION_EXEC_FLAGS = new Set([
|
|
|
20
28
|
"--allow-fs-write",
|
|
21
29
|
"--allow-worker",
|
|
22
30
|
"--allow-child-process",
|
|
31
|
+
"--allow-net",
|
|
23
32
|
"--allow-addons",
|
|
33
|
+
"--allow-ffi",
|
|
24
34
|
"--allow-wasi",
|
|
25
35
|
]);
|
|
26
36
|
const NODE_WORKER_SAFE_EXEC_FLAGS = new Set([
|
|
37
|
+
"--experimental-ffi",
|
|
27
38
|
"--experimental-transform-types",
|
|
28
39
|
"--expose-gc",
|
|
29
40
|
"--no-warnings",
|
|
@@ -107,10 +118,23 @@ const DENO_PROCESS_WORKER_INTERNAL_FLAGS = [
|
|
|
107
118
|
`--allow-env=${DENO_PROCESS_WORKER_BOOT_ENV_ALLOW}`,
|
|
108
119
|
"--allow-ffi",
|
|
109
120
|
];
|
|
110
|
-
const
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
|
|
121
|
+
const nodeMajorVersion = () => {
|
|
122
|
+
const version = getNodeProcess()?.versions?.node ?? "";
|
|
123
|
+
const major = Number.parseInt(version.split(".", 1)[0] ?? "", 10);
|
|
124
|
+
return Number.isInteger(major) ? major : 0;
|
|
125
|
+
};
|
|
126
|
+
const nodeProcessWorkerUsesFfi = () => {
|
|
127
|
+
const major = nodeMajorVersion();
|
|
128
|
+
return major >= 26 && major % 2 === 0;
|
|
129
|
+
};
|
|
130
|
+
const nodeProcessWorkerInternalExecArgv = () => {
|
|
131
|
+
return [
|
|
132
|
+
"--no-warnings",
|
|
133
|
+
...(nodeProcessWorkerUsesFfi()
|
|
134
|
+
? ["--experimental-ffi"]
|
|
135
|
+
: ["--experimental-transform-types"]),
|
|
136
|
+
];
|
|
137
|
+
};
|
|
114
138
|
const getProcessWorkerSharedMemoryPrimitives = () => {
|
|
115
139
|
switch (RUNTIME) {
|
|
116
140
|
case "bun":
|
|
@@ -393,7 +417,7 @@ const processWorkerNodeBinary = (commandPrefix) => {
|
|
|
393
417
|
: undefined) ??
|
|
394
418
|
DEFAULT_NODE_BINARY;
|
|
395
419
|
};
|
|
396
|
-
const processWorkerNodeExecArgv = () => {
|
|
420
|
+
const processWorkerNodeExecArgv = (permission) => {
|
|
397
421
|
const out = [];
|
|
398
422
|
const seen = new Set();
|
|
399
423
|
const add = (flag) => {
|
|
@@ -405,8 +429,17 @@ const processWorkerNodeExecArgv = () => {
|
|
|
405
429
|
for (const flag of toWorkerCompatExecArgv(getNodeProcess()?.execArgv) ?? []) {
|
|
406
430
|
add(flag);
|
|
407
431
|
}
|
|
408
|
-
for (const flag of
|
|
432
|
+
for (const flag of nodeProcessWorkerInternalExecArgv())
|
|
409
433
|
add(flag);
|
|
434
|
+
if (permission?.enabled === true && permission.unsafe !== true) {
|
|
435
|
+
for (const flag of permission.node.flags)
|
|
436
|
+
add(flag);
|
|
437
|
+
if (permission.netAll && nodeMajorVersion() >= 25)
|
|
438
|
+
add("--allow-net");
|
|
439
|
+
// Node process workers need one native transport capability regardless of
|
|
440
|
+
// task permissions: addons on Node 22/24, node:ffi on supported Node 26+ LTS.
|
|
441
|
+
add(nodeProcessWorkerUsesFfi() ? "--allow-ffi" : "--allow-addons");
|
|
442
|
+
}
|
|
410
443
|
return out;
|
|
411
444
|
};
|
|
412
445
|
const processWorkerCommand = ({ processRuntime, workerUrl, bun, deno, commandPrefix, permission, }) => {
|
|
@@ -423,7 +456,7 @@ const processWorkerCommand = ({ processRuntime, workerUrl, bun, deno, commandPre
|
|
|
423
456
|
else if (processRuntime === "node") {
|
|
424
457
|
command = [
|
|
425
458
|
processWorkerNodeBinary(commandPrefix),
|
|
426
|
-
...processWorkerNodeExecArgv(),
|
|
459
|
+
...processWorkerNodeExecArgv(permission),
|
|
427
460
|
workerPath,
|
|
428
461
|
];
|
|
429
462
|
}
|
|
@@ -670,4 +703,11 @@ export const cleanupProcessWorkerMemoryQuietly = (memory) => {
|
|
|
670
703
|
}
|
|
671
704
|
catch {
|
|
672
705
|
}
|
|
706
|
+
finally {
|
|
707
|
+
try {
|
|
708
|
+
memory?.mapping.close?.();
|
|
709
|
+
}
|
|
710
|
+
catch {
|
|
711
|
+
}
|
|
712
|
+
}
|
|
673
713
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import "../memory/payloadCodec.js";
|
|
1
2
|
import { type Lock2, type Task } from "../memory/lock.js";
|
|
2
3
|
import type { AbortSignalOption, TaskTimeout } from "../types.js";
|
|
3
4
|
import { type SignalAbortStore } from "../shared/abortSignal.js";
|
|
5
|
+
import { type BufferReferenceReturnHooks } from "../connections/buffer-reference.js";
|
|
4
6
|
type RawArguments = unknown;
|
|
5
7
|
type FunctionID = number;
|
|
6
8
|
type QueueTask = Task;
|
|
@@ -9,7 +11,7 @@ type CreateHostTxQueueArgs = {
|
|
|
9
11
|
max?: number;
|
|
10
12
|
lock: Lock2;
|
|
11
13
|
returnLock: Lock2;
|
|
12
|
-
releaseBufferReferenceReturn?: (token: bigint) => void;
|
|
14
|
+
releaseBufferReferenceReturn?: ((token: bigint) => void) | BufferReferenceReturnHooks;
|
|
13
15
|
abortSignals?: Pick<SignalAbortStore, "getSignal" | "setSignal" | "resetSignal" | "closeNow">;
|
|
14
16
|
now?: () => number;
|
|
15
17
|
};
|
package/src/runtime/tx-queue.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
// Side-effect import: registers the payload codec (cycle break for Andromeda;
|
|
2
|
+
// see lock.ts), ensuring registration before any lock2() call.
|
|
3
|
+
import "../memory/payloadCodec.js";
|
|
1
4
|
import { makeTask, resetTaskLocalFlags, runTaskFinalizers, TaskIndex, } from "../memory/lock.js";
|
|
2
5
|
import { withResolvers } from "../common/with-resolvers.js";
|
|
3
6
|
import { AbortSignalPoolExhausted, OneShotDeferred, } from "../shared/abortSignal.js";
|
|
4
|
-
import { withBufferReferenceReturnReleaser } from "../connections/buffer-reference.js";
|
|
7
|
+
import { withBufferReferenceReturnReleaser, } from "../connections/buffer-reference.js";
|
|
5
8
|
const SLOT_INDEX_MASK = 31;
|
|
6
9
|
const SLOT_META_MASK = 0x07ffffff;
|
|
7
10
|
const SLOT_META_SHIFT = 5;
|
package/src/types.d.ts
CHANGED
|
@@ -83,6 +83,7 @@ type AbortSignalConfig = {
|
|
|
83
83
|
type AbortSignalOption = true | AbortSignalConfig | undefined;
|
|
84
84
|
type AbortSignalMethods<AS extends AbortSignalOption> = AS extends undefined ? never : {
|
|
85
85
|
hasAborted: () => boolean;
|
|
86
|
+
now: () => number;
|
|
86
87
|
};
|
|
87
88
|
type AbortSignalToolkit<AS extends AbortSignalOption> = AbortSignalMethods<AS>;
|
|
88
89
|
type TaskFn<A extends TaskInput, B extends Args, AS extends AbortSignalOption = undefined> = BivariantCallback<AS extends undefined ? [NoBlob<Awaited<A>>] : [NoBlob<Awaited<A>>, AbortSignalToolkit<AS>], MaybePromise<NoBlob<B>>>;
|
|
@@ -220,6 +221,41 @@ type WorkerBootstrapOptions<Data = unknown> = {
|
|
|
220
221
|
*/
|
|
221
222
|
data?: Data;
|
|
222
223
|
};
|
|
224
|
+
/** Native worker artifact and on-demand compiler settings. */
|
|
225
|
+
type CompiledWorkerOptions = {
|
|
226
|
+
/**
|
|
227
|
+
* Native executable path. Relative paths resolve from the createPool caller.
|
|
228
|
+
* Defaults to the task module path with its extension replaced by `.knt`.
|
|
229
|
+
*/
|
|
230
|
+
artifact?: string;
|
|
231
|
+
/**
|
|
232
|
+
* Versioned metadata sidecar. Defaults to `<artifact>.json`.
|
|
233
|
+
*/
|
|
234
|
+
manifest?: string;
|
|
235
|
+
/**
|
|
236
|
+
* Build a missing/incompatible artifact, or use `"always"` to rebuild once
|
|
237
|
+
* whenever a pool is created. Defaults to true.
|
|
238
|
+
*/
|
|
239
|
+
build?: boolean | "always";
|
|
240
|
+
/**
|
|
241
|
+
* Porffor main executable or checkout. Defaults to PORFFOR_MAIN/PORF, then
|
|
242
|
+
* `porf` on PATH; a pinned compiler is cached locally when none is present.
|
|
243
|
+
*/
|
|
244
|
+
compiler?: string;
|
|
245
|
+
};
|
|
246
|
+
type CompiledWorkerSource = string | URL | {
|
|
247
|
+
readonly importedFrom: string;
|
|
248
|
+
};
|
|
249
|
+
type CompiledWorkerCheck = {
|
|
250
|
+
/** True only when the executable and compatible manifest both validate. */
|
|
251
|
+
compiled: boolean;
|
|
252
|
+
artifact: string;
|
|
253
|
+
manifest: string;
|
|
254
|
+
reason?: string;
|
|
255
|
+
compiler?: string;
|
|
256
|
+
protocol?: string;
|
|
257
|
+
tasks?: readonly string[];
|
|
258
|
+
};
|
|
223
259
|
type WorkerSettings = {
|
|
224
260
|
resolveAfterFinishingAll?: true;
|
|
225
261
|
/**
|
|
@@ -230,13 +266,18 @@ type WorkerSettings = {
|
|
|
230
266
|
/**
|
|
231
267
|
* Experimental worker runtime.
|
|
232
268
|
* "thread" uses Worker/worker_threads. "process" spawns another JavaScript
|
|
233
|
-
* runtime, useful for process isolation, bwrap, and containers.
|
|
269
|
+
* runtime, useful for process isolation, bwrap, and containers. "compiled"
|
|
270
|
+
* validates and runs a `.knt` native worker, building it on first use.
|
|
234
271
|
*/
|
|
235
|
-
runtime?: "thread" | "process";
|
|
272
|
+
runtime?: "thread" | "process" | "compiled";
|
|
273
|
+
/** Artifact settings used when runtime is "compiled". */
|
|
274
|
+
compiled?: CompiledWorkerOptions;
|
|
236
275
|
/**
|
|
237
|
-
* Runtime executable
|
|
276
|
+
* Runtime executable for process workers. Standalone `"porffor"` selects the
|
|
277
|
+
* compiled backend and rebuilds once per pool; with `runtime: "compiled"` it
|
|
278
|
+
* reuses the validated artifact.
|
|
238
279
|
*/
|
|
239
|
-
processRuntime?: "bun" | "deno" | "node";
|
|
280
|
+
processRuntime?: "bun" | "deno" | "node" | "porffor";
|
|
240
281
|
/**
|
|
241
282
|
* Command argv to prepend before the process worker runtime command.
|
|
242
283
|
* Useful for wrappers such as systemd-run, cgexec, nice, taskset, or
|
|
@@ -351,7 +392,8 @@ type CreatePool = {
|
|
|
351
392
|
debug?: DebugOptions;
|
|
352
393
|
source?: string;
|
|
353
394
|
};
|
|
354
|
-
export type { AbortSignalConfig as AbortSignalConfig, AbortSignalMethods as AbortSignalMethods, AbortSignalOption as AbortSignalOption, AbortSignalToolkit as AbortSignalToolkit, Args as Args, Balancer as Balancer, BalancerStrategy as BalancerStrategy, Composed as Composed, ComposedWithKey as ComposedWithKey, CreateContext as CreateContext, CreatePool as CreatePool, DebugNamespace as DebugNamespace, DebugOptions as DebugOptions, DispatcherSettings as DispatcherSettings, Envelope as Envelope, EnvelopeBody as EnvelopeBody, EnvelopeHeader as EnvelopeHeader, External as External, FixPoint as FixPoint, FunctionMapType as FunctionMapType, ImportTaskOptions as ImportTaskOptions, Inliner as Inliner, LockBuffers as LockBuffers, LockBufferTextCompat as LockBufferTextCompat, MaybePromise as MaybePromise, PayloadBufferMode as PayloadBufferMode, PayloadBufferOptions as PayloadBufferOptions, PermissionProtocol as PermissionProtocol, PermissionProtocolInput as PermissionProtocolInput, Pool as Pool, ProcessSharedMemoryMode as ProcessSharedMemoryMode, ProcessSharedMemorySettings as ProcessSharedMemorySettings, ResolvedPermissionProtocol as ResolvedPermissionProtocol, ReturnFixed as ReturnFixed, SecondPart as SecondPart, SharedBufferRegion as SharedBufferRegion, SharedBufferSource as SharedBufferSource, SharedBufferTextCompat as SharedBufferTextCompat, SingleTaskPool as SingleTaskPool, TaskFn as TaskFn, TaskInput as TaskInput, tasks as tasks, TaskTimeout as TaskTimeout, ValidInput as ValidInput, WorkerBootstrapContext as WorkerBootstrapContext, WorkerBootstrapFunction as WorkerBootstrapFunction, WorkerBootstrapOptions as WorkerBootstrapOptions, WorkerCall as WorkerCall, WorkerContext as WorkerContext, WorkerData as WorkerData, WorkerInvoke as WorkerInvoke, WorkerSettings as WorkerSettings, WorkerTimers as WorkerTimers, };
|
|
355
|
-
|
|
395
|
+
export type { AbortSignalConfig as AbortSignalConfig, AbortSignalMethods as AbortSignalMethods, AbortSignalOption as AbortSignalOption, AbortSignalToolkit as AbortSignalToolkit, Args as Args, Balancer as Balancer, BalancerStrategy as BalancerStrategy, CompiledWorkerCheck as CompiledWorkerCheck, CompiledWorkerOptions as CompiledWorkerOptions, CompiledWorkerSource as CompiledWorkerSource, Composed as Composed, ComposedWithKey as ComposedWithKey, CreateContext as CreateContext, CreatePool as CreatePool, DebugNamespace as DebugNamespace, DebugOptions as DebugOptions, DispatcherSettings as DispatcherSettings, Envelope as Envelope, EnvelopeBody as EnvelopeBody, EnvelopeHeader as EnvelopeHeader, External as External, FixPoint as FixPoint, FunctionMapType as FunctionMapType, ImportTaskOptions as ImportTaskOptions, Inliner as Inliner, LockBuffers as LockBuffers, LockBufferTextCompat as LockBufferTextCompat, MaybePromise as MaybePromise, PayloadBufferMode as PayloadBufferMode, PayloadBufferOptions as PayloadBufferOptions, PermissionProtocol as PermissionProtocol, PermissionProtocolInput as PermissionProtocolInput, Pool as Pool, ProcessSharedMemoryMode as ProcessSharedMemoryMode, ProcessSharedMemorySettings as ProcessSharedMemorySettings, ResolvedPermissionProtocol as ResolvedPermissionProtocol, ReturnFixed as ReturnFixed, SecondPart as SecondPart, SharedBufferRegion as SharedBufferRegion, SharedBufferSource as SharedBufferSource, SharedBufferTextCompat as SharedBufferTextCompat, SingleTaskPool as SingleTaskPool, TaskFn as TaskFn, TaskInput as TaskInput, tasks as tasks, TaskTimeout as TaskTimeout, ValidInput as ValidInput, WorkerBootstrapContext as WorkerBootstrapContext, WorkerBootstrapFunction as WorkerBootstrapFunction, WorkerBootstrapOptions as WorkerBootstrapOptions, WorkerCall as WorkerCall, WorkerContext as WorkerContext, WorkerData as WorkerData, WorkerInvoke as WorkerInvoke, WorkerSettings as WorkerSettings, WorkerTimers as WorkerTimers, };
|
|
396
|
+
import type { Task as TaskType } from "./memory/lock.js";
|
|
356
397
|
export { LockBound as LockBound, PayloadBuffer as PayloadBuffer, PayloadSignal as PayloadSignal, TaskIndex as TaskIndex, } from "./memory/lock.js";
|
|
398
|
+
export type Task = TaskType;
|
|
357
399
|
export type { RegisterMalloc as RegisterMalloc } from "./memory/regionRegistry.js";
|
|
@@ -49,7 +49,7 @@ const readSignal = (slot) => {
|
|
|
49
49
|
const signal = (encodedSignal - ABORT_SIGNAL_META_OFFSET) | 0;
|
|
50
50
|
return signal >= 0 ? signal : NO_ABORT_SIGNAL;
|
|
51
51
|
};
|
|
52
|
-
const makeToolkitCache = (hasAborted) => {
|
|
52
|
+
const makeToolkitCache = (hasAborted, now) => {
|
|
53
53
|
const bySignal = [];
|
|
54
54
|
return (signal) => {
|
|
55
55
|
let toolkit = bySignal[signal];
|
|
@@ -58,6 +58,7 @@ const makeToolkitCache = (hasAborted) => {
|
|
|
58
58
|
const hasAbortedMethod = () => hasAborted(signal);
|
|
59
59
|
toolkit = {
|
|
60
60
|
hasAborted: hasAbortedMethod,
|
|
61
|
+
now,
|
|
61
62
|
};
|
|
62
63
|
bySignal[signal] = toolkit;
|
|
63
64
|
return toolkit;
|
|
@@ -76,7 +77,7 @@ export const composeWorkerRunner = ({ job, timeout, hasAborted, now, }) => {
|
|
|
76
77
|
return applyTimeoutBudget(result, slot, timeout, nowTime);
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
|
-
const getToolkit = makeToolkitCache(hasAborted);
|
|
80
|
+
const getToolkit = makeToolkitCache(hasAborted, nowTime);
|
|
80
81
|
if (!timeout) {
|
|
81
82
|
return (slot) => {
|
|
82
83
|
const signal = readSignal(slot);
|
package/src/worker/loop.d.ts
CHANGED
package/src/worker/loop.js
CHANGED
|
@@ -4,9 +4,12 @@ import { isLockBufferTextCompat } from "../common/shared-buffer-text.js";
|
|
|
4
4
|
import { createWorkerRxQueue } from "./rx-queue.js";
|
|
5
5
|
import { createSharedMemoryTransport } from "../ipc/transport/shared-memory.js";
|
|
6
6
|
import { lock2 } from "../memory/lock.js";
|
|
7
|
+
// Side-effect import: registers the payload codec (cycle break for Andromeda;
|
|
8
|
+
// see lock.ts). Must run before any lock2() call.
|
|
9
|
+
import "../memory/payloadCodec.js";
|
|
7
10
|
import { getFunctions } from "./task-loader.js";
|
|
8
11
|
import { pauseGeneric, sleepUntilChanged, whilePausing } from "./timers.js";
|
|
9
|
-
import { RUNTIME, SET_IMMEDIATE } from "../common/runtime.js";
|
|
12
|
+
import { IS_ANDROMEDA, RUNTIME, SET_IMMEDIATE } from "../common/runtime.js";
|
|
10
13
|
import { getNodeProcess } from "../common/node-compat.js";
|
|
11
14
|
import { assertWorkerImportsResolved, assertWorkerSharedMemoryBootData, installPerformanceNowGuard, installTerminationGuard, installUnhandledRejectionSilencer, scrubWorkerDataSensitiveBuffers, } from "./safety/index.js";
|
|
12
15
|
import { signalAbortFactory } from "../shared/abortSignal.js";
|
|
@@ -81,10 +84,10 @@ export const workerMainLoop = async (startupData) => {
|
|
|
81
84
|
namespaces: debugNamespaces,
|
|
82
85
|
}))
|
|
83
86
|
: undefined;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
87
|
+
// const object, not `enum`: Andromeda's Nova engine can't parse `enum`.
|
|
88
|
+
const Comment = {
|
|
89
|
+
thisIsAHint: 0,
|
|
90
|
+
};
|
|
88
91
|
const signals = createSharedMemoryTransport({
|
|
89
92
|
sabObject: {
|
|
90
93
|
sharedSab: sab,
|
|
@@ -101,6 +104,7 @@ export const workerMainLoop = async (startupData) => {
|
|
|
101
104
|
payloadSector: lock.payloadSector,
|
|
102
105
|
payloadConfig,
|
|
103
106
|
textCompat: lock.textCompat,
|
|
107
|
+
processBoundary: RUNTIME_IS_PROCESS_WORKER,
|
|
104
108
|
});
|
|
105
109
|
const returnLockState = lock2({
|
|
106
110
|
headers: returnLock.headers,
|
|
@@ -110,6 +114,7 @@ export const workerMainLoop = async (startupData) => {
|
|
|
110
114
|
payloadSector: returnLock.payloadSector,
|
|
111
115
|
payloadConfig,
|
|
112
116
|
textCompat: returnLock.textCompat,
|
|
117
|
+
processBoundary: RUNTIME_IS_PROCESS_WORKER,
|
|
113
118
|
});
|
|
114
119
|
const timers = workerOptions?.timers;
|
|
115
120
|
const spinMicroseconds = timers?.spinMicroseconds ??
|
|
@@ -295,15 +300,23 @@ export const workerMainLoop = async (startupData) => {
|
|
|
295
300
|
};
|
|
296
301
|
const isWorkerGlobalScope = () => {
|
|
297
302
|
const scopeCtor = globalThis.WorkerGlobalScope;
|
|
298
|
-
if (typeof scopeCtor
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
+
if (typeof scopeCtor === "function") {
|
|
304
|
+
try {
|
|
305
|
+
if (globalThis instanceof scopeCtor) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// fall through to runtime-specific checks
|
|
311
|
+
}
|
|
303
312
|
}
|
|
304
|
-
|
|
305
|
-
|
|
313
|
+
// Andromeda has no `WorkerGlobalScope`; its worker scope carries a `self`
|
|
314
|
+
// global that the main thread lacks.
|
|
315
|
+
if (IS_ANDROMEDA &&
|
|
316
|
+
typeof globalThis.self !== "undefined") {
|
|
317
|
+
return true;
|
|
306
318
|
}
|
|
319
|
+
return false;
|
|
307
320
|
};
|
|
308
321
|
const isLockBuffers = (value) => {
|
|
309
322
|
if (!value || typeof value !== "object")
|