knitting 0.1.55 → 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 +7 -797
- package/knitting.js +6 -9780
- package/map.md +31 -15
- package/package.json +20 -6
- package/process-shared-buffer.d.ts +1 -0
- package/process-shared-buffer.js +1 -0
- 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/shared-memory.d.ts +1 -155
- package/shared-memory.js +1 -1342
- package/src/api.d.ts +92 -0
- package/src/api.js +798 -0
- package/src/common/envelope.d.ts +17 -0
- package/src/common/envelope.js +22 -0
- package/src/common/module-url.d.ts +2 -0
- package/src/common/module-url.js +52 -0
- package/src/common/node-compat.d.ts +22 -0
- package/src/common/node-compat.js +24 -0
- package/src/common/path-canonical.d.ts +6 -0
- package/src/common/path-canonical.js +55 -0
- package/src/common/runtime.d.ts +16 -0
- package/src/common/runtime.js +105 -0
- package/src/common/shared-buffer-region.d.ts +11 -0
- package/src/common/shared-buffer-region.js +21 -0
- package/src/common/shared-buffer-text.d.ts +16 -0
- package/src/common/shared-buffer-text.js +65 -0
- package/src/common/task-source.d.ts +5 -0
- package/src/common/task-source.js +100 -0
- package/src/common/task-symbol.d.ts +1 -0
- package/src/common/task-symbol.js +1 -0
- package/src/common/with-resolvers.d.ts +9 -0
- package/src/common/with-resolvers.js +23 -0
- package/src/common/worker-runtime.d.ts +42 -0
- package/src/common/worker-runtime.js +70 -0
- package/src/connections/buffer-reference-native.d.ts +56 -0
- package/src/connections/buffer-reference-native.js +241 -0
- package/src/connections/buffer-reference.d.ts +99 -0
- package/src/connections/buffer-reference.js +575 -0
- package/src/connections/bun.d.ts +22 -0
- package/src/connections/bun.js +225 -0
- package/src/connections/deno.d.ts +24 -0
- package/src/connections/deno.js +226 -0
- package/src/connections/external-array-buffer.d.ts +2 -0
- package/src/connections/external-array-buffer.js +33 -0
- package/src/connections/file-descriptor.d.ts +39 -0
- package/src/connections/file-descriptor.js +161 -0
- package/src/connections/index.d.ts +4 -0
- package/src/connections/index.js +4 -0
- package/src/connections/node-addons.d.ts +16 -0
- package/src/connections/node-addons.js +92 -0
- package/src/connections/node-buffer-pointer.d.ts +20 -0
- package/src/connections/node-buffer-pointer.js +16 -0
- 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 +30 -0
- package/src/connections/node.js +62 -0
- package/src/connections/numeric-array.d.ts +5 -0
- package/src/connections/numeric-array.js +17 -0
- package/src/connections/package-assets.d.ts +2 -0
- package/src/connections/package-assets.js +55 -0
- package/src/connections/posix.d.ts +74 -0
- package/src/connections/posix.js +178 -0
- package/src/connections/process-shared-buffer.d.ts +76 -0
- package/src/connections/process-shared-buffer.js +245 -0
- package/src/connections/shared-array-buffer-payload.d.ts +36 -0
- package/src/connections/shared-array-buffer-payload.js +235 -0
- package/src/connections/types.d.ts +54 -0
- package/src/connections/types.js +37 -0
- package/src/connections/windows.d.ts +37 -0
- package/src/connections/windows.js +245 -0
- package/src/debug/env-diff.d.ts +26 -0
- package/src/debug/env-diff.js +49 -0
- package/src/debug/gate.d.ts +18 -0
- package/src/debug/gate.js +69 -0
- package/src/debug/handle.d.ts +23 -0
- package/src/debug/handle.js +48 -0
- package/src/error.d.ts +14 -0
- package/src/error.js +50 -0
- package/src/ipc/tools/ring-queue.d.ts +33 -0
- package/src/ipc/tools/ring-queue.js +159 -0
- package/src/ipc/transport/shared-memory.d.ts +23 -0
- package/src/ipc/transport/shared-memory.js +35 -0
- package/src/memory/byte-carpet.d.ts +73 -0
- package/src/memory/byte-carpet.js +157 -0
- package/src/memory/lock.d.ts +213 -0
- package/src/memory/lock.js +760 -0
- package/src/memory/payload-config.d.ts +31 -0
- package/src/memory/payload-config.js +67 -0
- package/src/memory/payloadCodec.d.ts +55 -0
- package/src/memory/payloadCodec.js +1473 -0
- package/src/memory/regionRegistry.d.ts +17 -0
- package/src/memory/regionRegistry.js +285 -0
- package/src/memory/shared-buffer-io.d.ts +55 -0
- package/src/memory/shared-buffer-io.js +403 -0
- package/src/permission/compatibility.d.ts +28 -0
- package/src/permission/compatibility.js +239 -0
- package/src/permission/index.d.ts +4 -0
- package/src/permission/index.js +3 -0
- package/src/permission/protocol.d.ts +167 -0
- package/src/permission/protocol.js +690 -0
- package/src/runtime/balancer.d.ts +19 -0
- package/src/runtime/balancer.js +149 -0
- 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/dispatcher.d.ts +40 -0
- package/src/runtime/dispatcher.js +142 -0
- package/src/runtime/inline-executor.d.ts +10 -0
- package/src/runtime/inline-executor.js +294 -0
- package/src/runtime/pool.d.ts +44 -0
- package/src/runtime/pool.js +472 -0
- package/src/runtime/process-worker.d.ts +92 -0
- package/src/runtime/process-worker.js +713 -0
- package/src/runtime/tx-queue.d.ts +28 -0
- package/src/runtime/tx-queue.js +158 -0
- package/src/shared/abortSignal.d.ts +23 -0
- package/src/shared/abortSignal.js +134 -0
- package/src/types.d.ts +399 -0
- package/src/types.js +2 -0
- package/src/utils/http.d.ts +29 -0
- package/src/utils/http.js +100 -0
- package/src/worker/bootstrap.d.ts +5 -0
- package/src/worker/bootstrap.js +78 -0
- package/src/worker/composable-runners.d.ts +12 -0
- package/src/worker/composable-runners.js +98 -0
- package/src/worker/loop.d.ts +3 -0
- package/src/worker/loop.js +395 -0
- package/src/worker/process-worker-bootstrap.d.ts +8 -0
- package/src/worker/process-worker-bootstrap.js +160 -0
- package/src/worker/rx-queue.d.ts +25 -0
- package/src/worker/rx-queue.js +173 -0
- package/src/worker/safety/index.d.ts +4 -0
- package/src/worker/safety/index.js +4 -0
- package/src/worker/safety/performance.d.ts +1 -0
- package/src/worker/safety/performance.js +17 -0
- package/src/worker/safety/process.d.ts +2 -0
- package/src/worker/safety/process.js +79 -0
- package/src/worker/safety/startup.d.ts +16 -0
- package/src/worker/safety/startup.js +30 -0
- package/src/worker/safety/worker-data.d.ts +2 -0
- package/src/worker/safety/worker-data.js +36 -0
- package/src/worker/task-loader.d.ts +28 -0
- package/src/worker/task-loader.js +76 -0
- package/src/worker/timers.d.ts +18 -0
- package/src/worker/timers.js +118 -0
- package/unsafe.d.ts +1 -71
- package/unsafe.js +1 -878
- package/utils.d.ts +1 -31
- package/utils.js +1 -116
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "../memory/payloadCodec.js";
|
|
2
|
+
import { type Lock2, type Task } from "../memory/lock.js";
|
|
3
|
+
import type { AbortSignalOption, TaskTimeout } from "../types.js";
|
|
4
|
+
import { type SignalAbortStore } from "../shared/abortSignal.js";
|
|
5
|
+
import { type BufferReferenceReturnHooks } from "../connections/buffer-reference.js";
|
|
6
|
+
type RawArguments = unknown;
|
|
7
|
+
type FunctionID = number;
|
|
8
|
+
type QueueTask = Task;
|
|
9
|
+
export type MultiQueue = ReturnType<typeof createHostTxQueue>;
|
|
10
|
+
type CreateHostTxQueueArgs = {
|
|
11
|
+
max?: number;
|
|
12
|
+
lock: Lock2;
|
|
13
|
+
returnLock: Lock2;
|
|
14
|
+
releaseBufferReferenceReturn?: ((token: bigint) => void) | BufferReferenceReturnHooks;
|
|
15
|
+
abortSignals?: Pick<SignalAbortStore, "getSignal" | "setSignal" | "resetSignal" | "closeNow">;
|
|
16
|
+
now?: () => number;
|
|
17
|
+
};
|
|
18
|
+
export declare function createHostTxQueue({ max, lock, returnLock, releaseBufferReferenceReturn, abortSignals, now, }: CreateHostTxQueueArgs): {
|
|
19
|
+
rejectAll: (reason: string) => void;
|
|
20
|
+
hasPendingFrames: () => boolean;
|
|
21
|
+
txIdle: () => boolean;
|
|
22
|
+
completeFrame: () => number;
|
|
23
|
+
enqueue: (functionID: FunctionID, timeout?: TaskTimeout, abortSignal?: AbortSignalOption) => (rawArgs: RawArguments) => Promise<never> | import("../common/with-resolvers.js").PromiseWithMaybeReject<unknown>;
|
|
24
|
+
flushToWorker: () => boolean;
|
|
25
|
+
enqueueKnown: (task: QueueTask) => boolean;
|
|
26
|
+
settlePromisePayload: (task: QueueTask, isRejected: boolean, value: unknown) => boolean;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
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";
|
|
4
|
+
import { makeTask, resetTaskLocalFlags, runTaskFinalizers, TaskIndex, } from "../memory/lock.js";
|
|
5
|
+
import { withResolvers } from "../common/with-resolvers.js";
|
|
6
|
+
import { AbortSignalPoolExhausted, OneShotDeferred, } from "../shared/abortSignal.js";
|
|
7
|
+
import { withBufferReferenceReturnReleaser, } from "../connections/buffer-reference.js";
|
|
8
|
+
const SLOT_INDEX_MASK = 31;
|
|
9
|
+
const SLOT_META_MASK = 0x07ffffff;
|
|
10
|
+
const SLOT_META_SHIFT = 5;
|
|
11
|
+
const FUNCTION_ID_MASK = 0xffff;
|
|
12
|
+
const FUNCTION_META_MASK = 0xffff;
|
|
13
|
+
const FUNCTION_META_SHIFT = 16;
|
|
14
|
+
const ABORT_SIGNAL_META_OFFSET = 1;
|
|
15
|
+
const NO_ABORT_SIGNAL = -1;
|
|
16
|
+
const p_now = performance.now.bind(performance);
|
|
17
|
+
export function createHostTxQueue({ max, lock, returnLock, releaseBufferReferenceReturn, abortSignals, now, }) {
|
|
18
|
+
const PLACE_HOLDER = (_) => {
|
|
19
|
+
throw ("UNREACHABLE FROM PLACE HOLDER (main)");
|
|
20
|
+
};
|
|
21
|
+
const newSlot = (id) => {
|
|
22
|
+
const task = makeTask();
|
|
23
|
+
task[TaskIndex.ID] = id;
|
|
24
|
+
task[TaskIndex.FunctionID] = 0;
|
|
25
|
+
task.value = null;
|
|
26
|
+
task.resolve = PLACE_HOLDER;
|
|
27
|
+
task.reject = PLACE_HOLDER;
|
|
28
|
+
return task;
|
|
29
|
+
};
|
|
30
|
+
const initialSize = max ?? 10;
|
|
31
|
+
const queue = Array.from({ length: initialSize }, (_, index) => newSlot(index));
|
|
32
|
+
const freeSockets = Array.from({ length: initialSize }, (_, i) => i);
|
|
33
|
+
const freePush = (id) => freeSockets.push(id);
|
|
34
|
+
const freePop = () => freeSockets.pop();
|
|
35
|
+
const queuePush = (task) => queue.push(task);
|
|
36
|
+
const { publish, flushPending, hasPendingFrames, getPendingFrameCount, getPendingPromiseCount, resetPendingState, } = lock;
|
|
37
|
+
let inUsed = 0 | 0;
|
|
38
|
+
const resetSignal = abortSignals?.resetSignal;
|
|
39
|
+
const nowTime = now ?? p_now;
|
|
40
|
+
const resolveReturn = returnLock.resolveHost({
|
|
41
|
+
queue,
|
|
42
|
+
activeRejectPlaceholder: PLACE_HOLDER,
|
|
43
|
+
onResolved: (task) => {
|
|
44
|
+
inUsed = (inUsed - 1) | 0;
|
|
45
|
+
resetTaskLocalFlags(task);
|
|
46
|
+
runTaskFinalizers(task);
|
|
47
|
+
task.value = null;
|
|
48
|
+
task.resolve = PLACE_HOLDER;
|
|
49
|
+
task.reject = PLACE_HOLDER;
|
|
50
|
+
freePush(task[TaskIndex.ID]);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const completeFrame = releaseBufferReferenceReturn === undefined
|
|
54
|
+
? resolveReturn
|
|
55
|
+
: () => withBufferReferenceReturnReleaser(releaseBufferReferenceReturn, resolveReturn);
|
|
56
|
+
const hasActiveTasks = () => {
|
|
57
|
+
const count = (inUsed - getPendingPromiseCount()) | 0;
|
|
58
|
+
return count > 0;
|
|
59
|
+
};
|
|
60
|
+
const txIdle = () => getPendingFrameCount() === 0 && !hasActiveTasks();
|
|
61
|
+
const rejectAll = (reason) => {
|
|
62
|
+
for (let index = 0; index < queue.length; index++) {
|
|
63
|
+
const slot = queue[index];
|
|
64
|
+
if (slot.reject !== PLACE_HOLDER) {
|
|
65
|
+
try {
|
|
66
|
+
slot.reject(reason);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
}
|
|
70
|
+
runTaskFinalizers(slot);
|
|
71
|
+
slot.resolve = PLACE_HOLDER;
|
|
72
|
+
slot.reject = PLACE_HOLDER;
|
|
73
|
+
queue[index] = newSlot(index);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
resetPendingState();
|
|
77
|
+
inUsed = 0 | 0;
|
|
78
|
+
};
|
|
79
|
+
const flushToWorker = () => flushPending();
|
|
80
|
+
const enqueueKnown = (task) => {
|
|
81
|
+
return publish(task);
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
rejectAll,
|
|
85
|
+
hasPendingFrames,
|
|
86
|
+
txIdle,
|
|
87
|
+
completeFrame,
|
|
88
|
+
enqueue: (functionID, timeout, abortSignal) => {
|
|
89
|
+
const HAS_TIMER = timeout !== undefined;
|
|
90
|
+
const functionIDMasked = functionID & FUNCTION_ID_MASK;
|
|
91
|
+
const USE_SIGNAL = abortSignal !== undefined &&
|
|
92
|
+
abortSignals !== undefined;
|
|
93
|
+
return (rawArgs) => {
|
|
94
|
+
if (inUsed === queue.length) {
|
|
95
|
+
const newSize = inUsed + 32;
|
|
96
|
+
let current = queue.length;
|
|
97
|
+
while (newSize > current) {
|
|
98
|
+
queuePush(newSlot(current));
|
|
99
|
+
freePush(current);
|
|
100
|
+
current++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const index = freePop();
|
|
104
|
+
const slot = queue[index];
|
|
105
|
+
const deferred = withResolvers();
|
|
106
|
+
slot[TaskIndex.FunctionID] = functionIDMasked;
|
|
107
|
+
if (USE_SIGNAL) {
|
|
108
|
+
const maybeSignal = abortSignals.getSignal();
|
|
109
|
+
if (maybeSignal === abortSignals.closeNow) {
|
|
110
|
+
return Promise.reject(AbortSignalPoolExhausted);
|
|
111
|
+
}
|
|
112
|
+
new OneShotDeferred(deferred, () => resetSignal(maybeSignal), () => {
|
|
113
|
+
abortSignals.setSignal(maybeSignal);
|
|
114
|
+
});
|
|
115
|
+
const encodedSignalMeta = ((maybeSignal + ABORT_SIGNAL_META_OFFSET) & FUNCTION_META_MASK) >>>
|
|
116
|
+
0;
|
|
117
|
+
slot[TaskIndex.FunctionID] =
|
|
118
|
+
((encodedSignalMeta << FUNCTION_META_SHIFT) | functionIDMasked) >>>
|
|
119
|
+
0;
|
|
120
|
+
}
|
|
121
|
+
slot.value = rawArgs;
|
|
122
|
+
slot[TaskIndex.ID] = index;
|
|
123
|
+
slot.resolve = deferred.resolve;
|
|
124
|
+
slot.reject = deferred.reject;
|
|
125
|
+
if (HAS_TIMER) {
|
|
126
|
+
slot[TaskIndex.slotBuffer] = ((slot[TaskIndex.slotBuffer] & SLOT_INDEX_MASK) |
|
|
127
|
+
((((nowTime() >>> 0) & SLOT_META_MASK) << SLOT_META_SHIFT) >>> 0)) >>> 0;
|
|
128
|
+
}
|
|
129
|
+
void publish(slot);
|
|
130
|
+
inUsed = (inUsed + 1) | 0;
|
|
131
|
+
return deferred.promise;
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
flushToWorker,
|
|
135
|
+
enqueueKnown,
|
|
136
|
+
settlePromisePayload: (task, isRejected, value) => {
|
|
137
|
+
if (task.reject === PLACE_HOLDER)
|
|
138
|
+
return false;
|
|
139
|
+
if (isRejected) {
|
|
140
|
+
try {
|
|
141
|
+
task.reject(value);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
}
|
|
145
|
+
resetTaskLocalFlags(task);
|
|
146
|
+
runTaskFinalizers(task);
|
|
147
|
+
task.value = null;
|
|
148
|
+
task.resolve = PLACE_HOLDER;
|
|
149
|
+
task.reject = PLACE_HOLDER;
|
|
150
|
+
inUsed = (inUsed - 1) | 0;
|
|
151
|
+
freePush(task[TaskIndex.ID]);
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
task.value = value;
|
|
155
|
+
return enqueueKnown(task);
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { withResolvers } from "../common/with-resolvers.js";
|
|
2
|
+
import { type SharedBufferSource } from "../common/shared-buffer-region.js";
|
|
3
|
+
export declare const AbortSignalPoolExhausted: unique symbol;
|
|
4
|
+
export declare const EnqueuedAbortSignal: unique symbol;
|
|
5
|
+
export type SignalAbortStore = ReturnType<typeof signalAbortFactory>;
|
|
6
|
+
export type SetSignalResult = -1 | 0 | 1;
|
|
7
|
+
export declare const signalAbortFactory: ({ sab, maxSignals, }: {
|
|
8
|
+
sab: SharedBufferSource;
|
|
9
|
+
maxSignals?: number;
|
|
10
|
+
}) => {
|
|
11
|
+
max: number;
|
|
12
|
+
closeNow: number;
|
|
13
|
+
getSignal: () => number;
|
|
14
|
+
setSignal: (signal: number) => SetSignalResult;
|
|
15
|
+
abortAll: () => number;
|
|
16
|
+
hasAborted: (signal: number) => boolean;
|
|
17
|
+
resetSignal: (signal: number) => boolean;
|
|
18
|
+
inUseCount: () => number;
|
|
19
|
+
};
|
|
20
|
+
export declare class OneShotDeferred<T> {
|
|
21
|
+
#private;
|
|
22
|
+
constructor(deferred: ReturnType<typeof withResolvers<T>>, onSettle: () => void, onEmptyReject?: () => void);
|
|
23
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { toSharedBufferRegion, } from "../common/shared-buffer-region.js";
|
|
2
|
+
const SLOT_BITS = 32;
|
|
3
|
+
const SLOT_MASK = SLOT_BITS - 1;
|
|
4
|
+
export const AbortSignalPoolExhausted = Symbol.for("knitting.abortSignal.poolExhausted");
|
|
5
|
+
export const EnqueuedAbortSignal = Symbol.for("knitting.abortSignal.enqueuedSignal");
|
|
6
|
+
export const signalAbortFactory = ({ sab, maxSignals, }) => {
|
|
7
|
+
const sabRegion = toSharedBufferRegion(sab);
|
|
8
|
+
const atomicView = new Uint32Array(sabRegion.sab, sabRegion.byteOffset, sabRegion.byteLength / Uint32Array.BYTES_PER_ELEMENT);
|
|
9
|
+
const size = atomicView.length;
|
|
10
|
+
const inUse = new Uint32Array(size);
|
|
11
|
+
const physicalMax = size * SLOT_BITS;
|
|
12
|
+
const max = (() => {
|
|
13
|
+
if (!Number.isFinite(maxSignals))
|
|
14
|
+
return physicalMax;
|
|
15
|
+
const parsed = Math.floor(maxSignals);
|
|
16
|
+
if (parsed <= 0)
|
|
17
|
+
return physicalMax;
|
|
18
|
+
return Math.min(parsed, physicalMax);
|
|
19
|
+
})();
|
|
20
|
+
const closeNow = max + 1;
|
|
21
|
+
let current = 0;
|
|
22
|
+
let cursor = 0;
|
|
23
|
+
const getSignal = () => {
|
|
24
|
+
if (current >= max)
|
|
25
|
+
return closeNow;
|
|
26
|
+
for (let step = 0; step < size; step++) {
|
|
27
|
+
const word = (cursor + step) % size;
|
|
28
|
+
const wordBase = word << 5;
|
|
29
|
+
const remaining = max - wordBase;
|
|
30
|
+
if (remaining <= 0)
|
|
31
|
+
continue;
|
|
32
|
+
const allowedMask = remaining >= SLOT_BITS
|
|
33
|
+
? 0xFFFFFFFF
|
|
34
|
+
: ((1 << remaining) - 1) >>> 0;
|
|
35
|
+
const freeBits = ((~inUse[word]) & allowedMask) >>> 0;
|
|
36
|
+
if (freeBits === 0)
|
|
37
|
+
continue;
|
|
38
|
+
const bit = (freeBits & -freeBits) >>> 0;
|
|
39
|
+
inUse[word] = (inUse[word] | bit) >>> 0;
|
|
40
|
+
current = (current + 1) | 0;
|
|
41
|
+
cursor = (word + 1) % size;
|
|
42
|
+
// Recycled slot must start in "not aborted" state.
|
|
43
|
+
Atomics.and(atomicView, word, ~bit);
|
|
44
|
+
const bitIndex = 31 - Math.clz32(bit);
|
|
45
|
+
return (word << 5) + bitIndex;
|
|
46
|
+
}
|
|
47
|
+
return closeNow;
|
|
48
|
+
};
|
|
49
|
+
const setSignal = (signal) => {
|
|
50
|
+
// 0 => sentinel "abort because pool/size is exhausted"
|
|
51
|
+
if (signal === closeNow)
|
|
52
|
+
return 0;
|
|
53
|
+
// -1 => invalid signal id
|
|
54
|
+
if (!Number.isInteger(signal))
|
|
55
|
+
return -1;
|
|
56
|
+
if (signal < 0 || signal >= max)
|
|
57
|
+
return -1;
|
|
58
|
+
// 1 => signal bit was set as aborted
|
|
59
|
+
const word = signal >>> 5;
|
|
60
|
+
const bit = 1 << (signal & SLOT_MASK);
|
|
61
|
+
Atomics.or(atomicView, word, bit);
|
|
62
|
+
return 1;
|
|
63
|
+
};
|
|
64
|
+
const abortAll = () => {
|
|
65
|
+
for (let word = 0; word < size; word++) {
|
|
66
|
+
Atomics.store(atomicView, word, inUse[word]);
|
|
67
|
+
}
|
|
68
|
+
return current;
|
|
69
|
+
};
|
|
70
|
+
const hasAborted = (signal) => {
|
|
71
|
+
if (signal === closeNow)
|
|
72
|
+
return true;
|
|
73
|
+
if (!Number.isInteger(signal))
|
|
74
|
+
return false;
|
|
75
|
+
if (signal < 0 || signal >= max)
|
|
76
|
+
return false;
|
|
77
|
+
const word = signal >>> 5;
|
|
78
|
+
const bit = 1 << (signal & SLOT_MASK);
|
|
79
|
+
return (Atomics.load(atomicView, word) & bit) !== 0;
|
|
80
|
+
};
|
|
81
|
+
const resetSignal = (signal) => {
|
|
82
|
+
if (signal === closeNow)
|
|
83
|
+
return false;
|
|
84
|
+
if (!Number.isInteger(signal))
|
|
85
|
+
return false;
|
|
86
|
+
if (signal < 0 || signal >= max)
|
|
87
|
+
return false;
|
|
88
|
+
const word = signal >>> 5;
|
|
89
|
+
const bit = 1 << (signal & SLOT_MASK);
|
|
90
|
+
const used = (inUse[word] & bit) !== 0;
|
|
91
|
+
if (!used)
|
|
92
|
+
return false;
|
|
93
|
+
inUse[word] = (inUse[word] & ~bit) >>> 0;
|
|
94
|
+
if (current > 0)
|
|
95
|
+
current = (current - 1) | 0;
|
|
96
|
+
cursor = word;
|
|
97
|
+
// Clear aborted flag for future reuse.
|
|
98
|
+
Atomics.and(atomicView, word, ~bit);
|
|
99
|
+
return true;
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
max,
|
|
103
|
+
closeNow,
|
|
104
|
+
getSignal,
|
|
105
|
+
setSignal,
|
|
106
|
+
abortAll,
|
|
107
|
+
hasAborted,
|
|
108
|
+
resetSignal,
|
|
109
|
+
inUseCount: () => current,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
export class OneShotDeferred {
|
|
113
|
+
#triggered = false;
|
|
114
|
+
constructor(deferred, onSettle, onEmptyReject) {
|
|
115
|
+
const settleOnce = (fn) => (...args) => {
|
|
116
|
+
if (this.#triggered)
|
|
117
|
+
return;
|
|
118
|
+
this.#triggered = true;
|
|
119
|
+
onSettle();
|
|
120
|
+
fn(...args);
|
|
121
|
+
};
|
|
122
|
+
deferred.resolve = settleOnce(deferred.resolve);
|
|
123
|
+
deferred.reject = settleOnce(deferred.reject);
|
|
124
|
+
deferred.promise.reject = (reason) => {
|
|
125
|
+
if (this.#triggered)
|
|
126
|
+
return;
|
|
127
|
+
if (reason === undefined && onEmptyReject !== undefined) {
|
|
128
|
+
onEmptyReject();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
deferred.reject(reason);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|