summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-03-08 19:35:40 +0100
committerAnna Henningsen <anna@addaleax.net>2019-11-05 19:57:13 +0100
commitd855904ef6a0daa0c0475e745fdd33815e760e0c (patch)
tree56c605726ad3200bd533a3bfab836c45ad48473e /lib
parent309e1eae797d3060126ef2e13ee0ab124808f575 (diff)
downloadandroid-node-v8-d855904ef6a0daa0c0475e745fdd33815e760e0c.tar.gz
android-node-v8-d855904ef6a0daa0c0475e745fdd33815e760e0c.tar.bz2
android-node-v8-d855904ef6a0daa0c0475e745fdd33815e760e0c.zip
worker: allow specifying resource limits
Allow specifying resource limits for the JS engine instance created as part of a Worker. PR-URL: https://github.com/nodejs/node/pull/26628 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/internal/errors.js2
-rw-r--r--lib/internal/worker.js52
-rw-r--r--lib/worker_threads.js2
3 files changed, 51 insertions, 5 deletions
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index cd3c162183..2684931a77 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1226,6 +1226,8 @@ E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
E('ERR_WORKER_INVALID_EXEC_ARGV', (errors) =>
`Initiated Worker with invalid execArgv flags: ${errors.join(', ')}`,
Error);
+E('ERR_WORKER_OUT_OF_MEMORY', 'Worker terminated due to reaching memory limit',
+ Error);
E('ERR_WORKER_PATH',
'The worker script filename must be an absolute path or a relative ' +
'path starting with \'./\' or \'../\'. Received "%s"',
diff --git a/lib/internal/worker.js b/lib/internal/worker.js
index fc6588d527..614f930105 100644
--- a/lib/internal/worker.js
+++ b/lib/internal/worker.js
@@ -2,19 +2,20 @@
/* global SharedArrayBuffer */
-const { Object } = primordials;
+const { Math, Object } = primordials;
const EventEmitter = require('events');
const assert = require('internal/assert');
const path = require('path');
+const errorCodes = require('internal/errors').codes;
const {
ERR_WORKER_PATH,
ERR_WORKER_UNSERIALIZABLE_ERROR,
ERR_WORKER_UNSUPPORTED_EXTENSION,
ERR_WORKER_INVALID_EXEC_ARGV,
ERR_INVALID_ARG_TYPE,
-} = require('internal/errors').codes;
+} = errorCodes;
const { validateString } = require('internal/validators');
const { getOptionValue } = require('internal/options');
@@ -37,8 +38,13 @@ const { pathToFileURL } = require('url');
const {
ownsProcessState,
isMainThread,
+ resourceLimits: resourceLimitsRaw,
threadId,
Worker: WorkerImpl,
+ kMaxYoungGenerationSizeMb,
+ kMaxOldGenerationSizeMb,
+ kCodeRangeSizeMb,
+ kTotalResourceLimitCount
} = internalBinding('worker');
const kHandle = Symbol('kHandle');
@@ -102,7 +108,8 @@ class Worker extends EventEmitter {
const url = options.eval ? null : pathToFileURL(filename);
// Set up the C++ handle for the worker, as well as some internal wiring.
- this[kHandle] = new WorkerImpl(url, options.execArgv);
+ this[kHandle] = new WorkerImpl(url, options.execArgv,
+ parseResourceLimits(options.resourceLimits));
if (this[kHandle].invalidExecArgv) {
throw new ERR_WORKER_INVALID_EXEC_ARGV(this[kHandle].invalidExecArgv);
}
@@ -113,7 +120,7 @@ class Worker extends EventEmitter {
} else if (env !== undefined) {
this[kHandle].setEnvVars(env);
}
- this[kHandle].onexit = (code) => this[kOnExit](code);
+ this[kHandle].onexit = (code, customErr) => this[kOnExit](code, customErr);
this[kPort] = this[kHandle].messagePort;
this[kPort].on('message', (data) => this[kOnMessage](data));
this[kPort].start();
@@ -157,11 +164,15 @@ class Worker extends EventEmitter {
this[kHandle].startThread();
}
- [kOnExit](code) {
+ [kOnExit](code, customErr) {
debug(`[${threadId}] hears end event for Worker ${this.threadId}`);
drainMessagePort(this[kPublicPort]);
drainMessagePort(this[kPort]);
this[kDispose]();
+ if (customErr) {
+ debug(`[${threadId}] failing with custom error ${customErr}`);
+ this.emit('error', new errorCodes[customErr]());
+ }
this.emit('exit', code);
this.removeAllListeners();
}
@@ -280,6 +291,12 @@ class Worker extends EventEmitter {
get stderr() {
return this[kParentSideStdio].stderr;
}
+
+ get resourceLimits() {
+ if (this[kHandle] === null) return {};
+
+ return makeResourceLimits(this[kHandle].getResourceLimits());
+ }
}
function pipeWithoutWarning(source, dest) {
@@ -294,10 +311,35 @@ function pipeWithoutWarning(source, dest) {
dest._maxListeners = destMaxListeners;
}
+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')
+ ret[kMaxOldGenerationSizeMb] = Math.max(obj.maxOldGenerationSizeMb, 2);
+ 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]
+ };
+}
+
module.exports = {
ownsProcessState,
isMainThread,
SHARE_ENV,
+ resourceLimits:
+ !isMainThread ? makeResourceLimits(resourceLimitsRaw) : {},
threadId,
Worker,
};
diff --git a/lib/worker_threads.js b/lib/worker_threads.js
index bd455edea2..4b72bf2711 100644
--- a/lib/worker_threads.js
+++ b/lib/worker_threads.js
@@ -3,6 +3,7 @@
const {
isMainThread,
SHARE_ENV,
+ resourceLimits,
threadId,
Worker
} = require('internal/worker');
@@ -20,6 +21,7 @@ module.exports = {
MessageChannel,
moveMessagePortToContext,
receiveMessageOnPort,
+ resourceLimits,
threadId,
SHARE_ENV,
Worker,