From 88fb5a5c7933022de750745e51e5dc0996a1e2c4 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 19 Jun 2020 20:39:23 +0200 Subject: [PATCH] worker: add public method for marking objects as untransferable We currently mark a number of `ArrayBuffer`s as not transferable, including the `Buffer` pool and ones with finalizers provided by C++ addons. There is no good reason to assume that userland code might not encounter similar problems, for example when doing `ArrayBuffer` pooling similar to ours. Therefore, provide an API that lets userland code also mark objects as not transferable. PR-URL: https://github.com/nodejs/node/pull/33979 Reviewed-By: James M Snell Reviewed-By: Gus Caplan --- doc/api/worker_threads.md | 40 +++++++++++++++++++ lib/buffer.js | 6 +-- lib/internal/buffer.js | 15 ++++++- lib/worker_threads.js | 7 +++- src/env.h | 2 +- src/node_api.cc | 2 +- src/node_buffer.cc | 4 +- src/node_messaging.cc | 26 +++++++----- ...ge-transfer-port-mark-as-untransferable.js | 37 +++++++++++++++++ 9 files changed, 118 insertions(+), 21 deletions(-) create mode 100644 test/parallel/test-worker-message-transfer-port-mark-as-untransferable.js diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index a91a824c7d723b..6b402c4e99f652 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -80,6 +80,42 @@ if (isMainThread) { } ``` +## `worker.markAsUntransferable(object)` + + +Mark an object as not transferable. If `object` occurs in the transfer list of +a [`port.postMessage()`][] call, it will be ignored. + +In particular, this makes sense for objects that can be cloned, rather than +transferred, and which are used by other objects on the sending side. +For example, Node.js marks the `ArrayBuffer`s it uses for its +[`Buffer` pool][`Buffer.allocUnsafe()`] with this. + +This operation cannot be undone. + +```js +const { MessageChannel, markAsUntransferable } = require('worker_threads'); + +const pooledBuffer = new ArrayBuffer(8); +const typedArray1 = new Uint8Array(pooledBuffer); +const typedArray2 = new Float64Array(pooledBuffer); + +markAsUntransferable(pooledBuffer); + +const { port1 } = new MessageChannel(); +port1.postMessage(typedArray1, [ typedArray1.buffer ]); + +// The following line prints the contents of typedArray1 -- it still owns its +// memory and has been cloned, not transfered. Without `markAsUntransferable()`, +// this would print an empty Uint8Array. typedArray2 is intact as well. +console.log(typedArray1); +console.log(typedArray2); +``` + +There is no equivalent to this API in browsers. + ## `worker.moveMessagePortToContext(port, contextifiedSandbox)`