@metamask/ocap-kernel
Version:
OCap kernel core components
1 lines • 13.3 kB
Source Map (JSON)
{"version":3,"file":"KernelQueue.mjs","sourceRoot":"","sources":["../src/KernelQueue.ts"],"names":[],"mappings":"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","sourcesContent":["import type { VatOneResolution } from '@agoric/swingset-liveslots';\nimport type { CapData } from '@endo/marshal';\nimport { makePromiseKit } from '@endo/promise-kit';\n\nimport { processGCActionSet } from './services/garbage-collection.ts';\nimport { kser } from './services/kernel-marshal.ts';\nimport type { KernelStore } from './store/index.ts';\nimport { insistVatId } from './types.ts';\nimport type {\n CrankResults,\n KRef,\n Message,\n RunQueueItem,\n RunQueueItemNotify,\n RunQueueItemSend,\n VatId,\n} from './types.ts';\nimport { Fail } from './utils/assert.ts';\n\n/**\n * The kernel's run queue.\n *\n * This class manages the kernel's run queue, which is a queue of items that\n * need to be processed.\n */\nexport class KernelQueue {\n /** Storage holding the kernel's own persistent state */\n readonly #kernelStore: KernelStore;\n\n /** A function that terminates a vat. */\n readonly #terminateVat: (\n vatId: VatId,\n reason?: CapData<KRef>,\n ) => Promise<void>;\n\n /** Message results that the kernel itself has subscribed to */\n readonly subscriptions: Map<KRef, (value: CapData<KRef>) => void> = new Map();\n\n /** Thunk to signal run queue transition from empty to non-empty */\n #wakeUpTheRunQueue: (() => void) | null;\n\n constructor(\n kernelStore: KernelStore,\n terminateVat: (vatId: VatId, reason?: CapData<KRef>) => Promise<void>,\n ) {\n this.#kernelStore = kernelStore;\n this.#terminateVat = terminateVat;\n this.#wakeUpTheRunQueue = null;\n }\n\n /**\n * The kernel's run loop: take an item off the run queue, deliver it,\n * repeat. Note that this loops forever: the returned promise never resolves.\n *\n * @param deliver - A function that delivers an item to the kernel.\n */\n async run(\n deliver: (item: RunQueueItem) => Promise<CrankResults | undefined>,\n ): Promise<void> {\n for await (const item of this.#runQueueItems()) {\n this.#kernelStore.nextTerminatedVatCleanup();\n const crankResults = await deliver(item);\n if (crankResults?.abort) {\n // Rollback the kernel state to before the failed delivery attempt.\n // For active vats, this allows the message to be retried in a future crank.\n // For terminated vats, the message will just go splat.\n this.#kernelStore.rollbackCrank('start');\n // TODO: Currently all errors terminate the vat, but instead we could\n // restart it and terminate the vat only after a certain number of failed\n // retries. This is probably where we should implement the vat restart logic.\n }\n // Vat termination during delivery is triggered by an illegal syscall\n // or by syscall.exit().\n if (crankResults?.terminate) {\n const { vatId, info } = crankResults.terminate;\n await this.#terminateVat(vatId, info);\n }\n this.#kernelStore.collectGarbage();\n }\n }\n\n /**\n * Async generator that yields the items from the kernel run queue, in order.\n *\n * @yields the next item in the run queue.\n */\n async *#runQueueItems(): AsyncGenerator<RunQueueItem> {\n for (;;) {\n this.#kernelStore.startCrank();\n try {\n this.#kernelStore.createCrankSavepoint('start');\n const gcAction = processGCActionSet(this.#kernelStore);\n if (gcAction) {\n yield gcAction;\n continue;\n }\n\n const reapAction = this.#kernelStore.nextReapAction();\n if (reapAction) {\n yield reapAction;\n continue;\n }\n\n while (this.#kernelStore.runQueueLength() > 0) {\n const item = this.#kernelStore.dequeueRun();\n if (item) {\n yield item;\n } else {\n break;\n }\n }\n\n if (this.#kernelStore.runQueueLength() === 0) {\n const { promise, resolve } = makePromiseKit<void>();\n if (this.#wakeUpTheRunQueue !== null) {\n Fail`wakeUpTheRunQueue function already set`;\n }\n this.#wakeUpTheRunQueue = resolve;\n await promise;\n }\n } finally {\n this.#kernelStore.endCrank();\n }\n }\n }\n\n /**\n * Add an item to the tail of the kernel's run queue.\n *\n * @param item - The item to add.\n */\n #enqueueRun(item: RunQueueItem): void {\n this.#kernelStore.enqueueRun(item);\n if (this.#kernelStore.runQueueLength() === 1 && this.#wakeUpTheRunQueue) {\n const wakeUpTheRunQueue = this.#wakeUpTheRunQueue;\n this.#wakeUpTheRunQueue = null;\n wakeUpTheRunQueue();\n }\n }\n\n /**\n * Queue a message to be delivered from the kernel to an object in a vat.\n *\n * @param target - The object to which the message is directed.\n * @param method - The method to be invoked.\n * @param args - Message arguments.\n *\n * @returns a promise for the (CapData encoded) result of the message invocation.\n */\n async enqueueMessage(\n target: KRef,\n method: string,\n args: unknown[],\n ): Promise<CapData<KRef>> {\n const result = this.#kernelStore.initKernelPromise()[0];\n const { promise, resolve } = makePromiseKit<CapData<KRef>>();\n this.subscriptions.set(result, resolve);\n this.enqueueSend(target, {\n methargs: kser([method, args]),\n result,\n });\n return promise;\n }\n\n /**\n * Enqueue a send message to be delivered to a vat.\n *\n * @param target - The object to which the message is directed.\n * @param message - The message to be delivered.\n */\n enqueueSend(target: KRef, message: Message): void {\n this.#kernelStore.incrementRefCount(target, 'queue|target');\n if (message.result) {\n this.#kernelStore.incrementRefCount(message.result, 'queue|result');\n }\n for (const slot of message.methargs.slots || []) {\n this.#kernelStore.incrementRefCount(slot, 'queue|slot');\n }\n const queueItem: RunQueueItemSend = {\n type: 'send',\n target,\n message,\n };\n this.#enqueueRun(queueItem);\n }\n\n /**\n * Enqueue for delivery a notification to a vat about the resolution of a\n * promise.\n *\n * @param vatId - The vat that will be notified.\n * @param kpid - The promise of interest.\n */\n enqueueNotify(vatId: VatId, kpid: KRef): void {\n const notifyItem: RunQueueItemNotify = { type: 'notify', vatId, kpid };\n this.#enqueueRun(notifyItem);\n // Increment reference count for the promise being notified about\n this.#kernelStore.incrementRefCount(kpid, 'notify');\n }\n\n /**\n * Process a set of promise resolutions coming from a vat.\n *\n * @param vatId - The vat doing the resolving, if there is one.\n * @param resolutions - One or more resolutions, to be processed as a group.\n */\n resolvePromises(\n vatId: VatId | undefined,\n resolutions: VatOneResolution[],\n ): void {\n if (vatId) {\n insistVatId(vatId);\n }\n for (const resolution of resolutions) {\n const [kpid, rejected, dataRaw] = resolution;\n const data = dataRaw as CapData<KRef>;\n\n this.#kernelStore.incrementRefCount(kpid, 'resolve|kpid');\n for (const slot of data.slots || []) {\n this.#kernelStore.incrementRefCount(slot, 'resolve|slot');\n }\n\n const promise = this.#kernelStore.getKernelPromise(kpid);\n const { state, decider, subscribers } = promise;\n if (state !== 'unresolved') {\n Fail`${kpid} was already resolved`;\n }\n if (decider !== vatId) {\n const why = decider ? `its decider is ${decider}` : `it has no decider`;\n Fail`${vatId} not permitted to resolve ${kpid} because ${why}`;\n }\n if (!subscribers) {\n throw Fail`${kpid} subscribers not set`;\n }\n for (const subscriber of subscribers) {\n this.enqueueNotify(subscriber, kpid);\n }\n this.#kernelStore.resolveKernelPromise(kpid, rejected, data);\n const kernelResolve = this.subscriptions.get(kpid);\n if (kernelResolve) {\n this.subscriptions.delete(kpid);\n kernelResolve(data);\n }\n }\n }\n}\n"]}