From 72650bcf7283c7b9eb9df9154f981eabdf8c523a Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 25 Aug 2019 21:48:58 +0200 Subject: worker: make transfer list behave like web MessagePort Allow generic iterables as transfer list arguments, as well as an options object with a `transfer` option, for web compatibility. PR-URL: https://github.com/nodejs/node/pull/29319 Refs: https://github.com/nodejs/node/pull/28033#discussion_r289964991 Reviewed-By: James M Snell --- ...-worker-message-port-terminate-transfer-list.js | 26 +++++++++ test/parallel/test-worker-message-port.js | 63 +++++++++++++++++++++- 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-worker-message-port-terminate-transfer-list.js (limited to 'test') diff --git a/test/parallel/test-worker-message-port-terminate-transfer-list.js b/test/parallel/test-worker-message-port-terminate-transfer-list.js new file mode 100644 index 0000000000..a066405d9d --- /dev/null +++ b/test/parallel/test-worker-message-port-terminate-transfer-list.js @@ -0,0 +1,26 @@ +'use strict'; +const common = require('../common'); + +const { parentPort, MessageChannel, Worker } = require('worker_threads'); + +// Do not use isMainThread so that this test itself can be run inside a Worker. +if (!process.env.HAS_STARTED_WORKER) { + process.env.HAS_STARTED_WORKER = 1; + const w = new Worker(__filename); + w.once('message', common.mustCall(() => { + w.once('message', common.mustNotCall()); + setTimeout(() => w.terminate(), 100); + })); +} else { + const { port1 } = new MessageChannel(); + + parentPort.postMessage('ready'); + + // Make sure we don’t end up running JS after the infinite loop is broken. + port1.postMessage({}, { + transfer: (function*() { while (true); })() + }); + + parentPort.postMessage('UNREACHABLE'); + process.kill(process.pid, 'SIGINT'); +} diff --git a/test/parallel/test-worker-message-port.js b/test/parallel/test-worker-message-port.js index d1c58216fd..d128dc7edb 100644 --- a/test/parallel/test-worker-message-port.js +++ b/test/parallel/test-worker-message-port.js @@ -72,22 +72,81 @@ const { MessageChannel, MessagePort } = require('worker_threads'); { const { port1, port2 } = new MessageChannel(); - port2.on('message', common.mustCall(4)); + port2.on('message', common.mustCall(6)); port1.postMessage(1, null); port1.postMessage(2, undefined); port1.postMessage(3, []); port1.postMessage(4, {}); + port1.postMessage(5, { transfer: undefined }); + port1.postMessage(6, { transfer: [] }); const err = { constructor: TypeError, code: 'ERR_INVALID_ARG_TYPE', - message: 'Optional transferList argument must be an array' + message: 'Optional transferList argument must be an iterable' }; assert.throws(() => port1.postMessage(5, 0), err); assert.throws(() => port1.postMessage(5, false), err); assert.throws(() => port1.postMessage(5, 'X'), err); assert.throws(() => port1.postMessage(5, Symbol('X')), err); + + const err2 = { + constructor: TypeError, + code: 'ERR_INVALID_ARG_TYPE', + message: 'Optional options.transfer argument must be an iterable' + }; + + assert.throws(() => port1.postMessage(5, { transfer: null }), err2); + assert.throws(() => port1.postMessage(5, { transfer: 0 }), err2); + assert.throws(() => port1.postMessage(5, { transfer: false }), err2); + assert.throws(() => port1.postMessage(5, { transfer: {} }), err2); + assert.throws(() => port1.postMessage(5, { + transfer: { [Symbol.iterator]() { return {}; } } + }), err2); + assert.throws(() => port1.postMessage(5, { + transfer: { [Symbol.iterator]() { return { next: 42 }; } } + }), err2); + assert.throws(() => port1.postMessage(5, { + transfer: { [Symbol.iterator]() { return { next: null }; } } + }), err2); + port1.close(); +} + +{ + // Make sure these ArrayBuffers end up detached, i.e. are actually being + // transferred because the transfer list provides them. + const { port1, port2 } = new MessageChannel(); + port2.on('message', common.mustCall((msg) => { + assert.strictEqual(msg.ab.byteLength, 10); + }, 4)); + + { + const ab = new ArrayBuffer(10); + port1.postMessage({ ab }, [ ab ]); + assert.strictEqual(ab.byteLength, 0); + } + + { + const ab = new ArrayBuffer(10); + port1.postMessage({ ab }, { transfer: [ ab ] }); + assert.strictEqual(ab.byteLength, 0); + } + + { + const ab = new ArrayBuffer(10); + port1.postMessage({ ab }, (function*() { yield ab; })()); + assert.strictEqual(ab.byteLength, 0); + } + + { + const ab = new ArrayBuffer(10); + port1.postMessage({ ab }, { + transfer: (function*() { yield ab; })() + }); + assert.strictEqual(ab.byteLength, 0); + } + port1.close(); } -- cgit v1.2.3