2017-09-05 22:38:32 +02:00
|
|
|
'use strict';
|
|
|
|
|
2019-04-14 17:34:08 +02:00
|
|
|
/* global SharedArrayBuffer */
|
|
|
|
|
2019-11-22 18:04:46 +01:00
|
|
|
const {
|
2019-11-23 10:09:05 +01:00
|
|
|
ArrayIsArray,
|
2019-11-22 18:04:46 +01:00
|
|
|
MathMax,
|
|
|
|
ObjectCreate,
|
|
|
|
ObjectEntries,
|
2019-12-13 16:46:35 +01:00
|
|
|
Promise,
|
|
|
|
PromiseResolve,
|
2019-11-30 16:55:29 +01:00
|
|
|
Symbol,
|
2019-12-08 18:33:33 +01:00
|
|
|
SymbolFor,
|
2019-11-22 18:04:46 +01:00
|
|
|
} = primordials;
|
2019-04-09 09:55:53 +02:00
|
|
|
|
2017-09-05 22:38:32 +02:00
|
|
|
const EventEmitter = require('events');
|
2019-02-14 04:48:18 +01:00
|
|
|
const assert = require('internal/assert');
|
2017-09-01 17:03:41 +02:00
|
|
|
const path = require('path');
|
2019-03-06 12:54:12 +01:00
|
|
|
|
2019-03-08 19:35:40 +01:00
|
|
|
const errorCodes = require('internal/errors').codes;
|
2017-09-01 17:03:41 +02:00
|
|
|
const {
|
2018-06-26 17:31:36 +02:00
|
|
|
ERR_WORKER_PATH,
|
2017-09-20 23:23:31 +02:00
|
|
|
ERR_WORKER_UNSERIALIZABLE_ERROR,
|
|
|
|
ERR_WORKER_UNSUPPORTED_EXTENSION,
|
2019-01-04 19:02:25 +01:00
|
|
|
ERR_WORKER_INVALID_EXEC_ARGV,
|
|
|
|
ERR_INVALID_ARG_TYPE,
|
2019-03-08 19:35:40 +01:00
|
|
|
} = errorCodes;
|
2018-12-11 16:24:22 +01:00
|
|
|
const { validateString } = require('internal/validators');
|
2019-01-23 23:21:46 +01:00
|
|
|
const { getOptionValue } = require('internal/options');
|
2017-09-05 22:38:32 +02:00
|
|
|
|
2019-04-14 17:34:08 +02:00
|
|
|
const workerIo = require('internal/worker/io');
|
2018-09-23 19:14:57 +02:00
|
|
|
const {
|
2018-12-23 04:53:05 +01:00
|
|
|
drainMessagePort,
|
|
|
|
MessageChannel,
|
|
|
|
messageTypes,
|
|
|
|
kPort,
|
|
|
|
kIncrementsPortRef,
|
|
|
|
kWaitingStreams,
|
|
|
|
kStdioWantsMoreDataCallback,
|
|
|
|
setupPortReferencing,
|
|
|
|
ReadableWorkerStdio,
|
2019-04-14 17:34:08 +02:00
|
|
|
WritableWorkerStdio
|
|
|
|
} = workerIo;
|
2018-12-24 00:31:06 +01:00
|
|
|
const { deserializeError } = require('internal/error-serdes');
|
2018-09-09 04:45:10 +02:00
|
|
|
const { pathToFileURL } = require('url');
|
2017-09-05 22:38:32 +02:00
|
|
|
|
2017-09-01 17:03:41 +02:00
|
|
|
const {
|
2019-02-01 23:47:38 +01:00
|
|
|
ownsProcessState,
|
|
|
|
isMainThread,
|
2019-03-08 19:35:40 +01:00
|
|
|
resourceLimits: resourceLimitsRaw,
|
2019-01-29 19:06:17 +01:00
|
|
|
threadId,
|
2019-02-01 23:47:38 +01:00
|
|
|
Worker: WorkerImpl,
|
2019-03-08 19:35:40 +01:00
|
|
|
kMaxYoungGenerationSizeMb,
|
|
|
|
kMaxOldGenerationSizeMb,
|
|
|
|
kCodeRangeSizeMb,
|
|
|
|
kTotalResourceLimitCount
|
2017-09-01 17:03:41 +02:00
|
|
|
} = internalBinding('worker');
|
|
|
|
|
|
|
|
const kHandle = Symbol('kHandle');
|
|
|
|
const kPublicPort = Symbol('kPublicPort');
|
|
|
|
const kDispose = Symbol('kDispose');
|
|
|
|
const kOnExit = Symbol('kOnExit');
|
|
|
|
const kOnMessage = Symbol('kOnMessage');
|
|
|
|
const kOnCouldNotSerializeErr = Symbol('kOnCouldNotSerializeErr');
|
|
|
|
const kOnErrorMessage = Symbol('kOnErrorMessage');
|
2018-05-13 23:25:14 +02:00
|
|
|
const kParentSideStdio = Symbol('kParentSideStdio');
|
2017-09-05 22:38:32 +02:00
|
|
|
|
2019-12-08 18:33:33 +01:00
|
|
|
const SHARE_ENV = SymbolFor('nodejs.worker_threads.SHARE_ENV');
|
2019-04-17 17:45:53 +02:00
|
|
|
const debug = require('internal/util/debuglog').debuglog('worker');
|
2017-09-05 22:38:32 +02:00
|
|
|
|
2019-04-14 17:34:08 +02:00
|
|
|
let cwdCounter;
|
|
|
|
|
|
|
|
if (isMainThread) {
|
|
|
|
cwdCounter = new Uint32Array(new SharedArrayBuffer(4));
|
|
|
|
const originalChdir = process.chdir;
|
|
|
|
process.chdir = function(path) {
|
|
|
|
Atomics.add(cwdCounter, 0, 1);
|
|
|
|
originalChdir(path);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-09-01 17:03:41 +02:00
|
|
|
class Worker extends EventEmitter {
|
|
|
|
constructor(filename, options = {}) {
|
|
|
|
super();
|
|
|
|
debug(`[${threadId}] create new worker`, filename, options);
|
2018-12-11 16:24:22 +01:00
|
|
|
validateString(filename, 'filename');
|
2019-11-23 10:09:05 +01:00
|
|
|
if (options.execArgv && !ArrayIsArray(options.execArgv)) {
|
2019-01-04 19:02:25 +01:00
|
|
|
throw new ERR_INVALID_ARG_TYPE('options.execArgv',
|
2019-11-20 17:55:36 +01:00
|
|
|
'Array',
|
2019-01-04 19:02:25 +01:00
|
|
|
options.execArgv);
|
|
|
|
}
|
2019-11-20 17:55:36 +01:00
|
|
|
let argv;
|
|
|
|
if (options.argv) {
|
|
|
|
if (!ArrayIsArray(options.argv)) {
|
|
|
|
throw new ERR_INVALID_ARG_TYPE('options.argv', 'Array', options.argv);
|
|
|
|
}
|
|
|
|
argv = options.argv.map(String);
|
|
|
|
}
|
2017-09-20 23:23:31 +02:00
|
|
|
if (!options.eval) {
|
2019-04-15 01:50:58 +02:00
|
|
|
if (!path.isAbsolute(filename) && !/^\.\.?[\\/]/.test(filename)) {
|
2018-06-26 17:31:36 +02:00
|
|
|
throw new ERR_WORKER_PATH(filename);
|
2017-09-20 23:23:31 +02:00
|
|
|
}
|
2018-06-26 17:31:36 +02:00
|
|
|
filename = path.resolve(filename);
|
|
|
|
|
2017-09-20 23:23:31 +02:00
|
|
|
const ext = path.extname(filename);
|
|
|
|
if (ext !== '.js' && ext !== '.mjs') {
|
|
|
|
throw new ERR_WORKER_UNSUPPORTED_EXTENSION(ext);
|
|
|
|
}
|
2017-09-01 17:03:41 +02:00
|
|
|
}
|
|
|
|
|
2019-02-22 20:11:19 +01:00
|
|
|
let env;
|
|
|
|
if (typeof options.env === 'object' && options.env !== null) {
|
2019-11-22 18:04:46 +01:00
|
|
|
env = ObjectCreate(null);
|
|
|
|
for (const [ key, value ] of ObjectEntries(options.env))
|
2019-02-22 20:11:19 +01:00
|
|
|
env[key] = `${value}`;
|
|
|
|
} else if (options.env == null) {
|
|
|
|
env = process.env;
|
|
|
|
} else if (options.env !== SHARE_ENV) {
|
|
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
|
|
'options.env',
|
|
|
|
['object', 'undefined', 'null', 'worker_threads.SHARE_ENV'],
|
|
|
|
options.env);
|
|
|
|
}
|
|
|
|
|
2018-09-09 04:45:10 +02:00
|
|
|
const url = options.eval ? null : pathToFileURL(filename);
|
2017-09-01 17:03:41 +02:00
|
|
|
// Set up the C++ handle for the worker, as well as some internal wiring.
|
2019-03-08 19:35:40 +01:00
|
|
|
this[kHandle] = new WorkerImpl(url, options.execArgv,
|
|
|
|
parseResourceLimits(options.resourceLimits));
|
2019-01-04 19:02:25 +01:00
|
|
|
if (this[kHandle].invalidExecArgv) {
|
|
|
|
throw new ERR_WORKER_INVALID_EXEC_ARGV(this[kHandle].invalidExecArgv);
|
|
|
|
}
|
2019-02-22 20:11:19 +01:00
|
|
|
if (env === process.env) {
|
|
|
|
// This may be faster than manually cloning the object in C++, especially
|
|
|
|
// when recursively spawning Workers.
|
|
|
|
this[kHandle].cloneParentEnvVars();
|
|
|
|
} else if (env !== undefined) {
|
|
|
|
this[kHandle].setEnvVars(env);
|
|
|
|
}
|
2019-03-08 19:35:40 +01:00
|
|
|
this[kHandle].onexit = (code, customErr) => this[kOnExit](code, customErr);
|
2017-09-01 17:03:41 +02:00
|
|
|
this[kPort] = this[kHandle].messagePort;
|
|
|
|
this[kPort].on('message', (data) => this[kOnMessage](data));
|
|
|
|
this[kPort].start();
|
|
|
|
this[kPort].unref();
|
2018-05-13 23:25:14 +02:00
|
|
|
this[kPort][kWaitingStreams] = 0;
|
2017-09-01 17:03:41 +02:00
|
|
|
debug(`[${threadId}] created Worker with ID ${this.threadId}`);
|
|
|
|
|
2018-05-13 23:25:14 +02:00
|
|
|
let stdin = null;
|
|
|
|
if (options.stdin)
|
|
|
|
stdin = new WritableWorkerStdio(this[kPort], 'stdin');
|
|
|
|
const stdout = new ReadableWorkerStdio(this[kPort], 'stdout');
|
|
|
|
if (!options.stdout) {
|
|
|
|
stdout[kIncrementsPortRef] = false;
|
|
|
|
pipeWithoutWarning(stdout, process.stdout);
|
|
|
|
}
|
|
|
|
const stderr = new ReadableWorkerStdio(this[kPort], 'stderr');
|
|
|
|
if (!options.stderr) {
|
|
|
|
stderr[kIncrementsPortRef] = false;
|
|
|
|
pipeWithoutWarning(stderr, process.stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
this[kParentSideStdio] = { stdin, stdout, stderr };
|
|
|
|
|
2017-09-01 17:03:41 +02:00
|
|
|
const { port1, port2 } = new MessageChannel();
|
|
|
|
this[kPublicPort] = port1;
|
|
|
|
this[kPublicPort].on('message', (message) => this.emit('message', message));
|
|
|
|
setupPortReferencing(this[kPublicPort], this, 'message');
|
|
|
|
this[kPort].postMessage({
|
2019-11-20 17:55:36 +01:00
|
|
|
argv,
|
2018-06-26 02:14:41 +02:00
|
|
|
type: messageTypes.LOAD_SCRIPT,
|
2017-09-01 17:03:41 +02:00
|
|
|
filename,
|
|
|
|
doEval: !!options.eval,
|
2019-04-14 17:34:08 +02:00
|
|
|
cwdCounter: cwdCounter || workerIo.sharedCwdCounter,
|
2017-09-01 17:03:41 +02:00
|
|
|
workerData: options.workerData,
|
2018-05-13 23:25:14 +02:00
|
|
|
publicPort: port2,
|
2019-01-23 23:21:46 +01:00
|
|
|
manifestSrc: getOptionValue('--experimental-policy') ?
|
|
|
|
require('internal/process/policy').src :
|
|
|
|
null,
|
2018-05-13 23:25:14 +02:00
|
|
|
hasStdin: !!options.stdin
|
2017-09-01 17:03:41 +02:00
|
|
|
}, [port2]);
|
|
|
|
// Actually start the new thread now that everything is in place.
|
|
|
|
this[kHandle].startThread();
|
|
|
|
}
|
|
|
|
|
2019-03-08 19:35:40 +01:00
|
|
|
[kOnExit](code, customErr) {
|
2017-09-01 17:03:41 +02:00
|
|
|
debug(`[${threadId}] hears end event for Worker ${this.threadId}`);
|
2018-12-23 04:53:05 +01:00
|
|
|
drainMessagePort(this[kPublicPort]);
|
|
|
|
drainMessagePort(this[kPort]);
|
2017-09-01 17:03:41 +02:00
|
|
|
this[kDispose]();
|
2019-03-08 19:35:40 +01:00
|
|
|
if (customErr) {
|
|
|
|
debug(`[${threadId}] failing with custom error ${customErr}`);
|
|
|
|
this.emit('error', new errorCodes[customErr]());
|
|
|
|
}
|
2017-09-01 17:03:41 +02:00
|
|
|
this.emit('exit', code);
|
|
|
|
this.removeAllListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
[kOnCouldNotSerializeErr]() {
|
|
|
|
this.emit('error', new ERR_WORKER_UNSERIALIZABLE_ERROR());
|
|
|
|
}
|
|
|
|
|
|
|
|
[kOnErrorMessage](serialized) {
|
|
|
|
// This is what is called for uncaught exceptions.
|
|
|
|
const error = deserializeError(serialized);
|
|
|
|
this.emit('error', error);
|
|
|
|
}
|
|
|
|
|
|
|
|
[kOnMessage](message) {
|
|
|
|
switch (message.type) {
|
2018-06-26 02:14:41 +02:00
|
|
|
case messageTypes.UP_AND_RUNNING:
|
2017-09-01 17:03:41 +02:00
|
|
|
return this.emit('online');
|
2018-06-26 02:14:41 +02:00
|
|
|
case messageTypes.COULD_NOT_SERIALIZE_ERROR:
|
2017-09-01 17:03:41 +02:00
|
|
|
return this[kOnCouldNotSerializeErr]();
|
2018-06-26 02:14:41 +02:00
|
|
|
case messageTypes.ERROR_MESSAGE:
|
2017-09-01 17:03:41 +02:00
|
|
|
return this[kOnErrorMessage](message.error);
|
2018-06-26 02:14:41 +02:00
|
|
|
case messageTypes.STDIO_PAYLOAD:
|
2018-05-13 23:25:14 +02:00
|
|
|
{
|
|
|
|
const { stream, chunk, encoding } = message;
|
|
|
|
return this[kParentSideStdio][stream].push(chunk, encoding);
|
|
|
|
}
|
2018-06-26 02:14:41 +02:00
|
|
|
case messageTypes.STDIO_WANTS_MORE_DATA:
|
2018-05-13 23:25:14 +02:00
|
|
|
{
|
|
|
|
const { stream } = message;
|
|
|
|
return this[kParentSideStdio][stream][kStdioWantsMoreDataCallback]();
|
|
|
|
}
|
2017-09-01 17:03:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
assert.fail(`Unknown worker message type ${message.type}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
[kDispose]() {
|
|
|
|
this[kHandle].onexit = null;
|
|
|
|
this[kHandle] = null;
|
|
|
|
this[kPort] = null;
|
|
|
|
this[kPublicPort] = null;
|
2018-05-13 23:25:14 +02:00
|
|
|
|
|
|
|
const { stdout, stderr } = this[kParentSideStdio];
|
|
|
|
|
2019-09-21 16:12:13 +02:00
|
|
|
if (!stdout.readableEnded) {
|
2018-05-13 23:25:14 +02:00
|
|
|
debug(`[${threadId}] explicitly closes stdout for ${this.threadId}`);
|
|
|
|
stdout.push(null);
|
|
|
|
}
|
2019-09-21 16:12:13 +02:00
|
|
|
if (!stderr.readableEnded) {
|
2018-05-13 23:25:14 +02:00
|
|
|
debug(`[${threadId}] explicitly closes stderr for ${this.threadId}`);
|
|
|
|
stderr.push(null);
|
|
|
|
}
|
2017-09-01 17:03:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
postMessage(...args) {
|
2019-02-01 15:27:04 +01:00
|
|
|
if (this[kPublicPort] === null) return;
|
|
|
|
|
2017-09-01 17:03:41 +02:00
|
|
|
this[kPublicPort].postMessage(...args);
|
|
|
|
}
|
|
|
|
|
|
|
|
terminate(callback) {
|
|
|
|
debug(`[${threadId}] terminates Worker with ID ${this.threadId}`);
|
|
|
|
|
2019-09-07 21:56:24 +02:00
|
|
|
this.ref();
|
|
|
|
|
worker: refactor `worker.terminate()`
At the collaborator summit in Berlin, the behaviour of
`worker.terminate()` was discussed.
In particular, switching from a callback-based to a Promise-based API
was suggested. While investigating that possibility later, it was
discovered that `.terminate()` was unintentionally synchronous up
until now (including calling its callback synchronously).
Also, the topic of its stability has been brought up. I have performed
two manual reviews of the native codebase for compatibility with
`.terminate()`, and performed some manual fuzz testing with the test
suite. At this point, bugs with `.terminate()` should, in my opinion,
be treated like bugs in other Node.js features.
(It is possible to make Node.js crash with `.terminate()` by messing
with internals and/or built-in prototype objects, but that is already
the case without `.terminate()` as well.)
This commit:
- Makes `.terminate()` an asynchronous operation.
- Makes `.terminate()` return a `Promise`.
- Runtime-deprecates passing a callback.
- Removes a warning about its stability from the documentation.
- Eliminates an unnecessary extra function from the C++ code.
A possible alternative to returning a `Promise` would be to keep the
method synchronous and just drop the callback. Generally, providing
an asynchronous API does provide us with a bit more flexibility.
Refs: https://github.com/nodejs/summit/issues/141
PR-URL: https://github.com/nodejs/node/pull/28021
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2019-06-02 15:09:57 +02:00
|
|
|
if (typeof callback === 'function') {
|
|
|
|
process.emitWarning(
|
|
|
|
'Passing a callback to worker.terminate() is deprecated. ' +
|
|
|
|
'It returns a Promise instead.',
|
2019-06-23 15:39:57 +02:00
|
|
|
'DeprecationWarning', 'DEP0132');
|
2019-12-13 16:46:35 +01:00
|
|
|
if (this[kHandle] === null) return PromiseResolve();
|
2017-09-01 17:03:41 +02:00
|
|
|
this.once('exit', (exitCode) => callback(null, exitCode));
|
worker: refactor `worker.terminate()`
At the collaborator summit in Berlin, the behaviour of
`worker.terminate()` was discussed.
In particular, switching from a callback-based to a Promise-based API
was suggested. While investigating that possibility later, it was
discovered that `.terminate()` was unintentionally synchronous up
until now (including calling its callback synchronously).
Also, the topic of its stability has been brought up. I have performed
two manual reviews of the native codebase for compatibility with
`.terminate()`, and performed some manual fuzz testing with the test
suite. At this point, bugs with `.terminate()` should, in my opinion,
be treated like bugs in other Node.js features.
(It is possible to make Node.js crash with `.terminate()` by messing
with internals and/or built-in prototype objects, but that is already
the case without `.terminate()` as well.)
This commit:
- Makes `.terminate()` an asynchronous operation.
- Makes `.terminate()` return a `Promise`.
- Runtime-deprecates passing a callback.
- Removes a warning about its stability from the documentation.
- Eliminates an unnecessary extra function from the C++ code.
A possible alternative to returning a `Promise` would be to keep the
method synchronous and just drop the callback. Generally, providing
an asynchronous API does provide us with a bit more flexibility.
Refs: https://github.com/nodejs/summit/issues/141
PR-URL: https://github.com/nodejs/node/pull/28021
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2019-06-02 15:09:57 +02:00
|
|
|
}
|
2017-09-01 17:03:41 +02:00
|
|
|
|
2019-12-13 16:46:35 +01:00
|
|
|
if (this[kHandle] === null) return PromiseResolve();
|
2019-06-22 00:21:43 +02:00
|
|
|
|
2017-09-01 17:03:41 +02:00
|
|
|
this[kHandle].stopThread();
|
worker: refactor `worker.terminate()`
At the collaborator summit in Berlin, the behaviour of
`worker.terminate()` was discussed.
In particular, switching from a callback-based to a Promise-based API
was suggested. While investigating that possibility later, it was
discovered that `.terminate()` was unintentionally synchronous up
until now (including calling its callback synchronously).
Also, the topic of its stability has been brought up. I have performed
two manual reviews of the native codebase for compatibility with
`.terminate()`, and performed some manual fuzz testing with the test
suite. At this point, bugs with `.terminate()` should, in my opinion,
be treated like bugs in other Node.js features.
(It is possible to make Node.js crash with `.terminate()` by messing
with internals and/or built-in prototype objects, but that is already
the case without `.terminate()` as well.)
This commit:
- Makes `.terminate()` an asynchronous operation.
- Makes `.terminate()` return a `Promise`.
- Runtime-deprecates passing a callback.
- Removes a warning about its stability from the documentation.
- Eliminates an unnecessary extra function from the C++ code.
A possible alternative to returning a `Promise` would be to keep the
method synchronous and just drop the callback. Generally, providing
an asynchronous API does provide us with a bit more flexibility.
Refs: https://github.com/nodejs/summit/issues/141
PR-URL: https://github.com/nodejs/node/pull/28021
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2019-06-02 15:09:57 +02:00
|
|
|
|
|
|
|
// Do not use events.once() here, because the 'exit' event will always be
|
|
|
|
// emitted regardless of any errors, and the point is to only resolve
|
|
|
|
// once the thread has actually stopped.
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
this.once('exit', resolve);
|
|
|
|
});
|
2017-09-01 17:03:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ref() {
|
|
|
|
if (this[kHandle] === null) return;
|
|
|
|
|
|
|
|
this[kHandle].ref();
|
|
|
|
this[kPublicPort].ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
unref() {
|
|
|
|
if (this[kHandle] === null) return;
|
|
|
|
|
|
|
|
this[kHandle].unref();
|
|
|
|
this[kPublicPort].unref();
|
|
|
|
}
|
|
|
|
|
|
|
|
get threadId() {
|
|
|
|
if (this[kHandle] === null) return -1;
|
|
|
|
|
|
|
|
return this[kHandle].threadId;
|
|
|
|
}
|
2018-05-13 23:25:14 +02:00
|
|
|
|
|
|
|
get stdin() {
|
|
|
|
return this[kParentSideStdio].stdin;
|
|
|
|
}
|
|
|
|
|
|
|
|
get stdout() {
|
|
|
|
return this[kParentSideStdio].stdout;
|
|
|
|
}
|
|
|
|
|
|
|
|
get stderr() {
|
|
|
|
return this[kParentSideStdio].stderr;
|
|
|
|
}
|
2019-03-08 19:35:40 +01:00
|
|
|
|
|
|
|
get resourceLimits() {
|
|
|
|
if (this[kHandle] === null) return {};
|
|
|
|
|
|
|
|
return makeResourceLimits(this[kHandle].getResourceLimits());
|
|
|
|
}
|
2018-05-13 23:25:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function pipeWithoutWarning(source, dest) {
|
|
|
|
const sourceMaxListeners = source._maxListeners;
|
|
|
|
const destMaxListeners = dest._maxListeners;
|
|
|
|
source.setMaxListeners(Infinity);
|
|
|
|
dest.setMaxListeners(Infinity);
|
|
|
|
|
|
|
|
source.pipe(dest);
|
|
|
|
|
|
|
|
source._maxListeners = sourceMaxListeners;
|
|
|
|
dest._maxListeners = destMaxListeners;
|
|
|
|
}
|
|
|
|
|
2019-03-08 19:35:40 +01:00
|
|
|
const resourceLimitsArray = new Float64Array(kTotalResourceLimitCount);
|
|
|
|
function parseResourceLimits(obj) {
|
|
|
|
const ret = resourceLimitsArray;
|
|
|
|
ret.fill(-1);
|
|
|
|
if (typeof obj !== 'object' || obj === null) return ret;
|
|
|
|
|
|
|
|
if (typeof obj.maxOldGenerationSizeMb === 'number')
|
2019-11-22 18:04:46 +01:00
|
|
|
ret[kMaxOldGenerationSizeMb] = MathMax(obj.maxOldGenerationSizeMb, 2);
|
2019-03-08 19:35:40 +01:00
|
|
|
if (typeof obj.maxYoungGenerationSizeMb === 'number')
|
|
|
|
ret[kMaxYoungGenerationSizeMb] = obj.maxYoungGenerationSizeMb;
|
|
|
|
if (typeof obj.codeRangeSizeMb === 'number')
|
|
|
|
ret[kCodeRangeSizeMb] = obj.codeRangeSizeMb;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeResourceLimits(float64arr) {
|
|
|
|
return {
|
|
|
|
maxYoungGenerationSizeMb: float64arr[kMaxYoungGenerationSizeMb],
|
|
|
|
maxOldGenerationSizeMb: float64arr[kMaxOldGenerationSizeMb],
|
|
|
|
codeRangeSizeMb: float64arr[kCodeRangeSizeMb]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-09-05 22:38:32 +02:00
|
|
|
module.exports = {
|
2019-02-01 23:47:38 +01:00
|
|
|
ownsProcessState,
|
|
|
|
isMainThread,
|
2019-02-22 20:11:19 +01:00
|
|
|
SHARE_ENV,
|
2019-03-08 19:35:40 +01:00
|
|
|
resourceLimits:
|
|
|
|
!isMainThread ? makeResourceLimits(resourceLimitsRaw) : {},
|
2017-09-01 17:03:41 +02:00
|
|
|
threadId,
|
|
|
|
Worker,
|
2017-09-05 22:38:32 +02:00
|
|
|
};
|