summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJeremiah Senkpiel <fishrock123@rocketmail.com>2016-03-15 16:13:52 -0400
committerJeremiah Senkpiel <fishrock123@rocketmail.com>2016-03-22 19:20:01 -0400
commit015cef25eb30b8ac447fa855dd434f4da327d884 (patch)
treed8ad529429cf89027a3198ff24f961cb562dfc1c /lib
parent2c672891e11618b0ef401012d97524f43564cbb3 (diff)
downloadandroid-node-v8-015cef25eb30b8ac447fa855dd434f4da327d884.tar.gz
android-node-v8-015cef25eb30b8ac447fa855dd434f4da327d884.tar.bz2
android-node-v8-015cef25eb30b8ac447fa855dd434f4da327d884.zip
lib,src: refactor src/node.js into internal files
PR-URL: https://github.com/nodejs/node/pull/5103 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/internal/process.js186
-rw-r--r--lib/internal/process/next_tick.js157
-rw-r--r--lib/internal/process/promises.js61
-rw-r--r--lib/internal/process/stdio.js161
4 files changed, 565 insertions, 0 deletions
diff --git a/lib/internal/process.js b/lib/internal/process.js
new file mode 100644
index 0000000000..17ca5bc326
--- /dev/null
+++ b/lib/internal/process.js
@@ -0,0 +1,186 @@
+'use strict';
+
+var _lazyConstants = null;
+
+function lazyConstants() {
+ if (!_lazyConstants) {
+ _lazyConstants = process.binding('constants');
+ }
+ return _lazyConstants;
+}
+
+exports.setup_hrtime = setup_hrtime;
+exports.setupConfig = setupConfig;
+exports.setupKillAndExit = setupKillAndExit;
+exports.setupSignalHandlers = setupSignalHandlers;
+exports.setupChannel = setupChannel;
+exports.setupRawDebug = setupRawDebug;
+
+
+const assert = process.assert = function(x, msg) {
+ if (!x) throw new Error(msg || 'assertion error');
+};
+
+
+function setup_hrtime() {
+ const _hrtime = process.hrtime;
+ const hrValues = new Uint32Array(3);
+
+ process.hrtime = function hrtime(ar) {
+ _hrtime(hrValues);
+
+ if (typeof ar !== 'undefined') {
+ if (Array.isArray(ar)) {
+ const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - ar[0];
+ const nsec = hrValues[2] - ar[1];
+ return [nsec < 0 ? sec - 1 : sec, nsec < 0 ? nsec + 1e9 : nsec];
+ }
+
+ throw new TypeError('process.hrtime() only accepts an Array tuple');
+ }
+
+ return [
+ hrValues[0] * 0x100000000 + hrValues[1],
+ hrValues[2]
+ ];
+ };
+}
+
+
+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;
+
+ 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 (lazyConstants()[sig] &&
+ sig.slice(0, 3) === 'SIG') {
+ err = process._kill(pid, lazyConstants()[sig]);
+ } else {
+ throw new Error(`Unknown signal: ${sig}`);
+ }
+ }
+
+ if (err) {
+ var errnoException = require('util')._errnoException;
+ throw errnoException(err, 'kill');
+ }
+
+ return true;
+ };
+}
+
+
+function setupSignalHandlers() {
+ // 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' &&
+ 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 = lazyConstants()[type];
+ var err = wrap.start(signum);
+ if (err) {
+ wrap.close();
+ var errnoException = 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];
+ }
+ });
+}
+
+
+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) {
+ 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 = 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() {
+ var format = require('util').format;
+ var rawDebug = process._rawDebug;
+ process._rawDebug = function() {
+ rawDebug(format.apply(null, arguments));
+ };
+}
diff --git a/lib/internal/process/next_tick.js b/lib/internal/process/next_tick.js
new file mode 100644
index 0000000000..529645aa8d
--- /dev/null
+++ b/lib/internal/process/next_tick.js
@@ -0,0 +1,157 @@
+'use strict';
+
+exports.setup = setupNextTick;
+
+function setupNextTick() {
+ const promises = require('internal/process/promises');
+ const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
+ var nextTickQueue = [];
+ 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();
+ }
+
+ function _combinedTickCallback(args, callback) {
+ if (args === undefined) {
+ callback();
+ } else {
+ switch (args.length) {
+ case 1:
+ callback(args[0]);
+ break;
+ case 2:
+ callback(args[0], args[1]);
+ break;
+ case 3:
+ callback(args[0], args[1], args[2]);
+ break;
+ default:
+ callback.apply(null, args);
+ }
+ }
+ }
+
+ // 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 allows direct
+ // callback invocation with small numbers of arguments to avoid the
+ // performance hit associated with using `fn.apply()`
+ _combinedTickCallback(args, callback);
+ 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 allows direct
+ // callback invocation with small numbers of arguments to avoid the
+ // performance hit associated with using `fn.apply()`
+ _combinedTickCallback(args, callback);
+ if (1e4 < tickInfo[kIndex])
+ tickDone();
+ if (domain)
+ domain.exit();
+ }
+ tickDone();
+ _runMicrotasks();
+ emitPendingUnhandledRejections();
+ } while (tickInfo[kLength] !== 0);
+ }
+
+ function TickObject(c, args) {
+ this.callback = c;
+ this.domain = process.domain || null;
+ this.args = args;
+ }
+
+ function nextTick(callback) {
+ if (typeof callback !== 'function')
+ throw new TypeError('callback is not a function');
+ // on the way out, don't bother. it won't get fired anyway.
+ if (process._exiting)
+ return;
+
+ var args;
+ if (arguments.length > 1) {
+ args = new Array(arguments.length - 1);
+ for (var i = 1; i < arguments.length; i++)
+ args[i - 1] = arguments[i];
+ }
+
+ nextTickQueue.push(new TickObject(callback, args));
+ tickInfo[kLength]++;
+ }
+}
diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js
new file mode 100644
index 0000000000..165bf3319e
--- /dev/null
+++ b/lib/internal/process/promises.js
@@ -0,0 +1,61 @@
+'use strict';
+
+const promiseRejectEvent = process._promiseRejectEvent;
+const hasBeenNotifiedProperty = new WeakMap();
+const pendingUnhandledRejections = [];
+
+exports.setup = setupPromises;
+
+function setupPromises(scheduleMicrotasks) {
+ process._setupPromises(function(event, promise, reason) {
+ if (event === promiseRejectEvent.unhandled)
+ unhandledRejection(promise, reason);
+ else if (event === promiseRejectEvent.handled)
+ rejectionHandled(promise);
+ else
+ require('assert').fail('unexpected 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);
+ });
+ }
+
+ }
+ }
+
+ 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;
+ }
+
+ function addPendingUnhandledRejection(promise, reason) {
+ pendingUnhandledRejections.push(promise, reason);
+ scheduleMicrotasks();
+ }
+
+ return emitPendingUnhandledRejections;
+}
diff --git a/lib/internal/process/stdio.js b/lib/internal/process/stdio.js
new file mode 100644
index 0000000000..55689069ff
--- /dev/null
+++ b/lib/internal/process/stdio.js
@@ -0,0 +1,161 @@
+'use strict';
+
+exports.setup = setupStdio;
+
+function setupStdio() {
+ 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 = require('tty');
+ stdin = new tty.ReadStream(fd, {
+ highWaterMark: 0,
+ readable: true,
+ writable: false
+ });
+ break;
+
+ case 'FILE':
+ var fs = require('fs');
+ stdin = new fs.ReadStream(null, { fd: fd, autoClose: false });
+ break;
+
+ case 'PIPE':
+ case 'TCP':
+ var net = 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;
+ };
+}
+
+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 = require('tty');
+ stream = new tty.WriteStream(fd);
+ stream._type = 'tty';
+ break;
+
+ case 'FILE':
+ var fs = require('fs');
+ stream = new fs.SyncWriteStream(fd, { autoClose: false });
+ stream._type = 'fs';
+ break;
+
+ case 'PIPE':
+ case 'TCP':
+ var net = 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;
+}