generated from MetaMask/metamask-module-template
-
Notifications
You must be signed in to change notification settings - Fork 7
refactor(kernel): Isolate Kernel Queue, Syscall, Router & Translation Components #484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
4c376f0
move transls
sirtimid a7d5c17
restructure kernel
sirtimid d16c4d6
add comments
sirtimid 83078f0
fix test
sirtimid 9466327
move VatSyscall inside VatHandle
sirtimid 7594e59
split router as well
sirtimid f242512
add VatSyscall test
sirtimid f2cca64
add KernelRouter test
sirtimid eff4da0
add KernelQueue test and some more for types
sirtimid f7338d5
add tests for extractSingleRef
sirtimid 69d477d
Merge branch 'main' into sirtimid/kernel-restructure
sirtimid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| import type { VatOneResolution } from '@agoric/swingset-liveslots'; | ||
| import type { CapData } from '@endo/marshal'; | ||
| import { makePromiseKit } from '@endo/promise-kit'; | ||
|
|
||
| import { processGCActionSet } from './services/garbage-collection.ts'; | ||
| import type { KernelStore } from './store'; | ||
| import { insistVatId } from './types.ts'; | ||
| import type { KRef, RunQueueItem, RunQueueItemNotify, VatId } from './types.ts'; | ||
| import { Fail } from './utils/assert.ts'; | ||
|
|
||
| export class KernelQueue { | ||
| /** Storage holding the kernel's own persistent state */ | ||
| readonly #kernelStore: KernelStore; | ||
|
|
||
| /** Message results that the kernel itself has subscribed to */ | ||
| readonly subscriptions: Map<KRef, (value: CapData<KRef>) => void> = new Map(); | ||
|
|
||
| /** Thunk to signal run queue transition from empty to non-empty */ | ||
| #wakeUpTheRunQueue: (() => void) | null; | ||
|
|
||
| constructor(kernelStore: KernelStore) { | ||
| this.#kernelStore = kernelStore; | ||
| this.#wakeUpTheRunQueue = null; | ||
| } | ||
|
|
||
| /** | ||
| * The kernel's run loop: take an item off the run queue, deliver it, | ||
| * repeat. Note that this loops forever: the returned promise never resolves. | ||
| * | ||
| * @param deliver - A function that delivers an item to the kernel. | ||
| */ | ||
| async run(deliver: (item: RunQueueItem) => Promise<void>): Promise<void> { | ||
| for await (const item of this.#runQueueItems()) { | ||
| this.#kernelStore.nextTerminatedVatCleanup(); | ||
| await deliver(item); | ||
| this.#kernelStore.collectGarbage(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Async generator that yields the items from the kernel run queue, in order. | ||
| * | ||
| * @yields the next item in the run queue. | ||
| */ | ||
| async *#runQueueItems(): AsyncGenerator<RunQueueItem> { | ||
| for (;;) { | ||
| const gcAction = processGCActionSet(this.#kernelStore); | ||
| if (gcAction) { | ||
| yield gcAction; | ||
| continue; | ||
| } | ||
|
|
||
| const reapAction = this.#kernelStore.nextReapAction(); | ||
| if (reapAction) { | ||
| yield reapAction; | ||
| continue; | ||
| } | ||
|
|
||
| while (this.#kernelStore.runQueueLength() > 0) { | ||
| const item = this.#kernelStore.dequeueRun(); | ||
| if (item) { | ||
| yield item; | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (this.#kernelStore.runQueueLength() === 0) { | ||
| const { promise, resolve } = makePromiseKit<void>(); | ||
| if (this.#wakeUpTheRunQueue !== null) { | ||
| Fail`wakeUpTheRunQueue function already set`; | ||
| } | ||
| this.#wakeUpTheRunQueue = resolve; | ||
| await promise; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Add an item to the tail of the kernel's run queue. | ||
| * | ||
| * @param item - The item to add. | ||
| */ | ||
| enqueueRun(item: RunQueueItem): void { | ||
| this.#kernelStore.enqueueRun(item); | ||
| if (this.#kernelStore.runQueueLength() === 1 && this.#wakeUpTheRunQueue) { | ||
| const wakeUpTheRunQueue = this.#wakeUpTheRunQueue; | ||
| this.#wakeUpTheRunQueue = null; | ||
| wakeUpTheRunQueue(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Enqueue for delivery a notification to a vat about the resolution of a | ||
| * promise. | ||
| * | ||
| * @param vatId - The vat that will be notified. | ||
| * @param kpid - The promise of interest. | ||
| */ | ||
| enqueueNotify(vatId: VatId, kpid: KRef): void { | ||
| const notifyItem: RunQueueItemNotify = { type: 'notify', vatId, kpid }; | ||
| this.enqueueRun(notifyItem); | ||
| // Increment reference count for the promise being notified about | ||
| this.#kernelStore.incrementRefCount(kpid, 'notify'); | ||
| } | ||
|
|
||
| /** | ||
| * Process a set of promise resolutions coming from a vat. | ||
| * | ||
| * @param vatId - The vat doing the resolving, if there is one. | ||
| * @param resolutions - One or more resolutions, to be processed as a group. | ||
| */ | ||
| resolvePromises( | ||
| vatId: VatId | undefined, | ||
| resolutions: VatOneResolution[], | ||
| ): void { | ||
| if (vatId) { | ||
| insistVatId(vatId); | ||
| } | ||
| for (const resolution of resolutions) { | ||
| const [kpid, rejected, dataRaw] = resolution; | ||
| const data = dataRaw as CapData<KRef>; | ||
|
|
||
| this.#kernelStore.incrementRefCount(kpid, 'resolve|kpid'); | ||
| for (const slot of data.slots || []) { | ||
| this.#kernelStore.incrementRefCount(slot, 'resolve|slot'); | ||
| } | ||
|
|
||
| const promise = this.#kernelStore.getKernelPromise(kpid); | ||
| const { state, decider, subscribers } = promise; | ||
| if (state !== 'unresolved') { | ||
| Fail`${kpid} was already resolved`; | ||
| } | ||
| if (decider !== vatId) { | ||
| const why = decider ? `its decider is ${decider}` : `it has no decider`; | ||
| Fail`${vatId} not permitted to resolve ${kpid} because ${why}`; | ||
| } | ||
| if (!subscribers) { | ||
| throw Fail`${kpid} subscribers not set`; | ||
| } | ||
| for (const subscriber of subscribers) { | ||
| this.enqueueNotify(subscriber, kpid); | ||
| } | ||
| this.#kernelStore.resolveKernelPromise(kpid, rejected, data); | ||
| const kernelResolve = this.subscriptions.get(kpid); | ||
| if (kernelResolve) { | ||
| this.subscriptions.delete(kpid); | ||
| kernelResolve(data); | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are three
enqueueXXXmethods, butenqueueMessageandenqueueNotifyare specific whileenqueueRunis more generic (used both in the implementation of the other two and for general queue handling). So I'd suggest reordering them to putenqueueRunbefore of after the other two rather than in between them.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok yeah I'll do it later.