'use strict'; const errors = require('internal/errors'); const util = require('util'); const constants = process.binding('constants').os.signals; const assert = process.assert = function(x, msg) { if (!x) throw new errors.Error('ERR_ASSERTION', msg || 'assertion error'); }; function setup_performance() { require('perf_hooks'); } // Set up the process.cpuUsage() function. function setup_cpuUsage() { // Get the native function, which will be replaced with a JS version. const _cpuUsage = process.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)) { throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'preValue.user', 'Number'); } if (!previousValueIsValid(prevValue.system)) { throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'preValue.system', 'Number'); } } // Call the native function to get the current values. const errmsg = _cpuUsage(cpuValues); if (errmsg) { throw new errors.Error('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() { const _hrtime = process.hrtime; const hrValues = new Uint32Array(3); process.hrtime = function hrtime(time) { _hrtime(hrValues); if (time !== undefined) { if (!Array.isArray(time)) { throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'time', 'Array', time); } if (time.length !== 2) { throw new errors.TypeError('ERR_INVALID_ARRAY_LENGTH', '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() { const memoryUsage_ = process.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 var config = _source.config; delete _source.config; // strip the gyp comment line at the beginning config = config.split('\n') .slice(1) .join('\n') .replace(/"/g, '\\"') .replace(/'/g, '"'); 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 errors.TypeError('ERR_INVALID_ARG_TYPE', 'pid', 'Number'); } // preserve null signal if (0 === sig) { err = process._kill(pid, 0); } else { sig = sig || 'SIGTERM'; if (constants[sig]) { err = process._kill(pid, constants[sig]); } else { throw new errors.TypeError('ERR_UNKNOWN_SIGNAL', sig); } } if (err) throw util._errnoException(err, 'kill'); return true; }; } function setupSignalHandlers() { // Load events module in order to access prototype elements on process like // process.addListener. const signalWraps = {}; 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, listener) { if (isSignal(type) && !signalWraps.hasOwnProperty(type)) { const Signal = process.binding('signal_wrap').Signal; const wrap = new Signal(); wrap.unref(); wrap.onsignal = function() { process.emit(type); }; const signum = constants[type]; const err = wrap.start(signum); if (err) { wrap.close(); throw util._errnoException(err, 'uv_signal_start'); } signalWraps[type] = wrap; } }); process.on('removeListener', function(type, listener) { if (signalWraps.hasOwnProperty(type) && 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; const cp = require('child_process'); // Load tcp_wrap to avoid situation where we might immediately receive // a message. // FIXME is this really necessary? process.binding('tcp_wrap'); cp._forkChild(fd); assert(process.send); } } function setupRawDebug() { const rawDebug = process._rawDebug; process._rawDebug = function() { rawDebug(util.format.apply(null, arguments)); }; } module.exports = { setup_performance, setup_cpuUsage, setup_hrtime, setupMemoryUsage, setupConfig, setupKillAndExit, setupSignalHandlers, setupChannel, setupRawDebug };