Skip to content
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

refactor vat dispatch() #2671

Closed
warner opened this issue Mar 17, 2021 · 0 comments
Closed

refactor vat dispatch() #2671

warner opened this issue Mar 17, 2021 · 0 comments
Assignees
Labels
enhancement New feature or request SwingSet package: SwingSet

Comments

@warner
Copy link
Member

warner commented Mar 17, 2021

What is the Problem Being Solved?

As preparation for the second half of #2660 , I want to refactor the way vat supervisors invoke the liveslots/comms/raw-vat dispatch object.

Originally, dispatch was defined to contain four methods: deliver (for message delivery), and notifyFulfillToPresence/notifyFulfillToData/notifyReject (for promise resolution). When @FUDCo cleaned up promise resolution (and we moved to batch resolutions), the last three were consolidated into a single notify method, leaving us with two: deliver and notify. #2653 makes that three: deliver, notify, dropExports.

Originally, vats were defined by a dispatch object with those methods, wrapped around a syscall object with a half-dozen or so methods (which have changed over time as well, and currently support: send, callNow, subscribe, resolve, exit, vatstoreGet, vatstoreSet, vatstoreDelete, and dropImports via #2635). The return value of the dispatch methods are mostly ignored: if it throws, or returns a Promise which rejects, we will log the error, but we don't treat that as evidence that the delivery failed. The vat dispatch is not considered "done" until the engine's promise queue is empty: the code which called dispatch methods would return a separate Promise that isn't resolved until a pre-prepared setImmediate callback runs. This ensures that the vat code (at this point, everything beyond dispatch) cannot retain agency after the kernel believes the crank to be done.

Then, when we moved from running all vats locally, to different "manager types" and the manger/supervisor split, we introduced the "VatDeliveryObject": a serializable short array containing a command to be sent to a vat. The kernel-side code finds the target vat's manager and invokes manager.deliver(vatDelivery), which is expected to return a Promise that fires with a vatDeliveryResult (just a two-element array, ['ok'] or ['error', message]). The manager does whatever local or remote interaction it needs to fulfill this contract.

On the worker side (which might be the same process as the kernel, a thread, or a child process), some workertype-specific supervisor code receives and reconstructs the VatDeliveryObject and figures out how to invoke the vat's dispatch method. This supervisor is responsible for waiting until the vat is quiescent. The supervisor is also where we look at the metering situation and decide whether the crank failed because it exceeded a limit of some sort.

To support #2660, I want to change dispatch to return a Promise, and have liveslots take on responsibility for waiting for the user-level vat code to become quiescent (it will need a waitUntilQuiescent endowment for that). Meter checks are still the responsibility of the supervisor (both because the xsnap supervisor is written in C and only C has access to the metering data, and because then any time spent in liveslots is still subject to metering).

I'm thinking that dispatch should also be changed to a function that accepts a vatDeliveryObject, instead of exposing three separate methods. This would reduce some of the parsing code in each supervisor, and remove some duplication in the code that implements those methods.

@warner warner added enhancement New feature or request SwingSet package: SwingSet labels Mar 17, 2021
@warner warner self-assigned this Mar 17, 2021
warner added a commit that referenced this issue Mar 18, 2021
Previously, the low-level vat interface was defined by a `dispatch` *object*,
with methods like `.deliver` and `.notify`. Now, it is defined by a
`dispatch()` *function*, which takes a `vatDeliveryObject` that has the exact
same form as the data sent in the kernel-vat protocol.

This reduces the size of the manager/supervisor code and reduces the
redundancy somewhat.

refs #2671
warner added a commit that referenced this issue Mar 19, 2021
Previously, the low-level vat interface was defined by a `dispatch` *object*,
with methods like `.deliver` and `.notify`. Now, it is defined by a
`dispatch()` *function*, which takes a `vatDeliveryObject` that has the exact
same form as the data sent in the kernel-vat protocol.

This reduces the size of the manager/supervisor code and reduces the
redundancy somewhat.

refs #2671
warner added a commit that referenced this issue Mar 21, 2021
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
warner added a commit that referenced this issue Mar 21, 2021
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
warner added a commit that referenced this issue Mar 22, 2021
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
warner added a commit that referenced this issue Mar 22, 2021
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
warner added a commit that referenced this issue Mar 22, 2021
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
warner added a commit that referenced this issue Mar 24, 2021
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
warner added a commit that referenced this issue Mar 24, 2021
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
warner added a commit that referenced this issue Apr 23, 2021
swingset: refactor dispatch()

refs #2671 , but doesn't close it yet (the other half is making `dispatch()` be `async`, and giving liveslots responsibility for deciding when the crank is finished)
This was referenced Apr 23, 2021
warner added a commit that referenced this issue Apr 26, 2021
`dispatch()`, the low-level interface to each vat (generally provided by
liveslots), is now async. Vats are responsible for not resolving the promise
returned by `dispatch()` until the user-level code has finished running and
the crank is complete. Vats are given `waitUntilQuiescent` in their `gcTools`
argument to facilitate this.

This will make it possible for liveslots to run `gc()` and wait long enough
to give finalizers a chance to run (and then call `dropImports`) before the
crank is considered complete.

closes #2671
refs #2660
@warner warner closed this as completed in 1a6ae48 Apr 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request SwingSet package: SwingSet
Projects
None yet
Development

No branches or pull requests

1 participant