mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1044 lines
31 KiB
1044 lines
31 KiB
// Hello, and welcome to hacking node.js!
|
|
//
|
|
// This file is invoked by node::LoadEnvironment in src/node.cc, and is
|
|
// responsible for bootstrapping the node.js core. As special caution is given
|
|
// to the performance of the startup process, many dependencies are invoked
|
|
// lazily.
|
|
|
|
'use strict';
|
|
|
|
(function(process) {
|
|
this.global = this;
|
|
|
|
function startup() {
|
|
var EventEmitter = NativeModule.require('events');
|
|
process._eventsCount = 0;
|
|
|
|
Object.setPrototypeOf(process, Object.create(EventEmitter.prototype, {
|
|
constructor: {
|
|
value: process.constructor
|
|
}
|
|
}));
|
|
|
|
EventEmitter.call(process);
|
|
|
|
process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated
|
|
|
|
// do this good and early, since it handles errors.
|
|
startup.processFatal();
|
|
|
|
startup.globalVariables();
|
|
startup.globalTimeouts();
|
|
startup.globalConsole();
|
|
|
|
startup.processAssert();
|
|
startup.processConfig();
|
|
startup.processNextTick();
|
|
startup.processPromises();
|
|
startup.processStdio();
|
|
startup.processKillAndExit();
|
|
startup.processSignalHandlers();
|
|
startup.processCpuUsage();
|
|
|
|
// Do not initialize channel in debugger agent, it deletes env variable
|
|
// and the main thread won't see it.
|
|
if (process.argv[1] !== '--debug-agent')
|
|
startup.processChannel();
|
|
|
|
startup.processRawDebug();
|
|
|
|
process.argv[0] = process.execPath;
|
|
|
|
// There are various modes that Node can run in. The most common two
|
|
// are running from a script and running the REPL - but there are a few
|
|
// others like the debugger or running --eval arguments. Here we decide
|
|
// which mode we run in.
|
|
|
|
if (NativeModule.exists('_third_party_main')) {
|
|
// To allow people to extend Node in different ways, this hook allows
|
|
// one to drop a file lib/_third_party_main.js into the build
|
|
// directory which will be executed instead of Node's normal loading.
|
|
process.nextTick(function() {
|
|
NativeModule.require('_third_party_main');
|
|
});
|
|
|
|
} else if (process.argv[1] == 'debug') {
|
|
// Start the debugger agent
|
|
NativeModule.require('_debugger').start();
|
|
|
|
} else if (process.argv[1] == '--debug-agent') {
|
|
// Start the debugger agent
|
|
NativeModule.require('_debug_agent').start();
|
|
|
|
} else if (process.profProcess) {
|
|
NativeModule.require('internal/v8_prof_processor');
|
|
|
|
} else {
|
|
// There is user code to be run
|
|
|
|
// If this is a worker in cluster mode, start up the communication
|
|
// channel. This needs to be done before any user code gets executed
|
|
// (including preload modules).
|
|
if (process.argv[1] && process.env.NODE_UNIQUE_ID) {
|
|
var cluster = NativeModule.require('cluster');
|
|
cluster._setupWorker();
|
|
|
|
// Make sure it's not accidentally inherited by child processes.
|
|
delete process.env.NODE_UNIQUE_ID;
|
|
}
|
|
|
|
if (process._eval != null) {
|
|
// User passed '-e' or '--eval' arguments to Node.
|
|
startup.preloadModules();
|
|
evalScript('[eval]');
|
|
} else if (process.argv[1]) {
|
|
// make process.argv[1] into a full path
|
|
var path = NativeModule.require('path');
|
|
process.argv[1] = path.resolve(process.argv[1]);
|
|
|
|
var Module = NativeModule.require('module');
|
|
|
|
// check if user passed `-c` or `--check` arguments to Node.
|
|
if (process._syntax_check_only != null) {
|
|
var vm = NativeModule.require('vm');
|
|
var fs = NativeModule.require('fs');
|
|
var internalModule = NativeModule.require('internal/module');
|
|
// read the source
|
|
var filename = Module._resolveFilename(process.argv[1]);
|
|
var source = fs.readFileSync(filename, 'utf-8');
|
|
// remove shebang and BOM
|
|
source = internalModule.stripBOM(source.replace(/^\#\!.*/, ''));
|
|
// wrap it
|
|
source = Module.wrap(source);
|
|
// compile the script, this will throw if it fails
|
|
new vm.Script(source, {filename: filename, displayErrors: true});
|
|
process.exit(0);
|
|
}
|
|
|
|
startup.preloadModules();
|
|
if (global.v8debug &&
|
|
process.execArgv.some(function(arg) {
|
|
return arg.match(/^--debug-brk(=[0-9]*)?$/);
|
|
})) {
|
|
|
|
// XXX Fix this terrible hack!
|
|
//
|
|
// Give the client program a few ticks to connect.
|
|
// Otherwise, there's a race condition where `node debug foo.js`
|
|
// will not be able to connect in time to catch the first
|
|
// breakpoint message on line 1.
|
|
//
|
|
// A better fix would be to somehow get a message from the
|
|
// global.v8debug object about a connection, and runMain when
|
|
// that occurs. --isaacs
|
|
|
|
var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50;
|
|
setTimeout(Module.runMain, debugTimeout);
|
|
|
|
} else {
|
|
// Main entry point into most programs:
|
|
Module.runMain();
|
|
}
|
|
|
|
} else {
|
|
// If -i or --interactive were passed, or stdin is a TTY.
|
|
if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
|
|
// REPL
|
|
var cliRepl = NativeModule.require('internal/repl');
|
|
cliRepl.createInternalRepl(process.env, function(err, repl) {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
repl.on('exit', function() {
|
|
if (repl._flushing) {
|
|
repl.pause();
|
|
return repl.once('flushHistory', function() {
|
|
process.exit();
|
|
});
|
|
}
|
|
process.exit();
|
|
});
|
|
});
|
|
} else {
|
|
// Read all of stdin - execute it.
|
|
process.stdin.setEncoding('utf8');
|
|
|
|
var code = '';
|
|
process.stdin.on('data', function(d) {
|
|
code += d;
|
|
});
|
|
|
|
process.stdin.on('end', function() {
|
|
process._eval = code;
|
|
evalScript('[stdin]');
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
startup.globalVariables = function() {
|
|
global.process = process;
|
|
global.global = global;
|
|
global.GLOBAL = global;
|
|
global.root = global;
|
|
global.Buffer = NativeModule.require('buffer').Buffer;
|
|
process.domain = null;
|
|
process._exiting = false;
|
|
};
|
|
|
|
startup.globalTimeouts = function() {
|
|
const timers = NativeModule.require('timers');
|
|
global.clearImmediate = timers.clearImmediate;
|
|
global.clearInterval = timers.clearInterval;
|
|
global.clearTimeout = timers.clearTimeout;
|
|
global.setImmediate = timers.setImmediate;
|
|
global.setInterval = timers.setInterval;
|
|
global.setTimeout = timers.setTimeout;
|
|
};
|
|
|
|
startup.globalConsole = function() {
|
|
global.__defineGetter__('console', function() {
|
|
return NativeModule.require('console');
|
|
});
|
|
};
|
|
|
|
|
|
startup._lazyConstants = null;
|
|
|
|
startup.lazyConstants = function() {
|
|
if (!startup._lazyConstants) {
|
|
startup._lazyConstants = process.binding('constants');
|
|
}
|
|
return startup._lazyConstants;
|
|
};
|
|
|
|
startup.processFatal = function() {
|
|
|
|
process._fatalException = function(er) {
|
|
var caught;
|
|
|
|
if (process.domain && process.domain._errorHandler)
|
|
caught = process.domain._errorHandler(er) || caught;
|
|
|
|
if (!caught)
|
|
caught = process.emit('uncaughtException', er);
|
|
|
|
// If someone handled it, then great. otherwise, die in C++ land
|
|
// since that means that we'll exit the process, emit the 'exit' event
|
|
if (!caught) {
|
|
try {
|
|
if (!process._exiting) {
|
|
process._exiting = true;
|
|
process.emit('exit', 1);
|
|
}
|
|
} catch (er) {
|
|
// nothing to be done about it at this point.
|
|
}
|
|
|
|
// if we handled an error, then make sure any ticks get processed
|
|
} else {
|
|
NativeModule.require('timers').setImmediate(process._tickCallback);
|
|
}
|
|
|
|
return caught;
|
|
};
|
|
};
|
|
|
|
var assert;
|
|
startup.processAssert = function() {
|
|
assert = process.assert = function(x, msg) {
|
|
if (!x) throw new Error(msg || 'assertion error');
|
|
};
|
|
};
|
|
|
|
startup.processConfig = function() {
|
|
// used for `process.config`, but not a real module
|
|
var config = NativeModule._source.config;
|
|
delete NativeModule._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;
|
|
|
|
// Intl.v8BreakIterator() would crash w/ fatal error, so throw instead.
|
|
if (value.icu_small &&
|
|
global.hasOwnProperty('Intl') &&
|
|
Intl.hasOwnProperty('v8BreakIterator') &&
|
|
!process.icu_data_dir) {
|
|
const des = Object.getOwnPropertyDescriptor(Intl, 'v8BreakIterator');
|
|
des.value = function v8BreakIterator() {
|
|
throw new Error('v8BreakIterator: full ICU data not installed. ' +
|
|
'See https://github.com/nodejs/node/wiki/Intl');
|
|
};
|
|
Object.defineProperty(Intl, 'v8BreakIterator', des);
|
|
}
|
|
// Don’t let icu_data_dir leak through.
|
|
delete process.icu_data_dir;
|
|
|
|
return value;
|
|
});
|
|
};
|
|
|
|
startup.processCpuUsage = function() {
|
|
// 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 TypeError('value of user property of argument is invalid');
|
|
}
|
|
|
|
if (!previousValueIsValid(prevValue.system)) {
|
|
throw new TypeError(
|
|
'value of system property of argument is invalid');
|
|
}
|
|
}
|
|
|
|
// Call the native function to get the current values.
|
|
const errmsg = _cpuUsage(cpuValues);
|
|
if (errmsg) {
|
|
throw new Error('unable to obtain 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;
|
|
}
|
|
};
|
|
};
|
|
|
|
var addPendingUnhandledRejection;
|
|
var hasBeenNotifiedProperty = new WeakMap();
|
|
startup.processNextTick = function() {
|
|
var nextTickQueue = [];
|
|
var pendingUnhandledRejections = [];
|
|
var microtasksScheduled = false;
|
|
|
|
// Used to run V8's micro task queue.
|
|
var _runMicrotasks = {};
|
|
|
|
// *Must* match Environment::TickInfo::Fields in src/env.h.
|
|
var kIndex = 0;
|
|
var kLength = 1;
|
|
|
|
process.nextTick = nextTick;
|
|
// Needs to be accessible from beyond this scope.
|
|
process._tickCallback = _tickCallback;
|
|
process._tickDomainCallback = _tickDomainCallback;
|
|
|
|
// This tickInfo thing is used so that the C++ code in src/node.cc
|
|
// can have easy access to our nextTick state, and avoid unnecessary
|
|
// calls into JS land.
|
|
const tickInfo = process._setupNextTick(_tickCallback, _runMicrotasks);
|
|
|
|
_runMicrotasks = _runMicrotasks.runMicrotasks;
|
|
|
|
function tickDone() {
|
|
if (tickInfo[kLength] !== 0) {
|
|
if (tickInfo[kLength] <= tickInfo[kIndex]) {
|
|
nextTickQueue = [];
|
|
tickInfo[kLength] = 0;
|
|
} else {
|
|
nextTickQueue.splice(0, tickInfo[kIndex]);
|
|
tickInfo[kLength] = nextTickQueue.length;
|
|
}
|
|
}
|
|
tickInfo[kIndex] = 0;
|
|
}
|
|
|
|
function scheduleMicrotasks() {
|
|
if (microtasksScheduled)
|
|
return;
|
|
|
|
nextTickQueue.push({
|
|
callback: runMicrotasksCallback,
|
|
domain: null
|
|
});
|
|
|
|
tickInfo[kLength]++;
|
|
microtasksScheduled = true;
|
|
}
|
|
|
|
function runMicrotasksCallback() {
|
|
microtasksScheduled = false;
|
|
_runMicrotasks();
|
|
|
|
if (tickInfo[kIndex] < tickInfo[kLength] ||
|
|
emitPendingUnhandledRejections())
|
|
scheduleMicrotasks();
|
|
}
|
|
|
|
// Run callbacks that have no domain.
|
|
// Using domains will cause this to be overridden.
|
|
function _tickCallback() {
|
|
var callback, args, tock;
|
|
|
|
do {
|
|
while (tickInfo[kIndex] < tickInfo[kLength]) {
|
|
tock = nextTickQueue[tickInfo[kIndex]++];
|
|
callback = tock.callback;
|
|
args = tock.args;
|
|
// Using separate callback execution functions helps to limit the
|
|
// scope of DEOPTs caused by using try blocks and allows direct
|
|
// callback invocation with small numbers of arguments to avoid the
|
|
// performance hit associated with using `fn.apply()`
|
|
if (args === undefined) {
|
|
nextTickCallbackWith0Args(callback);
|
|
} else {
|
|
switch (args.length) {
|
|
case 1:
|
|
nextTickCallbackWith1Arg(callback, args[0]);
|
|
break;
|
|
case 2:
|
|
nextTickCallbackWith2Args(callback, args[0], args[1]);
|
|
break;
|
|
case 3:
|
|
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]);
|
|
break;
|
|
default:
|
|
nextTickCallbackWithManyArgs(callback, args);
|
|
}
|
|
}
|
|
if (1e4 < tickInfo[kIndex])
|
|
tickDone();
|
|
}
|
|
tickDone();
|
|
_runMicrotasks();
|
|
emitPendingUnhandledRejections();
|
|
} while (tickInfo[kLength] !== 0);
|
|
}
|
|
|
|
function _tickDomainCallback() {
|
|
var callback, domain, args, tock;
|
|
|
|
do {
|
|
while (tickInfo[kIndex] < tickInfo[kLength]) {
|
|
tock = nextTickQueue[tickInfo[kIndex]++];
|
|
callback = tock.callback;
|
|
domain = tock.domain;
|
|
args = tock.args;
|
|
if (domain)
|
|
domain.enter();
|
|
// Using separate callback execution functions helps to limit the
|
|
// scope of DEOPTs caused by using try blocks and allows direct
|
|
// callback invocation with small numbers of arguments to avoid the
|
|
// performance hit associated with using `fn.apply()`
|
|
if (args === undefined) {
|
|
nextTickCallbackWith0Args(callback);
|
|
} else {
|
|
switch (args.length) {
|
|
case 1:
|
|
nextTickCallbackWith1Arg(callback, args[0]);
|
|
break;
|
|
case 2:
|
|
nextTickCallbackWith2Args(callback, args[0], args[1]);
|
|
break;
|
|
case 3:
|
|
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]);
|
|
break;
|
|
default:
|
|
nextTickCallbackWithManyArgs(callback, args);
|
|
}
|
|
}
|
|
if (1e4 < tickInfo[kIndex])
|
|
tickDone();
|
|
if (domain)
|
|
domain.exit();
|
|
}
|
|
tickDone();
|
|
_runMicrotasks();
|
|
emitPendingUnhandledRejections();
|
|
} while (tickInfo[kLength] !== 0);
|
|
}
|
|
|
|
function nextTickCallbackWith0Args(callback) {
|
|
var threw = true;
|
|
try {
|
|
callback();
|
|
threw = false;
|
|
} finally {
|
|
if (threw)
|
|
tickDone();
|
|
}
|
|
}
|
|
|
|
function nextTickCallbackWith1Arg(callback, arg1) {
|
|
var threw = true;
|
|
try {
|
|
callback(arg1);
|
|
threw = false;
|
|
} finally {
|
|
if (threw)
|
|
tickDone();
|
|
}
|
|
}
|
|
|
|
function nextTickCallbackWith2Args(callback, arg1, arg2) {
|
|
var threw = true;
|
|
try {
|
|
callback(arg1, arg2);
|
|
threw = false;
|
|
} finally {
|
|
if (threw)
|
|
tickDone();
|
|
}
|
|
}
|
|
|
|
function nextTickCallbackWith3Args(callback, arg1, arg2, arg3) {
|
|
var threw = true;
|
|
try {
|
|
callback(arg1, arg2, arg3);
|
|
threw = false;
|
|
} finally {
|
|
if (threw)
|
|
tickDone();
|
|
}
|
|
}
|
|
|
|
function nextTickCallbackWithManyArgs(callback, args) {
|
|
var threw = true;
|
|
try {
|
|
callback.apply(null, args);
|
|
threw = false;
|
|
} finally {
|
|
if (threw)
|
|
tickDone();
|
|
}
|
|
}
|
|
|
|
function TickObject(c, args) {
|
|
this.callback = c;
|
|
this.domain = process.domain || null;
|
|
this.args = args;
|
|
}
|
|
|
|
function nextTick(callback) {
|
|
// on the way out, don't bother. it won't get fired anyway.
|
|
if (process._exiting)
|
|
return;
|
|
|
|
var args;
|
|
if (arguments.length > 1) {
|
|
args = [];
|
|
for (var i = 1; i < arguments.length; i++)
|
|
args.push(arguments[i]);
|
|
}
|
|
|
|
nextTickQueue.push(new TickObject(callback, args));
|
|
tickInfo[kLength]++;
|
|
}
|
|
|
|
function emitPendingUnhandledRejections() {
|
|
var hadListeners = false;
|
|
while (pendingUnhandledRejections.length > 0) {
|
|
var promise = pendingUnhandledRejections.shift();
|
|
var reason = pendingUnhandledRejections.shift();
|
|
if (hasBeenNotifiedProperty.get(promise) === false) {
|
|
hasBeenNotifiedProperty.set(promise, true);
|
|
if (!process.emit('unhandledRejection', reason, promise)) {
|
|
// Nobody is listening.
|
|
// TODO(petkaantonov) Take some default action, see #830
|
|
} else {
|
|
hadListeners = true;
|
|
}
|
|
}
|
|
}
|
|
return hadListeners;
|
|
}
|
|
|
|
addPendingUnhandledRejection = function(promise, reason) {
|
|
pendingUnhandledRejections.push(promise, reason);
|
|
scheduleMicrotasks();
|
|
};
|
|
};
|
|
|
|
startup.processPromises = function() {
|
|
var promiseRejectEvent = process._promiseRejectEvent;
|
|
|
|
function unhandledRejection(promise, reason) {
|
|
hasBeenNotifiedProperty.set(promise, false);
|
|
addPendingUnhandledRejection(promise, reason);
|
|
}
|
|
|
|
function rejectionHandled(promise) {
|
|
var hasBeenNotified = hasBeenNotifiedProperty.get(promise);
|
|
if (hasBeenNotified !== undefined) {
|
|
hasBeenNotifiedProperty.delete(promise);
|
|
if (hasBeenNotified === true) {
|
|
process.nextTick(function() {
|
|
process.emit('rejectionHandled', promise);
|
|
});
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
process._setupPromises(function(event, promise, reason) {
|
|
if (event === promiseRejectEvent.unhandled)
|
|
unhandledRejection(promise, reason);
|
|
else if (event === promiseRejectEvent.handled)
|
|
rejectionHandled(promise);
|
|
else
|
|
NativeModule.require('assert').fail('unexpected PromiseRejectEvent');
|
|
});
|
|
};
|
|
|
|
function evalScript(name) {
|
|
var Module = NativeModule.require('module');
|
|
var path = NativeModule.require('path');
|
|
|
|
try {
|
|
var cwd = process.cwd();
|
|
} catch (e) {
|
|
// getcwd(3) can fail if the current working directory has been deleted.
|
|
// Fall back to the directory name of the (absolute) executable path.
|
|
// It's not really correct but what are the alternatives?
|
|
cwd = path.dirname(process.execPath);
|
|
}
|
|
|
|
var module = new Module(name);
|
|
module.filename = path.join(cwd, name);
|
|
module.paths = Module._nodeModulePaths(cwd);
|
|
var script = process._eval;
|
|
var body = script;
|
|
script = `global.__filename = ${JSON.stringify(name)};\n` +
|
|
'global.exports = exports;\n' +
|
|
'global.module = module;\n' +
|
|
'global.__dirname = __dirname;\n' +
|
|
'global.require = require;\n' +
|
|
'return require("vm").runInThisContext(' +
|
|
`${JSON.stringify(body)}, { filename: ` +
|
|
`${JSON.stringify(name)} });\n`;
|
|
// Defer evaluation for a tick. This is a workaround for deferred
|
|
// events not firing when evaluating scripts from the command line,
|
|
// see https://github.com/nodejs/node/issues/1600.
|
|
process.nextTick(function() {
|
|
var result = module._compile(script, `${name}-wrapper`);
|
|
if (process._print_eval) console.log(result);
|
|
});
|
|
}
|
|
|
|
function createWritableStdioStream(fd) {
|
|
var stream;
|
|
var tty_wrap = process.binding('tty_wrap');
|
|
|
|
// Note stream._type is used for test-module-load-list.js
|
|
|
|
switch (tty_wrap.guessHandleType(fd)) {
|
|
case 'TTY':
|
|
var tty = NativeModule.require('tty');
|
|
stream = new tty.WriteStream(fd);
|
|
stream._type = 'tty';
|
|
break;
|
|
|
|
case 'FILE':
|
|
var fs = NativeModule.require('fs');
|
|
stream = new fs.SyncWriteStream(fd, { autoClose: false });
|
|
stream._type = 'fs';
|
|
break;
|
|
|
|
case 'PIPE':
|
|
case 'TCP':
|
|
var net = NativeModule.require('net');
|
|
stream = new net.Socket({
|
|
fd: fd,
|
|
readable: false,
|
|
writable: true
|
|
});
|
|
stream._type = 'pipe';
|
|
break;
|
|
|
|
default:
|
|
// Probably an error on in uv_guess_handle()
|
|
throw new Error('Implement me. Unknown stream file type!');
|
|
}
|
|
|
|
// For supporting legacy API we put the FD here.
|
|
stream.fd = fd;
|
|
|
|
stream._isStdio = true;
|
|
|
|
return stream;
|
|
}
|
|
|
|
startup.processStdio = function() {
|
|
var stdin, stdout, stderr;
|
|
|
|
process.__defineGetter__('stdout', function() {
|
|
if (stdout) return stdout;
|
|
stdout = createWritableStdioStream(1);
|
|
stdout.destroy = stdout.destroySoon = function(er) {
|
|
er = er || new Error('process.stdout cannot be closed.');
|
|
stdout.emit('error', er);
|
|
};
|
|
if (stdout.isTTY) {
|
|
process.on('SIGWINCH', function() {
|
|
stdout._refreshSize();
|
|
});
|
|
}
|
|
return stdout;
|
|
});
|
|
|
|
process.__defineGetter__('stderr', function() {
|
|
if (stderr) return stderr;
|
|
stderr = createWritableStdioStream(2);
|
|
stderr.destroy = stderr.destroySoon = function(er) {
|
|
er = er || new Error('process.stderr cannot be closed.');
|
|
stderr.emit('error', er);
|
|
};
|
|
if (stderr.isTTY) {
|
|
process.on('SIGWINCH', function() {
|
|
stderr._refreshSize();
|
|
});
|
|
}
|
|
return stderr;
|
|
});
|
|
|
|
process.__defineGetter__('stdin', function() {
|
|
if (stdin) return stdin;
|
|
|
|
var tty_wrap = process.binding('tty_wrap');
|
|
var fd = 0;
|
|
|
|
switch (tty_wrap.guessHandleType(fd)) {
|
|
case 'TTY':
|
|
var tty = NativeModule.require('tty');
|
|
stdin = new tty.ReadStream(fd, {
|
|
highWaterMark: 0,
|
|
readable: true,
|
|
writable: false
|
|
});
|
|
break;
|
|
|
|
case 'FILE':
|
|
var fs = NativeModule.require('fs');
|
|
stdin = new fs.ReadStream(null, { fd: fd, autoClose: false });
|
|
break;
|
|
|
|
case 'PIPE':
|
|
case 'TCP':
|
|
var net = NativeModule.require('net');
|
|
|
|
// It could be that process has been started with an IPC channel
|
|
// sitting on fd=0, in such case the pipe for this fd is already
|
|
// present and creating a new one will lead to the assertion failure
|
|
// in libuv.
|
|
if (process._channel && process._channel.fd === fd) {
|
|
stdin = new net.Socket({
|
|
handle: process._channel,
|
|
readable: true,
|
|
writable: false
|
|
});
|
|
} else {
|
|
stdin = new net.Socket({
|
|
fd: fd,
|
|
readable: true,
|
|
writable: false
|
|
});
|
|
}
|
|
// Make sure the stdin can't be `.end()`-ed
|
|
stdin._writableState.ended = true;
|
|
break;
|
|
|
|
default:
|
|
// Probably an error on in uv_guess_handle()
|
|
throw new Error('Implement me. Unknown stdin file type!');
|
|
}
|
|
|
|
// For supporting legacy API we put the FD here.
|
|
stdin.fd = fd;
|
|
|
|
// stdin starts out life in a paused state, but node doesn't
|
|
// know yet. Explicitly to readStop() it to put it in the
|
|
// not-reading state.
|
|
if (stdin._handle && stdin._handle.readStop) {
|
|
stdin._handle.reading = false;
|
|
stdin._readableState.reading = false;
|
|
stdin._handle.readStop();
|
|
}
|
|
|
|
// if the user calls stdin.pause(), then we need to stop reading
|
|
// immediately, so that the process can close down.
|
|
stdin.on('pause', function() {
|
|
if (!stdin._handle)
|
|
return;
|
|
stdin._readableState.reading = false;
|
|
stdin._handle.reading = false;
|
|
stdin._handle.readStop();
|
|
});
|
|
|
|
return stdin;
|
|
});
|
|
|
|
process.openStdin = function() {
|
|
process.stdin.resume();
|
|
return process.stdin;
|
|
};
|
|
};
|
|
|
|
startup.processKillAndExit = function() {
|
|
|
|
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;
|
|
|
|
if (pid != (pid | 0)) {
|
|
throw new TypeError('invalid pid');
|
|
}
|
|
|
|
// preserve null signal
|
|
if (0 === sig) {
|
|
err = process._kill(pid, 0);
|
|
} else {
|
|
sig = sig || 'SIGTERM';
|
|
if (startup.lazyConstants()[sig] &&
|
|
sig.slice(0, 3) === 'SIG') {
|
|
err = process._kill(pid, startup.lazyConstants()[sig]);
|
|
} else {
|
|
throw new Error(`Unknown signal: ${sig}`);
|
|
}
|
|
}
|
|
|
|
if (err) {
|
|
var errnoException = NativeModule.require('util')._errnoException;
|
|
throw errnoException(err, 'kill');
|
|
}
|
|
|
|
return true;
|
|
};
|
|
};
|
|
|
|
startup.processSignalHandlers = function() {
|
|
// Load events module in order to access prototype elements on process like
|
|
// process.addListener.
|
|
var signalWraps = {};
|
|
|
|
function isSignal(event) {
|
|
return typeof event === 'string' &&
|
|
event.slice(0, 3) === 'SIG' &&
|
|
startup.lazyConstants().hasOwnProperty(event);
|
|
}
|
|
|
|
// Detect presence of a listener for the special signal types
|
|
process.on('newListener', function(type, listener) {
|
|
if (isSignal(type) &&
|
|
!signalWraps.hasOwnProperty(type)) {
|
|
var Signal = process.binding('signal_wrap').Signal;
|
|
var wrap = new Signal();
|
|
|
|
wrap.unref();
|
|
|
|
wrap.onsignal = function() { process.emit(type); };
|
|
|
|
var signum = startup.lazyConstants()[type];
|
|
var err = wrap.start(signum);
|
|
if (err) {
|
|
wrap.close();
|
|
var errnoException = NativeModule.require('util')._errnoException;
|
|
throw 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];
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
startup.processChannel = function() {
|
|
// 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) {
|
|
var 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;
|
|
|
|
var cp = NativeModule.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);
|
|
}
|
|
};
|
|
|
|
|
|
startup.processRawDebug = function() {
|
|
var format = NativeModule.require('util').format;
|
|
var rawDebug = process._rawDebug;
|
|
process._rawDebug = function() {
|
|
rawDebug(format.apply(null, arguments));
|
|
};
|
|
};
|
|
|
|
// Load preload modules
|
|
startup.preloadModules = function() {
|
|
if (process._preload_modules) {
|
|
NativeModule.require('module')._preloadModules(process._preload_modules);
|
|
}
|
|
};
|
|
|
|
// Below you find a minimal module system, which is used to load the node
|
|
// core modules found in lib/*.js. All core modules are compiled into the
|
|
// node binary, so they can be loaded faster.
|
|
|
|
var ContextifyScript = process.binding('contextify').ContextifyScript;
|
|
function runInThisContext(code, options) {
|
|
var script = new ContextifyScript(code, options);
|
|
return script.runInThisContext();
|
|
}
|
|
|
|
function NativeModule(id) {
|
|
this.filename = `${id}.js`;
|
|
this.id = id;
|
|
this.exports = {};
|
|
this.loaded = false;
|
|
this.loading = true;
|
|
}
|
|
|
|
NativeModule._source = process.binding('natives');
|
|
NativeModule._cache = {};
|
|
|
|
NativeModule.require = function(id) {
|
|
if (id == 'native_module') {
|
|
return NativeModule;
|
|
}
|
|
|
|
var cached = NativeModule.getCached(id);
|
|
if (cached && (cached.loaded || cached.loading)) {
|
|
return cached.exports;
|
|
}
|
|
|
|
if (!NativeModule.exists(id)) {
|
|
throw new Error(`No such native module ${id}`);
|
|
}
|
|
|
|
process.moduleLoadList.push(`NativeModule ${id}`);
|
|
|
|
var nativeModule = new NativeModule(id);
|
|
|
|
nativeModule.cache();
|
|
nativeModule.compile();
|
|
|
|
return nativeModule.exports;
|
|
};
|
|
|
|
NativeModule.getCached = function(id) {
|
|
return NativeModule._cache[id];
|
|
};
|
|
|
|
NativeModule.exists = function(id) {
|
|
return NativeModule._source.hasOwnProperty(id);
|
|
};
|
|
|
|
const EXPOSE_INTERNALS = process.execArgv.some(function(arg) {
|
|
return arg.match(/^--expose[-_]internals$/);
|
|
});
|
|
|
|
if (EXPOSE_INTERNALS) {
|
|
NativeModule.nonInternalExists = NativeModule.exists;
|
|
|
|
NativeModule.isInternal = function(id) {
|
|
return false;
|
|
};
|
|
} else {
|
|
NativeModule.nonInternalExists = function(id) {
|
|
return NativeModule.exists(id) && !NativeModule.isInternal(id);
|
|
};
|
|
|
|
NativeModule.isInternal = function(id) {
|
|
return id.startsWith('internal/');
|
|
};
|
|
}
|
|
|
|
|
|
NativeModule.getSource = function(id) {
|
|
return NativeModule._source[id];
|
|
};
|
|
|
|
NativeModule.wrap = function(script) {
|
|
return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
|
|
};
|
|
|
|
NativeModule.wrapper = [
|
|
'(function (exports, require, module, __filename, __dirname) { ',
|
|
'\n});'
|
|
];
|
|
|
|
NativeModule.prototype.compile = function() {
|
|
var source = NativeModule.getSource(this.id);
|
|
source = NativeModule.wrap(source);
|
|
|
|
this.loading = true;
|
|
try {
|
|
var fn = runInThisContext(source, {
|
|
filename: this.filename,
|
|
lineOffset: 0
|
|
});
|
|
fn(this.exports, NativeModule.require, this, this.filename);
|
|
|
|
this.loaded = true;
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
};
|
|
|
|
NativeModule.prototype.cache = function() {
|
|
NativeModule._cache[this.id] = this;
|
|
};
|
|
|
|
startup();
|
|
});
|
|
|