diff --git a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js index 58daecb43e4..adfd6fa814b 100644 --- a/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js +++ b/packages/SwingSet/src/kernel/vatManager/manager-subprocess-xsnap.js @@ -8,6 +8,11 @@ function parentLog(first, ...args) { console.error(`--parent: ${first}`, ...args); } +const trace = label => x => { + parentLog(label, x); + return x; +}; + const encoder = new TextEncoder(); const decoder = new TextDecoder(); @@ -25,7 +30,7 @@ const decoder = new TextDecoder(); * @typedef { ReturnType } XSnap * @typedef { ReturnType } KernelKeeper * @typedef { ReturnType } VatManagerFactory - * @typedef { [string, ...unknown[]] } Tagged + * @typedef { [unknown, ...unknown[]] } Tagged */ export function makeXsSubprocessFactory({ startXSnap, @@ -39,7 +44,7 @@ export function makeXsSubprocessFactory({ * @param { ManagerOptions } managerOptions */ async function createFromBundle(vatID, bundle, managerOptions) { - console.log('@@createFromBundle', { vatID, managerOptions: { ...managerOptions, bundle: '' } }); + parentLog('createFromBundle', { vatID }); const { vatParameters, virtualObjectCacheSize } = managerOptions; assert(!managerOptions.metered, 'not supported yet'); assert(!managerOptions.enableSetup, 'not supported at all'); @@ -60,9 +65,10 @@ export function makeXsSubprocessFactory({ transcriptManager, ); - /** @type { (vatSyscallObject: Tagged) => Tagged } */ + //@@??? should this return Tagged? + /** @type { (vatSyscallObject: Tagged) => unknown } */ function handleSyscall(vatSyscallObject) { - return doSyscall(vatSyscallObject); + return trace('doSyscall')(doSyscall(vatSyscallObject)); } /** @type { (vref: unknown, count: number) => void } */ @@ -70,14 +76,13 @@ export function makeXsSubprocessFactory({ decref(vatID, vref, count); } - /** @type { (item: Tagged) => Tagged } */ + /** @type { (item: Tagged) => unknown } */ function handleUpstream([type, ...args]) { parentLog(`handleUpstream`, type, args.length); switch (type) { case 'syscall': { parentLog(`syscall`, args); const [scTag, ...vatSyscallArgs] = args; - assert(typeof scTag === 'string'); return handleSyscall([scTag, ...vatSyscallArgs]); } case 'testLog': @@ -90,47 +95,38 @@ export function makeXsSubprocessFactory({ return ['OK']; } default: - parentLog(`unrecognized uplink message ${type}`); - return ['?']; + throw new Error(`unrecognized uplink message ${type}`); } } /** @type { (msg: Uint8Array) => Uint8Array } */ function handleCommand(msg) { - console.log('handleCommand', { length: msg.byteLength }); + parentLog('handleCommand', { length: msg.byteLength }); const tagged = handleUpstream(JSON.parse(decoder.decode(msg))); return encoder.encode(JSON.stringify(tagged)); } - console.log('@@do we return from startXSnap?'); // start the worker and establish a connection const { worker, bundles } = startXSnap(`${vatID}`, handleCommand); - console.log('@@YES, we return from startXSnap.'); - await worker.evaluate('1+1'); //@@ - console.log('and evaluate() finishes @@'); - console.log('@@bundle keys', Object.keys(bundles.lockdown)); for await (const [it, superCode] of Object.entries(bundles)) { + parentLog('bundle', it); assert( superCode.moduleFormat === 'getExport', details`${it} unexpected: ${superCode.moduleFormat}`, ); - console.log('@@evaluating...', it); - const x = await worker.evaluate( + await worker.evaluate( `(${superCode.source} )()`.trim(), ); - console.log('@@evaluated.', it, x); } /** @type { (item: Tagged) => Promise } */ async function issueTagged(item) { - console.log('@@issueTagged', item[0]); + parentLog('issueTagged', item[0]); const txt = await worker.issueStringCommand(JSON.stringify(item)); const reply = JSON.parse(txt); - console.log('@@reply', Array.isArray(reply), reply[0]); assert(Array.isArray(reply)); const [tag, ...rest] = reply; - assert(typeof tag === 'string'); return [tag, ...rest]; } @@ -160,7 +156,6 @@ export function makeXsSubprocessFactory({ /** @type { (item: Tagged) => Promise } */ async function deliver(delivery) { parentLog(`sending delivery`, delivery); - // ensure return tag is 'deliverDone'? const result = await commandResult(['deliver', ...delivery]); parentLog(`deliverDone`, result[0], result.length); return result; @@ -189,7 +184,7 @@ export function makeXsSubprocessFactory({ shutdown, }); - console.log('@@returning manager', Object.keys(manager)); + parentLog('manager', Object.keys(manager)); return manager; } diff --git a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js index 94f396dae7d..1e825db5ae6 100644 --- a/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js +++ b/packages/SwingSet/src/kernel/vatManager/supervisor-subprocess-xsnap.js @@ -2,18 +2,30 @@ import { assert, details } from '@agoric/assert'; import { importBundle } from '@agoric/import-bundle'; import { Remotable, getInterfaceOf, makeMarshal } from '@agoric/marshal'; +// grumble... waitUntilQuiescent is exported and closes over ambient authority +import { waitUntilQuiescent } from '../../waitUntilQuiescent'; import { makeLiveSlots } from '../liveSlots'; const encoder = new TextEncoder(); const decoder = new TextDecoder(); +// eslint-disable-next-line no-unused-vars +function workerLog(first, ...args) { + // @ts-ignore + // eslint-disable-next-line + print(`---worker: ${first}`, ...args); +} + +workerLog(`supervisor started`); + /** * @typedef { [unknown, ...unknown[]] } Tagged */ const Item = { /** @type { (item: Tagged) => ArrayBuffer } */ encode: tagged => encoder.encode(JSON.stringify(tagged)).buffer, + /** @type { (msg: ArrayBuffer) => Tagged } */ decode(msg) { const txt = decoder.decode(msg); @@ -44,26 +56,36 @@ function testLog(...args) { issueCommand(Item.encode(['testLog', ...args])); } -// eslint-disable-next-line no-unused-vars -function workerLog(first, ...args) { - testLog(`---worker: ${first}`, ...args); +/** + * @param { (value: void) => void } f + * @param { string } errmsg + */ +function runAndWait(f, errmsg) { + Promise.resolve() + .then(f) + .then(undefined, err => workerLog(`doProcess: ${errmsg}:`, err)); + return waitUntilQuiescent(); } -workerLog(`supervisor started`); - function makeWorker() { - let dispatch; + /** @type { Record void> | null } */ + let dispatch = null; + /** @type { (dr: Tagged, errmsg: string) => Promise } */ async function doProcess(dispatchRecord, errmsg) { - const dispatchOp = dispatchRecord[0]; - const dispatchArgs = dispatchRecord.slice(1); + assert(dispatch); + const theDispatch = dispatch; + const [dispatchOp, ...dispatchArgs] = dispatchRecord; + assert(typeof dispatchOp === 'string'); workerLog(`runAndWait`); - await runAndWait(() => dispatch[dispatchOp](...dispatchArgs), errmsg); + await runAndWait(() => theDispatch[dispatchOp](...dispatchArgs), errmsg); workerLog(`doProcess done`); + /** @type { Tagged } */ const vatDeliveryResults = harden(['ok']); return vatDeliveryResults; } + /** @type { (ts: unknown, msg: any) => Promise } */ function doMessage(targetSlot, msg) { const errmsg = `vat[${targetSlot}].${msg.method} dispatch failed`; return doProcess( @@ -72,6 +94,7 @@ function makeWorker() { ); } + /** @type { (pv: unknown, msg: any) => Promise } */ function doNotify(primaryVpid, resolutions) { const errmsg = `vat.promise[${primaryVpid}] failed`; return doProcess(['notify', primaryVpid, resolutions], errmsg); @@ -90,12 +113,15 @@ function makeWorker() { vatParameters, virtualObjectCacheSize, ) { - /** @type { (item: Tagged) => Tagged } */ + //@@??? should this return Tagged? + /** @type { (item: Tagged) => unknown } */ function doSyscall(vatSyscallObject) { - return Item.decode( - // @ts-ignore - // eslint-disable-next-line no-undef - issueCommand(Item.encode(['syscall', ...vatSyscallObject])), + return JSON.parse( + decoder.decode( + // @ts-ignore + // eslint-disable-next-line no-undef + issueCommand(Item.encode(['syscall', ...vatSyscallObject])), + ), ); } @@ -137,6 +163,7 @@ function makeWorker() { workerLog(`got vatNS:`, Object.keys(vatNS).join(',')); ls.setBuildRootObject(vatNS.buildRootObject); dispatch = ls.dispatch; + assert(dispatch); workerLog(`got dispatch:`, Object.keys(dispatch).join(',')); return ['dispatchReady']; } @@ -152,11 +179,11 @@ function makeWorker() { const [dtype, ...dargs] = args; switch (dtype) { case 'message': { - const res = await doMessage(...dargs); + const res = await doMessage(dargs[0], dargs[1]); return ['deliverDone', ...res]; } case 'notify': { - const res = await doNotify(...dargs); + const res = await doNotify(dargs[0], dargs[1]); return ['deliverDone', ...res]; } default: diff --git a/packages/SwingSet/test/workers/test-worker.js b/packages/SwingSet/test/workers/test-worker.js index d92a613caa0..a1c4a09d3a7 100644 --- a/packages/SwingSet/test/workers/test-worker.js +++ b/packages/SwingSet/test/workers/test-worker.js @@ -8,14 +8,12 @@ test('xs vat manager', async t => { const c = await buildVatController(config, []); t.teardown(c.shutdown); - console.log('@@ready to run...'); await c.run(); t.is(c.kpStatus(c.bootstrapResult), 'fulfilled'); t.deepEqual(c.dump().log, ['testLog works']); }); -// @@ SKIP? -test.skip('nodeWorker vat manager', async t => { +test('nodeWorker vat manager', async t => { const config = await loadBasedir(__dirname); config.vats.target.creationOptions = { managerType: 'nodeWorker' }; const c = await buildVatController(config, []); @@ -26,8 +24,7 @@ test.skip('nodeWorker vat manager', async t => { t.deepEqual(c.dump().log, ['testLog works']); }); -// @@ SKIP? -test.skip('node-subprocess vat manager', async t => { +test('node-subprocess vat manager', async t => { const config = await loadBasedir(__dirname); config.vats.target.creationOptions = { managerType: 'node-subprocess' }; const c = await buildVatController(config, []);