diff options
author | Trevor Norris <trev.norris@gmail.com> | 2014-11-11 16:48:34 -0800 |
---|---|---|
committer | Trevor Norris <trev.norris@gmail.com> | 2014-12-05 04:33:26 -0800 |
commit | b6559553a42b05ad793e1ea755e252b230be6212 (patch) | |
tree | 9f9902f36a06e32425bee69b9c970d6d8a5b6fd3 /lib | |
parent | 0674cbaceb81ba1130355aa7eb8e6389824e3cc4 (diff) | |
download | node-b6559553a42b05ad793e1ea755e252b230be6212.tar.gz |
src: remove Async Listener
Async Listener was the name of the user-facing JS API, and is being
completely removed. Instead low level hooks directly into the mechanism
that AL used will be introduced in a future commit.
PR-URL: https://github.com/joyent/node/pull/8110
Signed-off-by: Trevor Norris <trev.norris@gmail.com>
Reviewed-by: Fedor Indutny <fedor@indutny.com>
Reviewed-by: Alexis Campailla <alexis@janeasystems.com>
Reviewed-by: Julien Gilli <julien.gilli@joyent.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/repl.js | 3 | ||||
-rw-r--r-- | lib/timers.js | 53 | ||||
-rw-r--r-- | lib/tracing.js | 395 |
3 files changed, 4 insertions, 447 deletions
diff --git a/lib/repl.js b/lib/repl.js index 578f99ed2..a8fa060c5 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -72,8 +72,7 @@ exports.writer = util.inspect; exports._builtinLibs = ['assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', 'os', 'path', 'punycode', 'querystring', 'readline', 'stream', - 'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc', - 'tracing']; + 'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc']; function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) { diff --git a/lib/timers.js b/lib/timers.js index 3039b49f2..68e3e65e9 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -30,21 +30,6 @@ var TIMEOUT_MAX = 2147483647; // 2^31-1 var debug = require('util').debuglog('timer'); -var tracing = require('tracing'); -var asyncFlags = tracing._asyncFlags; -var runAsyncQueue = tracing._runAsyncQueue; -var loadAsyncQueue = tracing._loadAsyncQueue; -var unloadAsyncQueue = tracing._unloadAsyncQueue; - -// Same as in AsyncListener in env.h -var kHasListener = 0; - -// Do a little housekeeping. -delete tracing._asyncFlags; -delete tracing._runAsyncQueue; -delete tracing._loadAsyncQueue; -delete tracing._unloadAsyncQueue; - // IDLE TIMEOUTS // @@ -59,11 +44,6 @@ delete tracing._unloadAsyncQueue; // value = list var lists = {}; -// Make Timer as monomorphic as possible. -Timer.prototype._asyncQueue = undefined; -Timer.prototype._asyncData = undefined; -Timer.prototype._asyncFlags = 0; - // the main function - creates lists on demand and the watchers associated // with them. function insert(item, msecs) { @@ -100,7 +80,7 @@ function listOnTimeout() { var now = Timer.now(); debug('now: %s', now); - var diff, first, hasQueue, threw; + var diff, first, threw; while (first = L.peek(list)) { diff = now - first._idleStart; if (diff < msecs) { @@ -122,19 +102,13 @@ function listOnTimeout() { if (domain && domain._disposed) continue; - hasQueue = !!first._asyncQueue; - try { - if (hasQueue) - loadAsyncQueue(first); if (domain) domain.enter(); threw = true; first._onTimeout(); if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(first); threw = false; } finally { if (threw) { @@ -204,11 +178,6 @@ exports.active = function(item) { L.append(list, item); } } - // Whether or not a new TimerWrap needed to be created, this should run - // for each item. This way each "item" (i.e. timer) can properly have - // their own domain assigned. - if (asyncFlags[kHasListener] > 0) - runAsyncQueue(item); }; @@ -354,18 +323,15 @@ L.init(immediateQueue); function processImmediate() { var queue = immediateQueue; - var domain, hasQueue, immediate; + var domain, immediate; immediateQueue = {}; L.init(immediateQueue); while (L.isEmpty(queue) === false) { immediate = L.shift(queue); - hasQueue = !!immediate._asyncQueue; domain = immediate.domain; - if (hasQueue) - loadAsyncQueue(immediate); if (domain) domain.enter(); @@ -389,8 +355,6 @@ function processImmediate() { if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(immediate); } // Only round-trip to C++ land if we have to. Calling clearImmediate() on an @@ -406,11 +370,8 @@ function Immediate() { } Immediate.prototype.domain = undefined; Immediate.prototype._onImmediate = undefined; -Immediate.prototype._asyncQueue = undefined; -Immediate.prototype._asyncData = undefined; Immediate.prototype._idleNext = undefined; Immediate.prototype._idlePrev = undefined; -Immediate.prototype._asyncFlags = 0; exports.setImmediate = function(callback) { @@ -436,9 +397,6 @@ exports.setImmediate = function(callback) { process._immediateCallback = processImmediate; } - // setImmediates are handled more like nextTicks. - if (asyncFlags[kHasListener] > 0) - runAsyncQueue(immediate); if (process.domain) immediate.domain = process.domain; @@ -472,7 +430,7 @@ function unrefTimeout() { debug('unrefTimer fired'); - var diff, domain, first, hasQueue, threw; + var diff, domain, first, threw; while (first = L.peek(unrefList)) { diff = now - first._idleStart; @@ -490,11 +448,8 @@ function unrefTimeout() { if (!first._onTimeout) continue; if (domain && domain._disposed) continue; - hasQueue = !!first._asyncQueue; try { - if (hasQueue) - loadAsyncQueue(first); if (domain) domain.enter(); threw = true; debug('unreftimer firing timeout'); @@ -502,8 +457,6 @@ function unrefTimeout() { threw = false; if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(first); } finally { if (threw) process.nextTick(unrefTimeout); } diff --git a/lib/tracing.js b/lib/tracing.js deleted file mode 100644 index 49d0dec35..000000000 --- a/lib/tracing.js +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var EventEmitter = require('events'); -var v8binding, process; - -// This needs to be loaded early, and before the "process" object is made -// global. So allow src/node.js to pass the process object in during -// initialization. -exports._nodeInitialization = function nodeInitialization(pobj) { - process = pobj; - v8binding = process.binding('v8'); - - // Finish setting up the v8 Object. - v8.getHeapStatistics = v8binding.getHeapStatistics; - - // Part of the AsyncListener setup to share objects/callbacks with the - // native layer. - process._setupAsyncListener(asyncFlags, - runAsyncQueue, - loadAsyncQueue, - unloadAsyncQueue); - - // Do a little housekeeping. - delete exports._nodeInitialization; -}; - - -// v8 - -var v8 = exports.v8 = new EventEmitter(); - - -function emitGC(before, after) { - v8.emit('gc', before, after); -} - - -v8.on('newListener', function(name) { - if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - v8binding.startGarbageCollectionTracking(emitGC); - } -}); - - -v8.on('removeListener', function(name) { - if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - v8binding.stopGarbageCollectionTracking(); - } -}); - - -// AsyncListener - -// new Array() is used here because it is more efficient for sparse -// arrays. Please *do not* change these to simple bracket notation. - -// Track the active queue of AsyncListeners that have been added. -var asyncQueue = new Array(); - -// Keep the stack of all contexts that have been loaded in the -// execution chain of asynchronous events. -var contextStack = new Array(); -var currentContext = undefined; - -// Incremental uid for new AsyncListener instances. -var alUid = 0; - -// Stateful flags shared with Environment for quick JS/C++ -// communication. -var asyncFlags = {}; - -// Prevent accidentally suppressed thrown errors from before/after. -var inAsyncTick = false; - -// To prevent infinite recursion when an error handler also throws -// flag when an error is currenly being handled. -var inErrorTick = false; - -// Needs to be the same as src/env.h -var kHasListener = 0; - -// Flags to determine what async listeners are available. -var HAS_CREATE_AL = 1 << 0; -var HAS_BEFORE_AL = 1 << 1; -var HAS_AFTER_AL = 1 << 2; -var HAS_ERROR_AL = 1 << 3; - -// _errorHandler is scoped so it's also accessible by _fatalException. -exports._errorHandler = errorHandler; - -// Needs to be accessible from lib/timers.js so they know when async -// listeners are currently in queue. They'll be cleaned up once -// references there are made. -exports._asyncFlags = asyncFlags; -exports._runAsyncQueue = runAsyncQueue; -exports._loadAsyncQueue = loadAsyncQueue; -exports._unloadAsyncQueue = unloadAsyncQueue; - -// Public API. -exports.createAsyncListener = createAsyncListener; -exports.addAsyncListener = addAsyncListener; -exports.removeAsyncListener = removeAsyncListener; - -// Load the currently executing context as the current context, and -// create a new asyncQueue that can receive any added queue items -// during the executing of the callback. -function loadContext(ctx) { - contextStack.push(currentContext); - currentContext = ctx; - - asyncFlags[kHasListener] = 1; -} - -function unloadContext() { - currentContext = contextStack.pop(); - - if (currentContext === undefined && asyncQueue.length === 0) - asyncFlags[kHasListener] = 0; -} - -// Run all the async listeners attached when an asynchronous event is -// instantiated. -function runAsyncQueue(context) { - var queue = new Array(); - var data = new Array(); - var ccQueue, i, queueItem, value; - - context._asyncQueue = queue; - context._asyncData = data; - context._asyncFlags = 0; - - inAsyncTick = true; - - // First run through all callbacks in the currentContext. These may - // add new AsyncListeners to the asyncQueue during execution. Hence - // why they need to be evaluated first. - if (currentContext) { - ccQueue = currentContext._asyncQueue; - context._asyncFlags |= currentContext._asyncFlags; - for (i = 0; i < ccQueue.length; i++) { - queueItem = ccQueue[i]; - queue[queue.length] = queueItem; - if ((queueItem.callback_flags & HAS_CREATE_AL) === 0) { - data[queueItem.uid] = queueItem.data; - continue; - } - value = queueItem.create(queueItem.data); - data[queueItem.uid] = (value === undefined) ? queueItem.data : value; - } - } - - // Then run through all items in the asyncQueue - if (asyncQueue) { - for (i = 0; i < asyncQueue.length; i++) { - queueItem = asyncQueue[i]; - // Quick way to check if an AL instance with the same uid was - // already run from currentContext. - if (data[queueItem.uid] !== undefined) - continue; - queue[queue.length] = queueItem; - context._asyncFlags |= queueItem.callback_flags; - if ((queueItem.callback_flags & HAS_CREATE_AL) === 0) { - data[queueItem.uid] = queueItem.data; - continue; - } - value = queueItem.create(queueItem.data); - data[queueItem.uid] = (value === undefined) ? queueItem.data : value; - } - } - - inAsyncTick = false; -} - -// Load the AsyncListener queue attached to context and run all -// "before" callbacks, if they exist. -function loadAsyncQueue(context) { - loadContext(context); - - if ((context._asyncFlags & HAS_BEFORE_AL) === 0) - return; - - var queue = context._asyncQueue; - var data = context._asyncData; - var i, queueItem; - - inAsyncTick = true; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_BEFORE_AL) > 0) - queueItem.before(context, data[queueItem.uid]); - } - inAsyncTick = false; -} - -// Unload the AsyncListener queue attached to context and run all -// "after" callbacks, if they exist. -function unloadAsyncQueue(context) { - if ((context._asyncFlags & HAS_AFTER_AL) === 0) { - unloadContext(); - return; - } - - var queue = context._asyncQueue; - var data = context._asyncData; - var i, queueItem; - - inAsyncTick = true; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_AFTER_AL) > 0) - queueItem.after(context, data[queueItem.uid]); - } - inAsyncTick = false; - - unloadContext(); -} - -// Handle errors that are thrown while in the context of an -// AsyncListener. If an error is thrown from an AsyncListener -// callback error handlers will be called once more to report -// the error, then the application will die forcefully. -function errorHandler(er) { - if (inErrorTick) - return false; - - var handled = false; - var i, queueItem, threw; - - inErrorTick = true; - - // First process error callbacks from the current context. - if (currentContext && (currentContext._asyncFlags & HAS_ERROR_AL) > 0) { - var queue = currentContext._asyncQueue; - var data = currentContext._asyncData; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_ERROR_AL) === 0) - continue; - try { - threw = true; - // While it would be possible to pass in currentContext, if - // the error is thrown from the "create" callback then there's - // a chance the object hasn't been fully constructed. - handled = queueItem.error(data[queueItem.uid], er) || handled; - threw = false; - } finally { - // If the error callback thew then die quickly. Only allow the - // exit events to be processed. - if (threw) { - process._exiting = true; - process.emit('exit', 1); - } - } - } - } - - // Now process callbacks from any existing queue. - if (asyncQueue) { - for (i = 0; i < asyncQueue.length; i++) { - queueItem = asyncQueue[i]; - if ((queueItem.callback_flags & HAS_ERROR_AL) === 0 || - (data && data[queueItem.uid] !== undefined)) - continue; - try { - threw = true; - handled = queueItem.error(queueItem.data, er) || handled; - threw = false; - } finally { - // If the error callback thew then die quickly. Only allow the - // exit events to be processed. - if (threw) { - process._exiting = true; - process.emit('exit', 1); - } - } - } - } - - inErrorTick = false; - - unloadContext(); - - // TODO(trevnorris): If the error was handled, should the after callbacks - // be fired anyways? - - return handled && !inAsyncTick; -} - -// Instance function of an AsyncListener object. -function AsyncListenerInst(callbacks, data) { - if (typeof callbacks.create === 'function') { - this.create = callbacks.create; - this.callback_flags |= HAS_CREATE_AL; - } - if (typeof callbacks.before === 'function') { - this.before = callbacks.before; - this.callback_flags |= HAS_BEFORE_AL; - } - if (typeof callbacks.after === 'function') { - this.after = callbacks.after; - this.callback_flags |= HAS_AFTER_AL; - } - if (typeof callbacks.error === 'function') { - this.error = callbacks.error; - this.callback_flags |= HAS_ERROR_AL; - } - - this.uid = ++alUid; - this.data = data === undefined ? null : data; -} -AsyncListenerInst.prototype.create = undefined; -AsyncListenerInst.prototype.before = undefined; -AsyncListenerInst.prototype.after = undefined; -AsyncListenerInst.prototype.error = undefined; -AsyncListenerInst.prototype.data = undefined; -AsyncListenerInst.prototype.uid = 0; -AsyncListenerInst.prototype.callback_flags = 0; - -// Create new async listener object. Useful when instantiating a new -// object and want the listener instance, but not add it to the stack. -// If an existing AsyncListenerInst is passed then any new "data" is -// ignored. -function createAsyncListener(callbacks, data) { - if (typeof callbacks !== 'object' || callbacks == null) - throw new TypeError('callbacks argument must be an object'); - - if (callbacks instanceof AsyncListenerInst) - return callbacks; - else - return new AsyncListenerInst(callbacks, data); -} - -// Add a listener to the current queue. -function addAsyncListener(callbacks, data) { - // Fast track if a new AsyncListenerInst has to be created. - if (!(callbacks instanceof AsyncListenerInst)) { - callbacks = createAsyncListener(callbacks, data); - asyncQueue.push(callbacks); - asyncFlags[kHasListener] = 1; - return callbacks; - } - - var inQueue = false; - // The asyncQueue will be small. Probably always <= 3 items. - for (var i = 0; i < asyncQueue.length; i++) { - if (callbacks === asyncQueue[i]) { - inQueue = true; - break; - } - } - - // Make sure the callback doesn't already exist in the queue. - if (!inQueue) { - asyncQueue.push(callbacks); - asyncFlags[kHasListener] = 1; - } - - return callbacks; -} - -// Remove listener from the current queue. Though this will not remove -// the listener from the current context. So callback propagation will -// continue. -function removeAsyncListener(obj) { - for (var i = 0; i < asyncQueue.length; i++) { - if (obj === asyncQueue[i]) { - asyncQueue.splice(i, 1); - break; - } - } - - if (asyncQueue.length > 0 || currentContext !== undefined) - asyncFlags[kHasListener] = 1; - else - asyncFlags[kHasListener] = 0; -} |