nodejs/lib/internal/process.js

293 lines
7.8 KiB
JavaScript
Raw Normal View History

'use strict';
const {
errnoException,
codes: {
ERR_ASSERTION,
ERR_CPU_USAGE,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_OPT_VALUE,
ERR_OUT_OF_RANGE,
ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET,
ERR_UNKNOWN_SIGNAL
}
} = require('internal/errors');
const util = require('util');
const constants = process.binding('constants').os.signals;
const assert = require('assert').strict;
const { deprecate } = require('internal/util');
const { isMainThread } = require('internal/worker');
process.assert = deprecate(
function(x, msg) {
if (!x) throw new ERR_ASSERTION(msg || 'assertion error');
},
'process.assert() is deprecated. Please use the `assert` module instead.',
'DEP0100');
// Set up the process.cpuUsage() function.
function setup_cpuUsage(_cpuUsage) {
// Create the argument array that will be passed to the native function.
const cpuValues = new Float64Array(2);
// Replace the native function with the JS version that calls the native
// function.
process.cpuUsage = function cpuUsage(prevValue) {
// If a previous value was passed in, ensure it has the correct shape.
if (prevValue) {
if (!previousValueIsValid(prevValue.user)) {
if (typeof prevValue !== 'object')
throw new ERR_INVALID_ARG_TYPE('prevValue', 'object', prevValue);
if (typeof prevValue.user !== 'number') {
throw new ERR_INVALID_ARG_TYPE('prevValue.user',
'number', prevValue.user);
}
throw new ERR_INVALID_OPT_VALUE.RangeError('prevValue.user',
prevValue.user);
}
if (!previousValueIsValid(prevValue.system)) {
if (typeof prevValue.system !== 'number') {
throw new ERR_INVALID_ARG_TYPE('prevValue.system',
'number', prevValue.system);
}
throw new ERR_INVALID_OPT_VALUE.RangeError('prevValue.system',
prevValue.system);
}
}
// Call the native function to get the current values.
const errmsg = _cpuUsage(cpuValues);
if (errmsg) {
throw new ERR_CPU_USAGE(errmsg);
}
// If a previous value was passed in, return diff of current from previous.
if (prevValue) {
return {
user: cpuValues[0] - prevValue.user,
system: cpuValues[1] - prevValue.system
};
}
// If no previous value passed in, return current value.
return {
user: cpuValues[0],
system: cpuValues[1]
};
};
// Ensure that a previously passed in value is valid. Currently, the native
// implementation always returns numbers <= Number.MAX_SAFE_INTEGER.
function previousValueIsValid(num) {
return Number.isFinite(num) &&
num <= Number.MAX_SAFE_INTEGER &&
num >= 0;
}
}
// The 3 entries filled in by the original process.hrtime contains
// the upper/lower 32 bits of the second part of the value,
// and the remaining nanoseconds of the value.
function setup_hrtime(_hrtime) {
const hrValues = new Uint32Array(3);
process.hrtime = function hrtime(time) {
_hrtime(hrValues);
if (time !== undefined) {
if (!Array.isArray(time)) {
throw new ERR_INVALID_ARG_TYPE('time', 'Array', time);
}
if (time.length !== 2) {
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
}
const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
const nsec = hrValues[2] - time[1];
const needsBorrow = nsec < 0;
return [needsBorrow ? sec - 1 : sec, needsBorrow ? nsec + 1e9 : nsec];
}
return [
hrValues[0] * 0x100000000 + hrValues[1],
hrValues[2]
];
};
}
function setupMemoryUsage(_memoryUsage) {
const memValues = new Float64Array(4);
process.memoryUsage = function memoryUsage() {
_memoryUsage(memValues);
return {
rss: memValues[0],
heapTotal: memValues[1],
heapUsed: memValues[2],
external: memValues[3]
};
};
}
function setupConfig(_source) {
// NativeModule._source
// used for `process.config`, but not a real module
const config = _source.config;
delete _source.config;
process.config = JSON.parse(config, function(key, value) {
if (value === 'true') return true;
if (value === 'false') return false;
return value;
});
}
function setupKillAndExit() {
process.exit = function(code) {
if (code || code === 0)
process.exitCode = code;
if (!process._exiting) {
process._exiting = true;
process.emit('exit', process.exitCode || 0);
}
process.reallyExit(process.exitCode || 0);
};
process.kill = function(pid, sig) {
var err;
// eslint-disable-next-line eqeqeq
if (pid != (pid | 0)) {
throw new ERR_INVALID_ARG_TYPE('pid', 'number', pid);
}
// preserve null signal
if (sig === (sig | 0)) {
err = process._kill(pid, sig);
} else {
sig = sig || 'SIGTERM';
if (constants[sig]) {
err = process._kill(pid, constants[sig]);
} else {
throw new ERR_UNKNOWN_SIGNAL(sig);
}
}
if (err)
throw errnoException(err, 'kill');
return true;
};
}
function setupSignalHandlers() {
if (!isMainThread) {
// Worker threads don't receive signals.
return;
}
const signalWraps = Object.create(null);
let Signal;
function isSignal(event) {
return typeof event === 'string' && constants[event] !== undefined;
}
// Detect presence of a listener for the special signal types
process.on('newListener', function(type) {
if (isSignal(type) && signalWraps[type] === undefined) {
if (Signal === undefined)
Signal = process.binding('signal_wrap').Signal;
const wrap = new Signal();
wrap.unref();
wrap.onsignal = process.emit.bind(process, type, type);
const signum = constants[type];
const err = wrap.start(signum);
if (err) {
wrap.close();
throw errnoException(err, 'uv_signal_start');
}
signalWraps[type] = wrap;
}
});
process.on('removeListener', function(type) {
if (signalWraps[type] !== undefined && this.listenerCount(type) === 0) {
signalWraps[type].close();
delete signalWraps[type];
}
});
}
function setupChannel() {
// If we were spawned with env NODE_CHANNEL_FD then load that up and
// start parsing data from that stream.
if (process.env.NODE_CHANNEL_FD) {
const fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
assert(fd >= 0);
// Make sure it's not accidentally inherited by child processes.
delete process.env.NODE_CHANNEL_FD;
require('child_process')._forkChild(fd);
assert(process.send);
}
}
function setupRawDebug(_rawDebug) {
process._rawDebug = function() {
_rawDebug(util.format.apply(null, arguments));
};
}
function setupUncaughtExceptionCapture(exceptionHandlerState,
shouldAbortOnUncaughtToggle) {
// shouldAbortOnUncaughtToggle is a typed array for faster
// communication with JS.
process.setUncaughtExceptionCaptureCallback = function(fn) {
if (fn === null) {
exceptionHandlerState.captureFn = fn;
shouldAbortOnUncaughtToggle[0] = 1;
return;
}
if (typeof fn !== 'function') {
throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'null'], fn);
}
if (exceptionHandlerState.captureFn !== null) {
throw new ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET();
}
exceptionHandlerState.captureFn = fn;
shouldAbortOnUncaughtToggle[0] = 0;
};
process.hasUncaughtExceptionCaptureCallback = function() {
return exceptionHandlerState.captureFn !== null;
};
}
module.exports = {
setup_cpuUsage,
setup_hrtime,
setupMemoryUsage,
setupConfig,
setupKillAndExit,
setupSignalHandlers,
setupChannel,
setupRawDebug,
setupUncaughtExceptionCapture
};