Skip to content

Commit

Permalink
lib,src: refactor src/node.js into internal files
Browse files Browse the repository at this point in the history
PR-URL: #5103
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
Fishrock123 committed Mar 22, 2016
1 parent 2c67289 commit 015cef2
Show file tree
Hide file tree
Showing 9 changed files with 618 additions and 588 deletions.
186 changes: 186 additions & 0 deletions lib/internal/process.js
Original file line number Diff line number Diff line change
@@ -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));
};
}
157 changes: 157 additions & 0 deletions lib/internal/process/next_tick.js
Original file line number Diff line number Diff line change
@@ -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]++;
}
}
Loading

0 comments on commit 015cef2

Please sign in to comment.