@agoric/swingset-vat 0.33.0-u16.1 → 0.33.0-u17.0
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 +1 -1
- package/package.json +31 -30
- package/src/controller/controller.js +48 -1
- package/src/controller/initializeKernel.js +35 -10
- package/src/controller/initializeSwingset.js +6 -3
- package/src/controller/startXSnap.js +1 -1
- package/src/controller/upgradeSwingset.js +212 -0
- package/src/devices/bridge/device-bridge.js +1 -1
- package/src/devices/bundle/device-bundle.js +1 -1
- package/src/devices/command/command.js +1 -2
- package/src/devices/command/device-command.js +1 -2
- package/src/devices/lib/deviceTools.js +1 -1
- package/src/devices/loopbox/device-loopbox.js +1 -1
- package/src/devices/loopbox/loopbox.js +1 -1
- package/src/devices/mailbox/device-mailbox.js +1 -2
- package/src/devices/mailbox/mailbox.js +1 -2
- package/src/devices/plugin/device-plugin.js +1 -1
- package/src/devices/timer/device-timer.js +1 -1
- package/src/devices/timer/timer.js +1 -1
- package/src/devices/vat-admin/device-vat-admin.js +4 -2
- package/src/index.js +1 -1
- package/src/kernel/deviceManager.js +1 -1
- package/src/kernel/deviceSlots.js +1 -1
- package/src/kernel/deviceTranslator.js +1 -1
- package/src/kernel/dummyMeterControl.js +1 -1
- package/src/kernel/gc-actions.js +55 -34
- package/src/kernel/kernel.js +216 -51
- package/src/kernel/kernelSyscall.js +2 -13
- package/src/kernel/parseKernelSlots.js +1 -1
- package/src/kernel/slogger.js +2 -2
- package/src/kernel/state/deviceKeeper.js +1 -1
- package/src/kernel/state/kernelKeeper.js +427 -81
- package/src/kernel/state/reachable.js +1 -1
- package/src/kernel/state/stats.js +1 -1
- package/src/kernel/state/storageHelper.js +1 -1
- package/src/kernel/state/vatKeeper.js +159 -44
- package/src/kernel/vat-admin-hooks.js +4 -1
- package/src/kernel/vat-loader/manager-factory.js +1 -2
- package/src/kernel/vat-loader/manager-helper.js +1 -1
- package/src/kernel/vat-loader/manager-local.js +1 -1
- package/src/kernel/vat-loader/manager-subprocess-node.js +1 -1
- package/src/kernel/vat-loader/manager-subprocess-xsnap.js +1 -1
- package/src/kernel/vat-loader/vat-loader.js +2 -2
- package/src/kernel/vat-warehouse.js +5 -1
- package/src/kernel/vatTranslator.js +1 -4
- package/src/lib/assertOptions.js +1 -1
- package/src/lib/capdata.js +1 -1
- package/src/lib/id.js +1 -1
- package/src/lib/message.js +1 -1
- package/src/lib/parseVatSlots.js +1 -1
- package/src/lib/recordVatOptions.js +18 -6
- package/src/lib/runPolicies.js +50 -4
- package/src/lib/storageAPI.js +1 -1
- package/src/lib/workerOptions.js +1 -1
- package/src/supervisors/subprocess-node/supervisor-subprocess-node.js +1 -1
- package/src/types-external.js +71 -22
- package/src/types-internal.js +56 -3
- package/src/vats/comms/clist-inbound.js +1 -1
- package/src/vats/comms/clist-kernel.js +1 -1
- package/src/vats/comms/clist-outbound.js +1 -1
- package/src/vats/comms/controller.js +1 -1
- package/src/vats/comms/delivery.js +1 -1
- package/src/vats/comms/dispatch.js +1 -1
- package/src/vats/comms/gc-comms.js +1 -1
- package/src/vats/comms/parseLocalSlots.js +1 -1
- package/src/vats/comms/parseRemoteSlot.js +1 -1
- package/src/vats/comms/remote.js +1 -1
- package/src/vats/comms/state.js +1 -1
- package/src/vats/timer/vat-timer.js +9 -9
- package/src/vats/vat-admin/vat-vat-admin.js +23 -8
- package/src/vats/vattp/vat-vattp.js +1 -1
- package/tools/bootstrap-relay.js +1 -3
- package/tools/bundleTool.js +9 -1
- package/tools/dvo-test-harness.js +1 -1
- package/tools/manual-timer.js +1 -1
- package/tools/run-utils.js +1 -1
package/src/kernel/kernel.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/* global globalThis */
|
|
2
2
|
|
|
3
|
-
import { assert, Fail } from '@
|
|
3
|
+
import { assert, Fail } from '@endo/errors';
|
|
4
4
|
import { isNat } from '@endo/nat';
|
|
5
|
+
import { mustMatch, M } from '@endo/patterns';
|
|
5
6
|
import { importBundle } from '@endo/import-bundle';
|
|
7
|
+
import { objectMetaMap, PromiseAllOrErrors } from '@agoric/internal';
|
|
6
8
|
import { makeUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
|
|
7
9
|
import { kser, kslot, makeError } from '@agoric/kmarshal';
|
|
8
10
|
import { assertKnownOptions } from '../lib/assertOptions.js';
|
|
@@ -10,7 +12,9 @@ import { foreverPolicy } from '../lib/runPolicies.js';
|
|
|
10
12
|
import { makeVatManagerFactory } from './vat-loader/manager-factory.js';
|
|
11
13
|
import { makeVatWarehouse } from './vat-warehouse.js';
|
|
12
14
|
import makeDeviceManager from './deviceManager.js';
|
|
13
|
-
import makeKernelKeeper
|
|
15
|
+
import makeKernelKeeper, {
|
|
16
|
+
CURRENT_SCHEMA_VERSION,
|
|
17
|
+
} from './state/kernelKeeper.js';
|
|
14
18
|
import {
|
|
15
19
|
kdebug,
|
|
16
20
|
kdebugEnable,
|
|
@@ -36,6 +40,7 @@ import { notifyTermination } from './notifyTermination.js';
|
|
|
36
40
|
import { makeVatAdminHooks } from './vat-admin-hooks.js';
|
|
37
41
|
|
|
38
42
|
/** @import * as liveslots from '@agoric/swingset-liveslots' */
|
|
43
|
+
/** @import {PolicyInputCleanupCounts} from '../types-external.js' */
|
|
39
44
|
|
|
40
45
|
function abbreviateReplacer(_, arg) {
|
|
41
46
|
if (typeof arg === 'bigint') {
|
|
@@ -112,7 +117,11 @@ export default function buildKernel(
|
|
|
112
117
|
? makeSlogger(slogCallbacks, writeSlogObject)
|
|
113
118
|
: makeDummySlogger(slogCallbacks, makeConsole('disabled slogger'));
|
|
114
119
|
|
|
115
|
-
const kernelKeeper = makeKernelKeeper(
|
|
120
|
+
const kernelKeeper = makeKernelKeeper(
|
|
121
|
+
kernelStorage,
|
|
122
|
+
CURRENT_SCHEMA_VERSION,
|
|
123
|
+
kernelSlog,
|
|
124
|
+
);
|
|
116
125
|
|
|
117
126
|
/** @type {ReturnType<makeVatWarehouse>} */
|
|
118
127
|
let vatWarehouse;
|
|
@@ -252,9 +261,12 @@ export default function buildKernel(
|
|
|
252
261
|
*/
|
|
253
262
|
async function terminateVat(vatID, shouldReject, info) {
|
|
254
263
|
console.log(`kernel terminating vat ${vatID} (failure=${shouldReject})`);
|
|
255
|
-
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
256
|
-
const critical = vatKeeper.getOptions().critical;
|
|
257
264
|
insistCapData(info);
|
|
265
|
+
// Note that it's important for much of this work to happen within the
|
|
266
|
+
// synchronous prelude. For details, see
|
|
267
|
+
// https://github.com/Agoric/agoric-sdk/pull/10055#discussion_r1754918394
|
|
268
|
+
let critical = false;
|
|
269
|
+
const deferred = [];
|
|
258
270
|
// ISSUE: terminate stuff in its own crank like creation?
|
|
259
271
|
// TODO: if a static vat terminates, panic the kernel?
|
|
260
272
|
// TODO: guard against somebody telling vatAdmin to kill a vat twice
|
|
@@ -264,10 +276,22 @@ export default function buildKernel(
|
|
|
264
276
|
// check will report 'false'. That's fine, there's no state to
|
|
265
277
|
// clean up.
|
|
266
278
|
if (kernelKeeper.vatIsAlive(vatID)) {
|
|
279
|
+
// If there was no vat state, we can't make a vatKeeper to ask for
|
|
280
|
+
// options. For now, pretend the vat was non-critical. This will fail
|
|
281
|
+
// to panic the kernel for startVat failures in critical vats
|
|
282
|
+
// (#9157). The fix will add .critical to CrankResults, populated by a
|
|
283
|
+
// getOptions query in deliveryCrankResults() or copied from
|
|
284
|
+
// dynamicOptions in processCreateVat.
|
|
285
|
+
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
286
|
+
critical = vatKeeper.getOptions().critical;
|
|
287
|
+
|
|
267
288
|
// Reject all promises decided by the vat, making sure to capture the list
|
|
268
289
|
// of kpids before that data is deleted.
|
|
269
290
|
const deadPromises = [...kernelKeeper.enumeratePromisesByDecider(vatID)];
|
|
270
|
-
|
|
291
|
+
// remove vatID from the list of live vats, and mark for deletion
|
|
292
|
+
kernelKeeper.deleteVatID(vatID);
|
|
293
|
+
kernelKeeper.markVatAsTerminated(vatID);
|
|
294
|
+
deferred.push(kernelKeeper.removeVatFromSwingStoreExports(vatID));
|
|
271
295
|
for (const kpid of deadPromises) {
|
|
272
296
|
resolveToError(kpid, makeError('vat terminated'), vatID);
|
|
273
297
|
}
|
|
@@ -282,9 +306,7 @@ export default function buildKernel(
|
|
|
282
306
|
// it's going to be a small cost compared to the trouble you're probably
|
|
283
307
|
// already in anyway if this happens.
|
|
284
308
|
panic(`critical vat ${vatID} failed`, Error(info.body));
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
if (vatAdminRootKref) {
|
|
309
|
+
} else if (vatAdminRootKref) {
|
|
288
310
|
// static vat termination can happen before vat admin vat exists
|
|
289
311
|
notifyTermination(
|
|
290
312
|
vatID,
|
|
@@ -299,8 +321,11 @@ export default function buildKernel(
|
|
|
299
321
|
);
|
|
300
322
|
}
|
|
301
323
|
|
|
302
|
-
// worker needs to be stopped
|
|
303
|
-
|
|
324
|
+
// worker, if present, needs to be stopped
|
|
325
|
+
// (note that this only applies to ephemeral vats)
|
|
326
|
+
deferred.push(vatWarehouse.stopWorker(vatID));
|
|
327
|
+
|
|
328
|
+
await PromiseAllOrErrors(deferred);
|
|
304
329
|
}
|
|
305
330
|
|
|
306
331
|
function notifyMeterThreshold(meterID) {
|
|
@@ -357,6 +382,7 @@ export default function buildKernel(
|
|
|
357
382
|
*
|
|
358
383
|
* @typedef { import('@agoric/swingset-liveslots').MeterConsumption } MeterConsumption
|
|
359
384
|
* @typedef { import('../types-internal.js').MeterID } MeterID
|
|
385
|
+
* @typedef { import('../types-internal.js').Dirt } Dirt
|
|
360
386
|
*
|
|
361
387
|
* Any delivery crank (send, notify, start-vat.. anything which is allowed
|
|
362
388
|
* to make vat delivery) emits one of these status events if a delivery
|
|
@@ -369,13 +395,15 @@ export default function buildKernel(
|
|
|
369
395
|
* illegalSyscall: { vatID: VatID, info: SwingSetCapData } | undefined,
|
|
370
396
|
* vatRequestedTermination: { reject: boolean, info: SwingSetCapData } | undefined,
|
|
371
397
|
* } } DeliveryStatus
|
|
398
|
+
* @import {PolicyInputCleanupCounts} from '../types-external.js';
|
|
372
399
|
* @typedef { {
|
|
373
400
|
* abort?: boolean, // changes should be discarded, not committed
|
|
374
401
|
* consumeMessage?: boolean, // discard the aborted delivery
|
|
375
402
|
* didDelivery?: VatID, // we made a delivery to a vat, for run policy and save-snapshot
|
|
376
|
-
* computrons?:
|
|
403
|
+
* computrons?: bigint, // computron count for run policy
|
|
404
|
+
* cleanups?: PolicyInputCleanupCounts, // cleanup budget spent
|
|
377
405
|
* meterID?: string, // deduct those computrons from a meter
|
|
378
|
-
*
|
|
406
|
+
* measureDirt?: { vatID: VatID, dirt: Dirt }, // dirt counters should increment
|
|
379
407
|
* terminate?: { vatID: VatID, reject: boolean, info: SwingSetCapData }, // terminate vat, notify vat-admin
|
|
380
408
|
* vatAdminMethargs?: RawMethargs, // methargs to notify vat-admin about create/upgrade results
|
|
381
409
|
* } } CrankResults
|
|
@@ -442,16 +470,17 @@ export default function buildKernel(
|
|
|
442
470
|
* event handler.
|
|
443
471
|
*
|
|
444
472
|
* Two flags influence this:
|
|
445
|
-
* `
|
|
473
|
+
* `measureDirt` is used for non-BOYD deliveries
|
|
446
474
|
* `meterID` means we should check a meter
|
|
447
475
|
*
|
|
448
476
|
* @param {VatID} vatID
|
|
449
477
|
* @param {DeliveryStatus} status
|
|
450
|
-
* @param {boolean}
|
|
478
|
+
* @param {boolean} measureDirt
|
|
451
479
|
* @param {MeterID} [meterID]
|
|
480
|
+
* @param {number} [gcKrefs]
|
|
452
481
|
* @returns {CrankResults}
|
|
453
482
|
*/
|
|
454
|
-
function deliveryCrankResults(vatID, status,
|
|
483
|
+
function deliveryCrankResults(vatID, status, measureDirt, meterID, gcKrefs) {
|
|
455
484
|
let meterUnderrun = false;
|
|
456
485
|
let computrons;
|
|
457
486
|
if (status.metering?.compute) {
|
|
@@ -495,8 +524,16 @@ export default function buildKernel(
|
|
|
495
524
|
results.terminate = { vatID, ...status.vatRequestedTermination };
|
|
496
525
|
}
|
|
497
526
|
|
|
498
|
-
if (
|
|
499
|
-
|
|
527
|
+
if (measureDirt && !(results.abort || results.terminate)) {
|
|
528
|
+
const dirt = { deliveries: 1 };
|
|
529
|
+
if (computrons) {
|
|
530
|
+
// this is BigInt, but we use plain Number in Dirt records
|
|
531
|
+
dirt.computrons = Number(computrons);
|
|
532
|
+
}
|
|
533
|
+
if (gcKrefs) {
|
|
534
|
+
dirt.gcKrefs = gcKrefs;
|
|
535
|
+
}
|
|
536
|
+
results.measureDirt = { vatID, dirt };
|
|
500
537
|
}
|
|
501
538
|
|
|
502
539
|
// We leave results.consumeMessage up to the caller. Send failures
|
|
@@ -535,7 +572,8 @@ export default function buildKernel(
|
|
|
535
572
|
}
|
|
536
573
|
|
|
537
574
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
538
|
-
|
|
575
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
576
|
+
return deliveryCrankResults(vatID, status, true, meterID, gcKrefs);
|
|
539
577
|
}
|
|
540
578
|
|
|
541
579
|
/**
|
|
@@ -581,7 +619,8 @@ export default function buildKernel(
|
|
|
581
619
|
const vd = vatWarehouse.kernelDeliveryToVatDelivery(vatID, kd);
|
|
582
620
|
vatKeeper.deleteCListEntriesForKernelSlots(targets);
|
|
583
621
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
584
|
-
|
|
622
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
623
|
+
return deliveryCrankResults(vatID, status, true, meterID, gcKrefs);
|
|
585
624
|
}
|
|
586
625
|
|
|
587
626
|
/**
|
|
@@ -609,7 +648,9 @@ export default function buildKernel(
|
|
|
609
648
|
}
|
|
610
649
|
const vd = vatWarehouse.kernelDeliveryToVatDelivery(vatID, kd);
|
|
611
650
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
612
|
-
|
|
651
|
+
const meterID = undefined; // no meterID
|
|
652
|
+
const gcKrefs = krefs.length;
|
|
653
|
+
return deliveryCrankResults(vatID, status, true, meterID, gcKrefs);
|
|
613
654
|
}
|
|
614
655
|
|
|
615
656
|
/**
|
|
@@ -628,7 +669,50 @@ export default function buildKernel(
|
|
|
628
669
|
const kd = harden([type]);
|
|
629
670
|
const vd = vatWarehouse.kernelDeliveryToVatDelivery(vatID, kd);
|
|
630
671
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
631
|
-
|
|
672
|
+
// no gcKrefs, BOYD clears them anyways
|
|
673
|
+
return deliveryCrankResults(vatID, status, false); // no meter, BOYD clears dirt
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Perform a small (budget-limited) amount of dead-vat cleanup work.
|
|
678
|
+
*
|
|
679
|
+
* @param {RunQueueEventCleanupTerminatedVat} message
|
|
680
|
+
* 'message' is the run-queue cleanup action, which includes a
|
|
681
|
+
* vatID and budget. The budget contains work limits for each
|
|
682
|
+
* phase of cleanup (perhaps Infinity to allow unlimited
|
|
683
|
+
* work). Cleanup should not touch more than maybe 5*limit DB
|
|
684
|
+
* rows.
|
|
685
|
+
* @returns {Promise<CrankResults>}
|
|
686
|
+
*/
|
|
687
|
+
async function processCleanupTerminatedVat(message) {
|
|
688
|
+
const { vatID, budget } = message;
|
|
689
|
+
const { done, work } = kernelKeeper.cleanupAfterTerminatedVat(
|
|
690
|
+
vatID,
|
|
691
|
+
budget,
|
|
692
|
+
);
|
|
693
|
+
const zeroFreeWorkCounts = objectMetaMap(work, desc =>
|
|
694
|
+
desc.value ? desc : undefined,
|
|
695
|
+
);
|
|
696
|
+
kernelSlog.write({ type: 'vat-cleanup', vatID, work: zeroFreeWorkCounts });
|
|
697
|
+
|
|
698
|
+
/** @type {PolicyInputCleanupCounts} */
|
|
699
|
+
const cleanups = {
|
|
700
|
+
total:
|
|
701
|
+
work.exports +
|
|
702
|
+
work.imports +
|
|
703
|
+
work.kv +
|
|
704
|
+
work.snapshots +
|
|
705
|
+
work.transcripts,
|
|
706
|
+
...work,
|
|
707
|
+
};
|
|
708
|
+
if (done) {
|
|
709
|
+
kernelKeeper.forgetTerminatedVat(vatID);
|
|
710
|
+
kernelSlog.write({ type: 'vat-cleanup-complete', vatID });
|
|
711
|
+
}
|
|
712
|
+
// We don't perform any deliveries here, so there are no computrons to
|
|
713
|
+
// report, but we do tell the runPolicy know how much kernel-side DB
|
|
714
|
+
// work we did, so it can decide how much was too much.
|
|
715
|
+
return harden({ computrons: 0n, cleanups });
|
|
632
716
|
}
|
|
633
717
|
|
|
634
718
|
/**
|
|
@@ -669,8 +753,9 @@ export default function buildKernel(
|
|
|
669
753
|
const status = await deliverAndLogToVat(vatID, kd, vd);
|
|
670
754
|
// note: if deliveryCrankResults() learns to suspend vats,
|
|
671
755
|
// startVat errors should still terminate them
|
|
756
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
672
757
|
const results = harden({
|
|
673
|
-
...deliveryCrankResults(vatID, status, true, meterID),
|
|
758
|
+
...deliveryCrankResults(vatID, status, true, meterID, gcKrefs),
|
|
674
759
|
consumeMessage: true,
|
|
675
760
|
});
|
|
676
761
|
return results;
|
|
@@ -735,9 +820,17 @@ export default function buildKernel(
|
|
|
735
820
|
function setKernelVatOption(vatID, option, value) {
|
|
736
821
|
switch (option) {
|
|
737
822
|
case 'reapInterval': {
|
|
823
|
+
// This still controls reapDirtThreshold.deliveries, and we do not
|
|
824
|
+
// yet offer controls for the other limits (gcKrefs or computrons).
|
|
738
825
|
if (value === 'never' || isNat(value)) {
|
|
739
826
|
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
740
|
-
vatKeeper.
|
|
827
|
+
const threshold = { ...vatKeeper.getReapDirtThreshold() };
|
|
828
|
+
if (value === 'never') {
|
|
829
|
+
threshold.deliveries = value;
|
|
830
|
+
} else {
|
|
831
|
+
threshold.deliveries = Number(value);
|
|
832
|
+
}
|
|
833
|
+
vatKeeper.setReapDirtThreshold(threshold);
|
|
741
834
|
} else {
|
|
742
835
|
console.log(`WARNING: invalid reapInterval value`, value);
|
|
743
836
|
}
|
|
@@ -911,10 +1004,7 @@ export default function buildKernel(
|
|
|
911
1004
|
const abandonedObjects = [
|
|
912
1005
|
...kernelKeeper.enumerateNonDurableObjectExports(vatID),
|
|
913
1006
|
];
|
|
914
|
-
for (const { kref
|
|
915
|
-
/** @see translateAbandonExports in {@link ./vatTranslator.js} */
|
|
916
|
-
vatKeeper.deleteCListEntry(kref, vref);
|
|
917
|
-
/** @see abandonExports in {@link ./kernelSyscall.js} */
|
|
1007
|
+
for (const { kref } of abandonedObjects) {
|
|
918
1008
|
kernelKeeper.orphanKernelObject(kref, vatID);
|
|
919
1009
|
}
|
|
920
1010
|
|
|
@@ -951,7 +1041,14 @@ export default function buildKernel(
|
|
|
951
1041
|
startVatKD,
|
|
952
1042
|
startVatVD,
|
|
953
1043
|
);
|
|
954
|
-
const
|
|
1044
|
+
const gcKrefs = undefined; // TODO maybe increase by number of vrefs in args?
|
|
1045
|
+
const startVatResults = deliveryCrankResults(
|
|
1046
|
+
vatID,
|
|
1047
|
+
startVatStatus,
|
|
1048
|
+
true,
|
|
1049
|
+
meterID,
|
|
1050
|
+
gcKrefs,
|
|
1051
|
+
);
|
|
955
1052
|
computrons = addComputrons(computrons, startVatResults.computrons);
|
|
956
1053
|
|
|
957
1054
|
if (startVatResults.terminate) {
|
|
@@ -1125,6 +1222,7 @@ export default function buildKernel(
|
|
|
1125
1222
|
* @typedef { import('../types-internal.js').RunQueueEventRetireImports } RunQueueEventRetireImports
|
|
1126
1223
|
* @typedef { import('../types-internal.js').RunQueueEventNegatedGCAction } RunQueueEventNegatedGCAction
|
|
1127
1224
|
* @typedef { import('../types-internal.js').RunQueueEventBringOutYourDead } RunQueueEventBringOutYourDead
|
|
1225
|
+
* @typedef { import('../types-internal.js').RunQueueEventCleanupTerminatedVat } RunQueueEventCleanupTerminatedVat
|
|
1128
1226
|
* @typedef { import('../types-internal.js').RunQueueEvent } RunQueueEvent
|
|
1129
1227
|
*/
|
|
1130
1228
|
|
|
@@ -1192,6 +1290,8 @@ export default function buildKernel(
|
|
|
1192
1290
|
} else if (message.type === 'negated-gc-action') {
|
|
1193
1291
|
// processGCActionSet pruned some negated actions, but had no GC
|
|
1194
1292
|
// action to perform. Record the DB changes in their own crank.
|
|
1293
|
+
} else if (message.type === 'cleanup-terminated-vat') {
|
|
1294
|
+
deliverP = processCleanupTerminatedVat(message);
|
|
1195
1295
|
} else if (gcMessages.includes(message.type)) {
|
|
1196
1296
|
deliverP = processGCMessage(message);
|
|
1197
1297
|
} else {
|
|
@@ -1242,18 +1342,13 @@ export default function buildKernel(
|
|
|
1242
1342
|
const crankResults = await deliverRunQueueEvent(message);
|
|
1243
1343
|
// { abort/commit, deduct, terminate+notify, consumeMessage }
|
|
1244
1344
|
|
|
1245
|
-
if (
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
// which should not affect the in-consensus policyInput)
|
|
1253
|
-
policyInput = ['create-vat', {}];
|
|
1254
|
-
} else {
|
|
1255
|
-
policyInput = ['crank', {}];
|
|
1256
|
-
}
|
|
1345
|
+
if (message.type === 'cleanup-terminated-vat') {
|
|
1346
|
+
const { cleanups } = crankResults;
|
|
1347
|
+
assert(cleanups !== undefined);
|
|
1348
|
+
policyInput = ['cleanup', { cleanups }];
|
|
1349
|
+
} else if (crankResults.didDelivery) {
|
|
1350
|
+
const tag = message.type === 'create-vat' ? 'create-vat' : 'crank';
|
|
1351
|
+
policyInput = [tag, {}];
|
|
1257
1352
|
}
|
|
1258
1353
|
|
|
1259
1354
|
// Deliveries cause syscalls, syscalls might cause errors
|
|
@@ -1292,13 +1387,11 @@ export default function buildKernel(
|
|
|
1292
1387
|
}
|
|
1293
1388
|
}
|
|
1294
1389
|
}
|
|
1295
|
-
if (crankResults.
|
|
1390
|
+
if (crankResults.measureDirt) {
|
|
1296
1391
|
// deliveries cause garbage, garbage needs collection
|
|
1297
|
-
const { vatID } = crankResults.
|
|
1392
|
+
const { vatID, dirt } = crankResults.measureDirt;
|
|
1298
1393
|
const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
|
|
1299
|
-
|
|
1300
|
-
kernelKeeper.scheduleReap(vatID);
|
|
1301
|
-
}
|
|
1394
|
+
vatKeeper.addDirt(dirt); // might schedule a reap for that vat
|
|
1302
1395
|
}
|
|
1303
1396
|
|
|
1304
1397
|
// Vat termination (during delivery) is triggered by an illegal
|
|
@@ -1572,10 +1665,14 @@ export default function buildKernel(
|
|
|
1572
1665
|
'bundleID',
|
|
1573
1666
|
'enablePipelining',
|
|
1574
1667
|
'reapInterval',
|
|
1668
|
+
'reapGCKrefs',
|
|
1669
|
+
'neverReap',
|
|
1575
1670
|
]);
|
|
1576
1671
|
const {
|
|
1577
1672
|
bundleID = 'b1-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
1578
1673
|
reapInterval = 'never',
|
|
1674
|
+
reapGCKrefs = 'never',
|
|
1675
|
+
neverReap = false,
|
|
1579
1676
|
enablePipelining,
|
|
1580
1677
|
} = creationOptions;
|
|
1581
1678
|
const vatID = kernelKeeper.allocateVatIDForNameIfNeeded(name);
|
|
@@ -1587,6 +1684,8 @@ export default function buildKernel(
|
|
|
1587
1684
|
const options = {
|
|
1588
1685
|
name,
|
|
1589
1686
|
reapInterval,
|
|
1687
|
+
reapGCKrefs,
|
|
1688
|
+
neverReap,
|
|
1590
1689
|
enablePipelining,
|
|
1591
1690
|
managerType,
|
|
1592
1691
|
};
|
|
@@ -1617,7 +1716,6 @@ export default function buildKernel(
|
|
|
1617
1716
|
throw Error('kernel.start already called');
|
|
1618
1717
|
}
|
|
1619
1718
|
started = true;
|
|
1620
|
-
kernelKeeper.getInitialized() || Fail`kernel not initialized`;
|
|
1621
1719
|
|
|
1622
1720
|
kernelKeeper.loadStats();
|
|
1623
1721
|
|
|
@@ -1708,16 +1806,38 @@ export default function buildKernel(
|
|
|
1708
1806
|
}
|
|
1709
1807
|
}
|
|
1710
1808
|
|
|
1809
|
+
// match return value of runPolicy.allowCleanup, which is
|
|
1810
|
+
// PolicyOutputCleanupBudget | true | false
|
|
1811
|
+
const allowCleanupShape = M.or(
|
|
1812
|
+
// 'false' will prohibit cleanup
|
|
1813
|
+
false,
|
|
1814
|
+
// 'true' will allow unlimited cleanup
|
|
1815
|
+
true,
|
|
1816
|
+
// otherwise allow cleanup, optionally with a limiting budget
|
|
1817
|
+
M.splitRecord(
|
|
1818
|
+
{ default: M.number() },
|
|
1819
|
+
{
|
|
1820
|
+
exports: M.number(),
|
|
1821
|
+
imports: M.number(),
|
|
1822
|
+
kv: M.number(),
|
|
1823
|
+
snapshots: M.number(),
|
|
1824
|
+
transcripts: M.number(),
|
|
1825
|
+
},
|
|
1826
|
+
M.record(),
|
|
1827
|
+
),
|
|
1828
|
+
);
|
|
1829
|
+
|
|
1711
1830
|
/**
|
|
1712
1831
|
* Pulls the next message from the highest-priority queue and returns it
|
|
1713
1832
|
* along with a corresponding processor.
|
|
1714
1833
|
*
|
|
1834
|
+
* @param {RunPolicy} [policy] - a RunPolicy to limit the work being done
|
|
1715
1835
|
* @returns {{
|
|
1716
1836
|
* message: RunQueueEvent | undefined,
|
|
1717
1837
|
* processor: (message: RunQueueEvent) => Promise<PolicyInput>,
|
|
1718
1838
|
* }}
|
|
1719
1839
|
*/
|
|
1720
|
-
function getNextMessageAndProcessor() {
|
|
1840
|
+
function getNextMessageAndProcessor(policy) {
|
|
1721
1841
|
const acceptanceMessage = kernelKeeper.getNextAcceptanceQueueMsg();
|
|
1722
1842
|
if (acceptanceMessage) {
|
|
1723
1843
|
return {
|
|
@@ -1725,7 +1845,12 @@ export default function buildKernel(
|
|
|
1725
1845
|
processor: processAcceptanceMessage,
|
|
1726
1846
|
};
|
|
1727
1847
|
}
|
|
1848
|
+
// Absent specific configuration, allow unlimited cleanup.
|
|
1849
|
+
const allowCleanup = policy?.allowCleanup?.() ?? true;
|
|
1850
|
+
mustMatch(harden(allowCleanup), allowCleanupShape);
|
|
1851
|
+
|
|
1728
1852
|
const message =
|
|
1853
|
+
kernelKeeper.nextCleanupTerminatedVatAction(allowCleanup) ||
|
|
1729
1854
|
processGCActionSet(kernelKeeper) ||
|
|
1730
1855
|
kernelKeeper.nextReapAction() ||
|
|
1731
1856
|
kernelKeeper.getNextRunQueueMsg();
|
|
@@ -1733,14 +1858,36 @@ export default function buildKernel(
|
|
|
1733
1858
|
}
|
|
1734
1859
|
|
|
1735
1860
|
function changeKernelOptions(options) {
|
|
1736
|
-
assertKnownOptions(options, [
|
|
1861
|
+
assertKnownOptions(options, [
|
|
1862
|
+
'defaultReapInterval',
|
|
1863
|
+
'defaultReapGCKrefs',
|
|
1864
|
+
'snapshotInterval',
|
|
1865
|
+
]);
|
|
1737
1866
|
kernelKeeper.startCrank();
|
|
1738
1867
|
try {
|
|
1739
1868
|
for (const option of Object.getOwnPropertyNames(options)) {
|
|
1740
1869
|
const value = options[option];
|
|
1741
1870
|
switch (option) {
|
|
1742
1871
|
case 'defaultReapInterval': {
|
|
1743
|
-
|
|
1872
|
+
assert(
|
|
1873
|
+
(typeof value === 'number' && value > 0) || value === 'never',
|
|
1874
|
+
`defaultReapInterval ${value} must be a positive number or "never"`,
|
|
1875
|
+
);
|
|
1876
|
+
kernelKeeper.setDefaultReapDirtThreshold({
|
|
1877
|
+
...kernelKeeper.getDefaultReapDirtThreshold(),
|
|
1878
|
+
deliveries: value,
|
|
1879
|
+
});
|
|
1880
|
+
break;
|
|
1881
|
+
}
|
|
1882
|
+
case 'defaultReapGCKrefs': {
|
|
1883
|
+
assert(
|
|
1884
|
+
(typeof value === 'number' && value > 0) || value === 'never',
|
|
1885
|
+
`defaultReapGCKrefs ${value} must be a positive number or "never"`,
|
|
1886
|
+
);
|
|
1887
|
+
kernelKeeper.setDefaultReapDirtThreshold({
|
|
1888
|
+
...kernelKeeper.getDefaultReapDirtThreshold(),
|
|
1889
|
+
gcKrefs: value,
|
|
1890
|
+
});
|
|
1744
1891
|
break;
|
|
1745
1892
|
}
|
|
1746
1893
|
case 'snapshotInterval': {
|
|
@@ -1813,7 +1960,7 @@ export default function buildKernel(
|
|
|
1813
1960
|
kernelKeeper.startCrank();
|
|
1814
1961
|
try {
|
|
1815
1962
|
kernelKeeper.establishCrankSavepoint('start');
|
|
1816
|
-
const { processor, message } = getNextMessageAndProcessor();
|
|
1963
|
+
const { processor, message } = getNextMessageAndProcessor(policy);
|
|
1817
1964
|
if (!message) {
|
|
1818
1965
|
break;
|
|
1819
1966
|
}
|
|
@@ -1835,6 +1982,13 @@ export default function buildKernel(
|
|
|
1835
1982
|
case 'crank-failed':
|
|
1836
1983
|
policyOutput = policy.crankFailed(policyInput[1]);
|
|
1837
1984
|
break;
|
|
1985
|
+
case 'cleanup': {
|
|
1986
|
+
// Give the policy a chance to interrupt kernel execution,
|
|
1987
|
+
// but default to continuing.
|
|
1988
|
+
const { didCleanup } = policy;
|
|
1989
|
+
policyOutput = didCleanup ? didCleanup(policyInput[1]) : true;
|
|
1990
|
+
break;
|
|
1991
|
+
}
|
|
1838
1992
|
case 'none':
|
|
1839
1993
|
policyOutput = policy.emptyCrank();
|
|
1840
1994
|
break;
|
|
@@ -1944,6 +2098,16 @@ export default function buildKernel(
|
|
|
1944
2098
|
hooks[hookName] = hook;
|
|
1945
2099
|
}
|
|
1946
2100
|
|
|
2101
|
+
function terminateVatExternally(vatID, reasonCD) {
|
|
2102
|
+
assert(started, 'must do kernel.start() before terminateVatExternally()');
|
|
2103
|
+
insistCapData(reasonCD);
|
|
2104
|
+
assert(reasonCD.slots.length === 0, 'no slots allowed in reason');
|
|
2105
|
+
// this fires a promise when worker is dead, mostly for tests, so don't
|
|
2106
|
+
// give it to external callers
|
|
2107
|
+
void terminateVat(vatID, true, reasonCD);
|
|
2108
|
+
console.log(`scheduled vatID ${vatID} for termination`);
|
|
2109
|
+
}
|
|
2110
|
+
|
|
1947
2111
|
const kernel = harden({
|
|
1948
2112
|
// these are meant for the controller
|
|
1949
2113
|
installBundle,
|
|
@@ -2019,6 +2183,7 @@ export default function buildKernel(
|
|
|
2019
2183
|
kpStatus,
|
|
2020
2184
|
kpResolution,
|
|
2021
2185
|
addDeviceHook,
|
|
2186
|
+
terminateVatExternally,
|
|
2022
2187
|
});
|
|
2023
2188
|
|
|
2024
2189
|
return kernel;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assert, Fail } from '@
|
|
1
|
+
import { assert, Fail } from '@endo/errors';
|
|
2
2
|
import { insistKernelType } from './parseKernelSlots.js';
|
|
3
3
|
import { insistCapData } from '../lib/capdata.js';
|
|
4
4
|
import { insistDeviceID, insistVatID } from '../lib/id.js';
|
|
@@ -178,24 +178,13 @@ export function makeKernelSyscallHandler(tools) {
|
|
|
178
178
|
|
|
179
179
|
function retireExports(koids) {
|
|
180
180
|
Array.isArray(koids) || Fail`retireExports given non-Array ${koids}`;
|
|
181
|
-
|
|
182
|
-
for (const koid of koids) {
|
|
183
|
-
const importers = kernelKeeper.getImporters(koid);
|
|
184
|
-
for (const vatID of importers) {
|
|
185
|
-
newActions.push(`${vatID} retireImport ${koid}`);
|
|
186
|
-
}
|
|
187
|
-
// TODO: decref and delete any #2069 auxdata
|
|
188
|
-
kernelKeeper.deleteKernelObject(koid);
|
|
189
|
-
}
|
|
190
|
-
kernelKeeper.addGCActions(newActions);
|
|
181
|
+
kernelKeeper.retireKernelObjects(koids);
|
|
191
182
|
return OKNULL;
|
|
192
183
|
}
|
|
193
184
|
|
|
194
185
|
function abandonExports(vatID, koids) {
|
|
195
186
|
Array.isArray(koids) || Fail`abandonExports given non-Array ${koids}`;
|
|
196
187
|
for (const koid of koids) {
|
|
197
|
-
// note that this is effectful and also performed outside of a syscall
|
|
198
|
-
// by processUpgradeVat in {@link ./kernel.js}
|
|
199
188
|
kernelKeeper.orphanKernelObject(koid, vatID);
|
|
200
189
|
}
|
|
201
190
|
return OKNULL;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Nat } from '@endo/nat';
|
|
2
|
-
import { assert, Fail } from '@
|
|
2
|
+
import { assert, Fail } from '@endo/errors';
|
|
3
3
|
|
|
4
4
|
// Object/promise references (in the kernel) contain a two-tuple of (type,
|
|
5
5
|
// index). All object references point to entries in the kernel Object
|
package/src/kernel/slogger.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { q } from '@endo/errors';
|
|
2
2
|
|
|
3
3
|
const IDLE = 'idle';
|
|
4
4
|
const STARTUP = 'startup';
|
|
@@ -66,7 +66,7 @@ function makeCallbackRegistry(callbacks) {
|
|
|
66
66
|
if (!cbNames.length) {
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
|
-
console.warn(errorUnusedMsg, cbNames.map(
|
|
69
|
+
console.warn(errorUnusedMsg, cbNames.map(q).sort().join(', '));
|
|
70
70
|
},
|
|
71
71
|
});
|
|
72
72
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { Nat } from '@endo/nat';
|
|
6
|
-
import { assert, Fail } from '@
|
|
6
|
+
import { assert, Fail } from '@endo/errors';
|
|
7
7
|
import { parseKernelSlot } from '../parseKernelSlots.js';
|
|
8
8
|
import { makeVatSlot, parseVatSlot } from '../../lib/parseVatSlots.js';
|
|
9
9
|
import { insistDeviceID } from '../../lib/id.js';
|