knitting 0.1.60 → 0.1.62

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 (46) hide show
  1. package/BROWSER.md +134 -0
  2. package/README.md +94 -6
  3. package/knitting.browser.d.ts +6 -0
  4. package/knitting.browser.js +1 -0
  5. package/package.json +11 -2
  6. package/prebuilds/darwin-arm64-node-127/knitting_buffer_pointer.node +0 -0
  7. package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
  8. package/prebuilds/darwin-arm64-node-127/knitting_shm.node +0 -0
  9. package/prebuilds/darwin-arm64-node-137/knitting_buffer_pointer.node +0 -0
  10. package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
  11. package/prebuilds/darwin-arm64-node-137/knitting_shm.node +0 -0
  12. package/prebuilds/win32-x64/knitting_windows_shared_memory.dll +0 -0
  13. package/prebuilds/win32-x64-node-127/knitting_buffer_pointer.node +0 -0
  14. package/prebuilds/win32-x64-node-127/knitting_shared_memory.node +0 -0
  15. package/prebuilds/win32-x64-node-127/knitting_shm.node +0 -0
  16. package/prebuilds/win32-x64-node-137/knitting_buffer_pointer.node +0 -0
  17. package/prebuilds/win32-x64-node-137/knitting_shared_memory.node +0 -0
  18. package/prebuilds/win32-x64-node-137/knitting_shm.node +0 -0
  19. package/src/api.js +136 -25
  20. package/src/common/runtime.d.ts +2 -1
  21. package/src/common/runtime.js +8 -1
  22. package/src/common/task-source.d.ts +9 -0
  23. package/src/common/task-source.js +15 -0
  24. package/src/memory/lock.d.ts +37 -1
  25. package/src/memory/lock.js +262 -5
  26. package/src/memory/payloadCodec.js +2 -6
  27. package/src/memory/regionRegistry.d.ts +1 -3
  28. package/src/memory/regionRegistry.js +16 -14
  29. package/src/permission/protocol.js +5 -1
  30. package/src/runtime/dispatcher.d.ts +11 -8
  31. package/src/runtime/dispatcher.js +163 -21
  32. package/src/runtime/inline-executor.js +6 -1
  33. package/src/runtime/pool.d.ts +127 -4
  34. package/src/runtime/pool.js +262 -73
  35. package/src/runtime/process-worker.d.ts +24 -12
  36. package/src/runtime/process-worker.js +185 -115
  37. package/src/runtime/tx-queue.d.ts +17 -1
  38. package/src/runtime/tx-queue.js +120 -15
  39. package/src/runtime/worker-common.d.ts +13 -0
  40. package/src/runtime/worker-common.js +103 -0
  41. package/src/types.d.ts +75 -4
  42. package/src/worker/loop.js +34 -5
  43. package/src/worker/rx-queue.d.ts +11 -1
  44. package/src/worker/rx-queue.js +4 -1
  45. package/src/worker/timers.d.ts +8 -1
  46. package/src/worker/timers.js +20 -17
package/src/api.js CHANGED
@@ -1,15 +1,16 @@
1
1
  import { getCallerFilePath, getCallerHref, setModuleUrl, } from "./common/task-source.js";
2
2
  import { DEBUG_ENABLED, resolveDebugNamespaces } from "./debug/gate.js";
3
- import { genTaskID } from "./common/task-source.js";
3
+ import { genTaskID, stableTaskID } from "./common/task-source.js";
4
4
  import { toModuleUrl } from "./common/module-url.js";
5
5
  import { endpointSymbol } from "./common/task-symbol.js";
6
- import { spawnWorkerContext } from "./runtime/pool.js";
7
- import { ChannelHandler } from "./runtime/dispatcher.js";
8
- import { RUNTIME } from "./common/runtime.js";
6
+ import { createStealPoolBuffers, MAX_STEAL_CONSUMERS, spawnWorkerContext, } from "./runtime/pool.js";
7
+ import { ChannelHandler, hostDispatcherLoop } from "./runtime/dispatcher.js";
8
+ import { createSharedArrayBuffer, RUNTIME } from "./common/runtime.js";
9
9
  import { RUNTIME_IS_MAIN_THREAD, RUNTIME_POOL_DEPTH, RUNTIME_WORKER_DATA, } from "./common/worker-runtime.js";
10
10
  import { classifyProcessPermissionCompatibility, enforceProcessPermissionCompatibility, resolvePermissionProtocol, toRuntimePermissionFlags, } from "./permission/index.js";
11
11
  import { getNodeProcess } from "./common/node-compat.js";
12
- import { readProcessWorkerCommandPrefix, readProcessWorkerRuntime, } from "./runtime/process-worker.js";
12
+ import { readProcessSharedMemorySettings, readProcessWorkerNodeMajor, readProcessWorkerRuntime, } from "./runtime/process-worker.js";
13
+ import { TRANSPORT_SIGNAL_BYTES } from "./ipc/transport/shared-memory.js";
13
14
  import { inspectCompiledWorkerArtifact } from "./runtime/compiled-artifact.js";
14
15
  import { managerMethod } from "./runtime/balancer.js";
15
16
  import { createInlineExecutor } from "./runtime/inline-executor.js";
@@ -46,18 +47,6 @@ const readHostCwd = () => {
46
47
  }
47
48
  return undefined;
48
49
  };
49
- const readKnownProcessWorkerNodeMajor = (worker) => {
50
- if (RUNTIME !== "node")
51
- return undefined;
52
- if (readProcessWorkerCommandPrefix(worker) !== undefined)
53
- return undefined;
54
- const nodeProcess = getNodeProcess();
55
- if (nodeProcess?.env?.NODE_BINARY !== undefined)
56
- return undefined;
57
- const raw = nodeProcess?.versions?.node;
58
- const major = Number.parseInt(String(raw).split(".", 1)[0] ?? "", 10);
59
- return Number.isInteger(major) && major > 0 ? major : undefined;
60
- };
61
50
  const formatDebugList = (values, empty = "(none)") => values && values.length > 0 ? values.join(",") : empty;
62
51
  const MAX_FUNCTION_ID = 0xFFFF;
63
52
  const MAX_FUNCTION_COUNT = MAX_FUNCTION_ID + 1;
@@ -375,6 +364,21 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
375
364
  hostDebug?.log(`permission=${permissionProtocol?.mode ?? "off"} execArgv=${formatDebugList(execArgv)}`);
376
365
  const usesAbortSignal = listOfFunctions.some((fn) => fn.abortSignal !== undefined);
377
366
  const resolvedWorker = resolveWorkerSettings(worker, callerHref);
367
+ const dispatcherEnv = nodeProcess?.env?.KNITTING_DISPATCHER;
368
+ const stealEnvRaw = nodeProcess?.env?.KNITTING_STEAL?.trim().toLowerCase();
369
+ const stealEnv = stealEnvRaw === "1" || stealEnvRaw === "true"
370
+ ? true
371
+ : stealEnvRaw === "0" || stealEnvRaw === "false"
372
+ ? false
373
+ : undefined;
374
+ // Shared-submit stealing is the default for compatible multi-worker pools.
375
+ // An explicit option wins over the environment; compiled and inline
376
+ // transports retain their existing topology.
377
+ const dispatcherExplicitlySelected = host?.dispatcher !== undefined ||
378
+ dispatcherEnv === "serial-channel" || dispatcherEnv === "per-thread";
379
+ const stealDefaultCompatible = balancer === undefined &&
380
+ !dispatcherExplicitlySelected && (threads ?? 1) <= MAX_STEAL_CONSUMERS;
381
+ const stealRequested = host?.steal ?? stealEnv ?? stealDefaultCompatible;
378
382
  const usingCompiledWorker = resolvedWorker?.runtime === "compiled";
379
383
  if (resolvedWorker?.compiled !== undefined && !usingCompiledWorker) {
380
384
  throw new Error("worker.compiled requires worker.runtime to be compiled");
@@ -437,7 +441,7 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
437
441
  target: {
438
442
  runtime: processRuntime,
439
443
  nodeMajor: processRuntime === "node"
440
- ? readKnownProcessWorkerNodeMajor(resolvedWorker)
444
+ ? readProcessWorkerNodeMajor(resolvedWorker)
441
445
  : undefined,
442
446
  },
443
447
  }));
@@ -454,7 +458,6 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
454
458
  `(import { isMain } from "knitting") so only the main program starts ` +
455
459
  `the pool.`);
456
460
  }
457
- const dispatcherEnv = nodeProcess?.env?.KNITTING_DISPATCHER;
458
461
  const explicitDispatcher = host?.dispatcher ??
459
462
  (dispatcherEnv === "serial-channel" || dispatcherEnv === "per-thread"
460
463
  ? dispatcherEnv
@@ -470,10 +473,37 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
470
473
  return "serial-channel";
471
474
  })();
472
475
  const dispatcher = explicitDispatcher ?? autoDispatcher;
473
- const serialChannel = !usingCompiledWorker &&
476
+ // Work stealing: one shared submit region, private return lanes, one
477
+ // pool-global pending registry. It is the compatible multi-worker default;
478
+ // an explicit balancer/dispatcher keeps the private-lane topology unless
479
+ // stealing itself was explicitly requested.
480
+ const useSteal = stealRequested &&
481
+ !usingCompiledWorker &&
482
+ (threads ?? 1) > 1 &&
483
+ !usingInliner;
484
+ const stealBuffers = useSteal
485
+ ? createStealPoolBuffers({
486
+ threads: threads ?? 1,
487
+ payload,
488
+ regionLanes: host?.stealRegionLanes,
489
+ abortSignalCapacity,
490
+ usesAbortSignal,
491
+ processWorker: resolvedWorker?.runtime === "process"
492
+ ? {
493
+ signalBytes: TRANSPORT_SIGNAL_BYTES,
494
+ sharedMemory: readProcessSharedMemorySettings(resolvedWorker),
495
+ }
496
+ : undefined,
497
+ })
498
+ : undefined;
499
+ const serialChannel = !usingCompiledWorker && !useSteal &&
474
500
  dispatcher === "serial-channel";
501
+ // One serial-channel hop drives every lane check in turn, and it depends on
502
+ // the channel's delivery to do that: swapping in the cheaper `setImmediate`
503
+ // pump cost 25% throughput and tripled p99 here, where every other topology
504
+ // gained. See ChannelHandler's note.
475
505
  const serialDispatcherChannel = serialChannel
476
- ? new ChannelHandler()
506
+ ? new ChannelHandler("channel")
477
507
  : undefined;
478
508
  let workers = Array.from({
479
509
  length: threads ?? 1,
@@ -496,14 +526,85 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
496
526
  usesAbortSignal,
497
527
  permission: permissionProtocol,
498
528
  sharedChannelHandler: serialDispatcherChannel,
529
+ stealPool: stealBuffers === undefined ? undefined : {
530
+ submitBuffers: stealBuffers.submitBuffers,
531
+ returnBuffers: stealBuffers.returnBuffers[thread],
532
+ hostSubmitLock: stealBuffers.hostSubmitLock,
533
+ hostReturnLock: stealBuffers.hostReturnLocks[thread],
534
+ sharedQueue: stealBuffers.sharedQueue,
535
+ consumers: threads ?? 1,
536
+ consumerId: thread,
537
+ regionLanes: stealBuffers.regionLanes,
538
+ abortSignalSAB: stealBuffers.abortSignalSAB,
539
+ abortSignalMax: stealBuffers.abortSignalMax,
540
+ processMemory: stealBuffers.processMemory,
541
+ },
499
542
  }));
543
+ const stealChannel = useSteal ? new ChannelHandler() : undefined;
544
+ if (useSteal) {
545
+ const channel = stealChannel;
546
+ const queue = stealBuffers.sharedQueue;
547
+ // Wake exactly one worker per drain, round-robin. Stealing decouples the
548
+ // wake target from the assignment: if the woken worker is busy, any other
549
+ // idle endpoint claims the region instead. So this costs one notify per
550
+ // publish regardless of pool size, rather than one per lane.
551
+ let wakeCursor = 0;
552
+ const wakeOne = () => {
553
+ const lanes = workers.length;
554
+ if (lanes === 0)
555
+ return;
556
+ const lane = wakeCursor;
557
+ wakeCursor = wakeCursor + 1 < lanes ? wakeCursor + 1 : 0;
558
+ workers[lane].laneWake?.();
559
+ };
560
+ // The shared dispatcher drives one queue, so it needs signal words of its
561
+ // own rather than any single lane's; waking is delegated to `wakeOne`.
562
+ const signalWords = new Int32Array(createSharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT));
563
+ const { check } = hostDispatcherLoop({
564
+ signalBox: {
565
+ opView: signalWords.subarray(0, 1),
566
+ txStatus: signalWords.subarray(1, 2),
567
+ rxStatus: signalWords.subarray(2, 3),
568
+ },
569
+ queue,
570
+ channelHandler: channel,
571
+ dispatcherOptions: host,
572
+ notifySignal: wakeOne,
573
+ crossProcess: resolvedWorker?.runtime === "process",
574
+ });
575
+ channel.open(check);
576
+ workers.forEach((context) => {
577
+ context.bindSend(() => {
578
+ if (check.isRunning !== true) {
579
+ check.isRunning = true;
580
+ Promise.resolve().then(check);
581
+ }
582
+ wakeOne();
583
+ });
584
+ });
585
+ hostDebug?.log(`dispatcher=steal lanes=${workers.length} g=${stealBuffers.regionLanes}`);
586
+ }
500
587
  const sharedDispatcherChannel = serialDispatcherChannel;
501
588
  if (serialChannel) {
502
589
  const channel = serialDispatcherChannel;
503
590
  const checks = workers.map((context) => context.dispatcherCheck);
591
+ const laneIdle = workers.map((context) => context.txIdle);
504
592
  let serialScheduled = false;
505
593
  let serialInFlight = false;
506
594
  let serialRerun = false;
595
+ // Busy-lane set: a tick walks only the lanes that have work, not all of
596
+ // them. `active` is a dense list of lane indices; `isActive` keeps the
597
+ // membership test O(1). A lane joins on send() and leaves once its queue
598
+ // reports idle, so an N-worker pool with one busy lane costs one check per
599
+ // tick instead of N.
600
+ const active = [];
601
+ const isActive = new Uint8Array(checks.length);
602
+ const markActive = (lane) => {
603
+ if (isActive[lane] === 1)
604
+ return;
605
+ isActive[lane] = 1;
606
+ active.push(lane);
607
+ };
507
608
  const runSerialChecks = () => {
508
609
  if (serialInFlight) {
509
610
  serialRerun = true;
@@ -513,11 +614,19 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
513
614
  do {
514
615
  serialRerun = false;
515
616
  serialScheduled = false;
516
- for (let index = 0; index < checks.length; index++) {
517
- const check = checks[index];
617
+ // Walk backwards so dropping an idle lane is a swap-with-last pop.
618
+ for (let index = active.length - 1; index >= 0; index--) {
619
+ const lane = active[index];
620
+ const check = checks[lane];
518
621
  if (check.isRunning !== true)
519
622
  check.isRunning = true;
520
623
  check();
624
+ if (laneIdle[lane]()) {
625
+ isActive[lane] = 0;
626
+ const last = active.pop();
627
+ if (index < active.length)
628
+ active[index] = last;
629
+ }
521
630
  }
522
631
  } while (serialRerun);
523
632
  serialInFlight = false;
@@ -533,9 +642,10 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
533
642
  Promise.resolve().then(runSerialChecks);
534
643
  };
535
644
  channel.open(runSerialChecks);
536
- workers.forEach((context) => {
645
+ workers.forEach((context, lane) => {
537
646
  const wake = context.laneWake;
538
647
  context.bindSend(() => {
648
+ markActive(lane);
539
649
  scheduleSerialCheck();
540
650
  wake();
541
651
  });
@@ -580,6 +690,7 @@ export const createPool = ({ threads, debug, inliner, balancer, payload, unsafe,
580
690
  closePromise = Promise.allSettled(workers.map((context) => context.kills()))
581
691
  .then(() => {
582
692
  sharedDispatcherChannel?.close();
693
+ stealChannel?.close();
583
694
  });
584
695
  return closePromise;
585
696
  };
@@ -738,7 +849,7 @@ const buildTaskDefinitionFromCaller = (input, callerHref, at, imported = false)
738
849
  const importedFrom = new URL(callerHref).href;
739
850
  const out = ({
740
851
  ...input,
741
- id: genTaskID(),
852
+ id: stableTaskID(importedFrom, at),
742
853
  importedFrom,
743
854
  at,
744
855
  imported,
@@ -1,8 +1,9 @@
1
- type RuntimeName = "deno" | "bun" | "node" | "andromeda" | "unknown";
1
+ type RuntimeName = "deno" | "bun" | "node" | "andromeda" | "browser" | "unknown";
2
2
  export declare const IS_DENO: boolean;
3
3
  export declare const IS_BUN: boolean;
4
4
  export declare const IS_NODE: boolean;
5
5
  export declare const IS_ANDROMEDA: boolean;
6
+ export declare const IS_BROWSER: boolean;
6
7
  export declare const RUNTIME: RuntimeName;
7
8
  export declare const SET_IMMEDIATE: typeof setImmediate & ((cb: () => void) => void);
8
9
  export declare const HAS_SHARED_WASM_MEMORY: boolean;
@@ -7,6 +7,11 @@ export const IS_NODE = typeof nodeProcess?.versions?.node === "string";
7
7
  // Andromeda (Nova engine): no `node:` builtins or `WebAssembly`; detect via
8
8
  // its private bootstrap global.
9
9
  export const IS_ANDROMEDA = typeof globals.__andromeda__ !== "undefined";
10
+ // A page or a web worker: no `node:` builtins, but `Worker`, `MessageChannel`,
11
+ // and a cross-origin isolated `SharedArrayBuffer` are all the pool needs.
12
+ export const IS_BROWSER = !IS_DENO && !IS_BUN && !IS_NODE && !IS_ANDROMEDA &&
13
+ (typeof globals.document !== "undefined" ||
14
+ typeof globals.WorkerGlobalScope === "function");
10
15
  export const RUNTIME = (IS_DENO
11
16
  ? "deno"
12
17
  : IS_BUN
@@ -15,7 +20,9 @@ export const RUNTIME = (IS_DENO
15
20
  ? "node"
16
21
  : IS_ANDROMEDA
17
22
  ? "andromeda"
18
- : "unknown");
23
+ : IS_BROWSER
24
+ ? "browser"
25
+ : "unknown");
19
26
  // `WebAssembly` may be undeclared (not just undefined) on Andromeda, where a
20
27
  // bare reference throws; capture it through `globalThis` so access is safe.
21
28
  const WebAssemblyRef = globals.WebAssembly;
@@ -1,4 +1,13 @@
1
1
  export declare const genTaskID: () => number;
2
+ /**
3
+ * Identity of a task, stable across processes.
4
+ *
5
+ * `genTaskID` numbers tasks by the order their module happened to be evaluated,
6
+ * which host and worker do not share: the host imports in its own source order
7
+ * and the worker imports in task-name order. `(href, at)` is the same pair in
8
+ * both, because `at` counts `task()` calls within one module.
9
+ */
10
+ export declare const stableTaskID: (href: string, at: number) => number;
2
11
  export declare const setModuleUrl: (url: string | undefined) => void;
3
12
  export declare const getModuleUrlOverride: () => string | undefined;
4
13
  export declare const getCallerHref: (offset?: number) => string;
@@ -1,5 +1,20 @@
1
1
  import { toModuleUrl } from "./module-url.js";
2
2
  export const genTaskID = ((counter) => () => counter++)(0);
3
+ /**
4
+ * Identity of a task, stable across processes.
5
+ *
6
+ * `genTaskID` numbers tasks by the order their module happened to be evaluated,
7
+ * which host and worker do not share: the host imports in its own source order
8
+ * and the worker imports in task-name order. `(href, at)` is the same pair in
9
+ * both, because `at` counts `task()` calls within one module.
10
+ */
11
+ export const stableTaskID = (href, at) => {
12
+ let hash = 0x811c9dc5;
13
+ for (let index = 0; index < href.length; index++) {
14
+ hash = Math.imul(hash ^ href.charCodeAt(index), 0x01000193);
15
+ }
16
+ return (Math.imul(hash ^ at, 0x01000193) >>> 0);
17
+ };
3
18
  const INTERNAL_CALLER_HINTS = [
4
19
  "/src/common/task-source.ts",
5
20
  "/src/common/task-source.js",
@@ -159,6 +159,22 @@ export declare const HEADER_SLOT_STRIDE_BYTES: number;
159
159
  export declare const HEADER_TASK_LINE_U32: number;
160
160
  export declare const HEADER_STATIC_PAYLOAD_U32: number;
161
161
  export declare const HEADER_TASK_OFFSET_IN_SLOT_U32: number;
162
+ export declare const STEAL_ACK_SLOT_OFFSET_U32: number;
163
+ export declare const STEAL_WANT_SLOT_OFFSET_U32: number;
164
+ /**
165
+ * The payload allocator needs its own participant-owned ACK per consumer, since
166
+ * several workers can free payload slots from one shared allocator. No intent
167
+ * word: freeing needs no arbitration, a consumer only frees what it drained.
168
+ */
169
+ export declare const STEAL_PAYLOAD_ACK_SLOT_OFFSET_U32: number;
170
+ /**
171
+ * Host-owned liveness mask for stealing consumers. A dead claimant may leave
172
+ * its WANT word set forever; survivors ignore WANT from consumers whose bit is
173
+ * clear here. This preserves single-writer ownership of every WANT word.
174
+ */
175
+ export declare const STEAL_LIVE_SLOT_OFFSET_U32: number;
176
+ /** Host-owned arm word for the return-lock completion doorbell. */
177
+ export declare const DOORBELL_ARMED_SLOT_OFFSET_U32: number;
162
178
  export declare const HEADER_U32_LENGTH: number;
163
179
  export declare const HEADER_BYTE_LENGTH: number;
164
180
  export declare const makeTask: () => Task;
@@ -177,7 +193,12 @@ type ResolveHostOptions = {
177
193
  * - encode/decode are not re-entrant; payload codec uses a shared scratch buffer.
178
194
  */
179
195
  export type Lock2 = ReturnType<typeof lock2>;
180
- export declare const lock2: ({ headers, headerSlotStrideU32, LockBoundSector, payload, payloadConfig, payloadSector, textCompat, resultList, toSentList, recycleList, processBoundary, }: {
196
+ export type WaitAsyncState = "not-equal" | "ok" | "timed-out";
197
+ export type WaitAsyncResult = {
198
+ async: boolean;
199
+ value: WaitAsyncState | PromiseLike<WaitAsyncState>;
200
+ };
201
+ export declare const lock2: ({ headers, headerSlotStrideU32, LockBoundSector, payload, payloadConfig, payloadSector, textCompat, resultList, toSentList, recycleList, processBoundary, consumers, consumerId, regionLanes, notifyOnHostPublish, }: {
181
202
  headers?: SharedBufferSource;
182
203
  headerSlotStrideU32?: number;
183
204
  LockBoundSector?: SharedBufferSource;
@@ -189,6 +210,18 @@ export declare const lock2: ({ headers, headerSlotStrideU32, LockBoundSector, pa
189
210
  resultList?: RingQueue<Task>;
190
211
  recycleList?: RingQueue<Task>;
191
212
  processBoundary?: boolean;
213
+ /**
214
+ * Number of consumer endpoints sharing this lock. `1` (default) keeps the
215
+ * classic single-consumer path. `> 1` enables region-Dekker work stealing and
216
+ * is only valid on a host->worker submit lock, never on a return lock.
217
+ */
218
+ consumers?: number;
219
+ /** This endpoint's id, `0..consumers-1`. Priority is fixed by id. */
220
+ consumerId?: number;
221
+ /** Lanes claimed per Dekker handshake. Paper rule: `slots / regionLanes >= consumers + 1`. */
222
+ regionLanes?: number;
223
+ /** Notify a host-side wait after this endpoint publishes a frame. */
224
+ notifyOnHostPublish?: boolean;
192
225
  }) => {
193
226
  enlist: (task: Task) => true;
194
227
  encode: (task: Task, state?: number) => boolean;
@@ -203,10 +236,13 @@ export declare const lock2: ({ headers, headerSlotStrideU32, LockBoundSector, pa
203
236
  workerBits: Int32Array<import("../common/shared-buffer-region.js").SharedBuffer>;
204
237
  recyclecList: RingQueue<Task>;
205
238
  resolveHost: ({ queue, onResolved, shouldSettle, activeRejectPlaceholder, }: ResolveHostOptions) => () => number;
239
+ waitForHostChange: (timeoutMs?: number) => WaitAsyncResult | undefined;
240
+ setHostWaiterArmed: (armed: boolean) => void;
206
241
  hasPendingFrames: () => boolean;
207
242
  getPendingFrameCount: () => number;
208
243
  getPendingPromiseCount: () => number;
209
244
  resetPendingState: () => void;
245
+ deactivateStealConsumer: (id: number) => boolean;
210
246
  takeDeferredCount: () => number;
211
247
  setPromiseHandler: (handler?: PromisePayloadHandler) => void;
212
248
  };