diff --git a/doc/api/process.markdown b/doc/api/process.markdown index 1a66807d81..6b9051c283 100644 --- a/doc/api/process.markdown +++ b/doc/api/process.markdown @@ -684,219 +684,4 @@ a diff reading, useful for benchmarks and measuring intervals: // benchmark took 1000000527 nanoseconds }, 1000); - -## Async Listeners - - - - Stability: 1 - Experimental - -The `AsyncListener` API is the JavaScript interface for the `AsyncWrap` -class which allows developers to be notified about key events in the -lifetime of an asynchronous event. Node performs a lot of asynchronous -events internally, and significant use of this API may have a -**significant performance impact** on your application. - - -## process.createAsyncListener(callbacksObj[, userData]) - -* `callbacksObj` {Object} Contains optional callbacks that will fire at -specific times in the life cycle of the asynchronous event. -* `userData` {Value} a value that will be passed to all callbacks. - -Returns a constructed `AsyncListener` object. - -To begin capturing asynchronous events pass either the `callbacksObj` or -and existing `AsyncListener` instance to [`process.addAsyncListener()`][]. -The same `AsyncListener` instance can only be added once to the active -queue, and subsequent attempts to add the instance will be ignored. - -To stop capturing pass the `AsyncListener` instance to -[`process.removeAsyncListener()`][]. This does _not_ mean the -`AsyncListener` previously added will stop triggering callbacks. Once -attached to an asynchronous event it will persist with the lifetime of the -asynchronous call stack. - -Explanation of function parameters: - - -`callbacksObj`: An `Object` which may contain three optional fields: - -* `create(userData)`: A `Function` called when an asynchronous -event is instantiated. If a `Value` is returned then it will be attached -to the event and overwrite any value that had been passed to -`process.createAsyncListener()`'s `userData` argument. If an initial -`userData` was passed when created, then `create()` will -receive that as a function argument. - -* `before(context, userData)`: A `Function` that is called immediately -before the asynchronous callback is about to run. It will be passed both -the `context` (i.e. `this`) of the calling function and the `userData` -either returned from `create()` or passed during construction (if -either occurred). - -* `after(context, userData)`: A `Function` called immediately after -the asynchronous event's callback has run. Note this will not be called -if the callback throws and the error is not handled. - -* `error(userData, error)`: A `Function` called if the event's -callback threw. If this registered callback returns `true` then Node will -assume the error has been properly handled and resume execution normally. -When multiple `error()` callbacks have been registered only **one** of -those callbacks needs to return `true` for `AsyncListener` to accept that -the error has been handled, but all `error()` callbacks will always be run. - -`userData`: A `Value` (i.e. anything) that will be, by default, -attached to all new event instances. This will be overwritten if a `Value` -is returned by `create()`. - -Here is an example of overwriting the `userData`: - - process.createAsyncListener({ - create: function listener(value) { - // value === true - return false; - }, { - before: function before(context, value) { - // value === false - } - }, true); - -**Note:** The [EventEmitter][], while used to emit status of an asynchronous -event, is not itself asynchronous. So `create()` will not fire when -an event is added, and `before`/`after` will not fire when emitted -callbacks are called. - - -## process.addAsyncListener(callbacksObj[, userData]) -## process.addAsyncListener(asyncListener) - -Returns a constructed `AsyncListener` object and immediately adds it to -the listening queue to begin capturing asynchronous events. - -Function parameters can either be the same as -[`process.createAsyncListener()`][], or a constructed `AsyncListener` -object. - -Example usage for capturing errors: - - var fs = require('fs'); - - var cntr = 0; - var key = process.addAsyncListener({ - create: function onCreate() { - return { uid: cntr++ }; - }, - before: function onBefore(context, storage) { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'uid: ' + storage.uid + ' is about to run\n'); - }, - after: function onAfter(context, storage) { - fs.writeSync(1, 'uid: ' + storage.uid + ' ran\n'); - }, - error: function onError(storage, err) { - // Handle known errors - if (err.message === 'everything is fine') { - fs.writeSync(1, 'handled error just threw:\n'); - fs.writeSync(1, err.stack + '\n'); - return true; - } - } - }); - - process.nextTick(function() { - throw new Error('everything is fine'); - }); - - // Output: - // uid: 0 is about to run - // handled error just threw: - // Error: really, it's ok - // at /tmp/test2.js:27:9 - // at process._tickCallback (node.js:583:11) - // at Function.Module.runMain (module.js:492:11) - // at startup (node.js:123:16) - // at node.js:1012:3 - -## process.removeAsyncListener(asyncListener) - -Removes the `AsyncListener` from the listening queue. - -Removing the `AsyncListener` from the active queue does _not_ mean the -`asyncListener` callbacks will cease to fire on the events they've been -registered. Subsequently, any asynchronous events fired during the -execution of a callback will also have the same `asyncListener` callbacks -attached for future execution. For example: - - var fs = require('fs'); - - var key = process.createAsyncListener({ - create: function asyncListener() { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'You summoned me?\n'); - } - }); - - // We want to begin capturing async events some time in the future. - setTimeout(function() { - process.addAsyncListener(key); - - // Perform a few additional async events. - setTimeout(function() { - setImmediate(function() { - process.nextTick(function() { }); - }); - }); - - // Removing the listener doesn't mean to stop capturing events that - // have already been added. - process.removeAsyncListener(key); - }, 100); - - // Output: - // You summoned me? - // You summoned me? - // You summoned me? - // You summoned me? - -The fact that we logged 4 asynchronous events is an implementation detail -of Node's [Timers][]. - -To stop capturing from a specific asynchronous event stack -`process.removeAsyncListener()` must be called from within the call -stack itself. For example: - - var fs = require('fs'); - - var key = process.createAsyncListener({ - create: function asyncListener() { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'You summoned me?\n'); - } - }); - - // We want to begin capturing async events some time in the future. - setTimeout(function() { - process.addAsyncListener(key); - - // Perform a few additional async events. - setImmediate(function() { - // Stop capturing from this call stack. - process.removeAsyncListener(key); - - process.nextTick(function() { }); - }); - }, 100); - - // Output: - // You summoned me? - -The user must be explicit and always pass the `AsyncListener` they wish -to remove. It is not possible to simply remove all listeners at once. - - [EventEmitter]: events.html#events_class_events_eventemitter -[Timers]: timers.html -[`process.createAsyncListener()`]: #process_process_createasynclistener_asynclistener_callbacksobj_storagevalue -[`process.addAsyncListener()`]: #process_process_addasynclistener_asynclistener -[`process.removeAsyncListener()`]: #process_process_removeasynclistener_asynclistener diff --git a/doc/api/tracing.markdown b/doc/api/tracing.markdown index 1791cbd9fc..92e6809a04 100644 --- a/doc/api/tracing.markdown +++ b/doc/api/tracing.markdown @@ -58,4 +58,216 @@ Returns an object with the following properties } ``` + +# Async Listeners + +The `AsyncListener` API is the JavaScript interface for the `AsyncWrap` +class which allows developers to be notified about key events in the +lifetime of an asynchronous event. Node performs a lot of asynchronous +events internally, and significant use of this API may have a +**significant performance impact** on your application. + + +## tracing.createAsyncListener(callbacksObj[, userData]) + +* `callbacksObj` {Object} Contains optional callbacks that will fire at +specific times in the life cycle of the asynchronous event. +* `userData` {Value} a value that will be passed to all callbacks. + +Returns a constructed `AsyncListener` object. + +To begin capturing asynchronous events pass either the `callbacksObj` or +pass an existing `AsyncListener` instance to [`tracing.addAsyncListener()`][]. +The same `AsyncListener` instance can only be added once to the active +queue, and subsequent attempts to add the instance will be ignored. + +To stop capturing pass the `AsyncListener` instance to +[`tracing.removeAsyncListener()`][]. This does _not_ mean the +`AsyncListener` previously added will stop triggering callbacks. Once +attached to an asynchronous event it will persist with the lifetime of the +asynchronous call stack. + +Explanation of function parameters: + + +`callbacksObj`: An `Object` which may contain several optional fields: + +* `create(userData)`: A `Function` called when an asynchronous +event is instantiated. If a `Value` is returned then it will be attached +to the event and overwrite any value that had been passed to +`tracing.createAsyncListener()`'s `userData` argument. If an initial +`userData` was passed when created, then `create()` will +receive that as a function argument. + +* `before(context, userData)`: A `Function` that is called immediately +before the asynchronous callback is about to run. It will be passed both +the `context` (i.e. `this`) of the calling function and the `userData` +either returned from `create()` or passed during construction (if +either occurred). + +* `after(context, userData)`: A `Function` called immediately after +the asynchronous event's callback has run. Note this will not be called +if the callback throws and the error is not handled. + +* `error(userData, error)`: A `Function` called if the event's +callback threw. If this registered callback returns `true` then Node will +assume the error has been properly handled and resume execution normally. +When multiple `error()` callbacks have been registered only **one** of +those callbacks needs to return `true` for `AsyncListener` to accept that +the error has been handled, but all `error()` callbacks will always be run. + +`userData`: A `Value` (i.e. anything) that will be, by default, +attached to all new event instances. This will be overwritten if a `Value` +is returned by `create()`. + +Here is an example of overwriting the `userData`: + + tracing.createAsyncListener({ + create: function listener(value) { + // value === true + return false; + }, { + before: function before(context, value) { + // value === false + } + }, true); + +**Note:** The [EventEmitter][], while used to emit status of an asynchronous +event, is not itself asynchronous. So `create()` will not fire when +an event is added, and `before()`/`after()` will not fire when emitted +callbacks are called. + + +## tracing.addAsyncListener(callbacksObj[, userData]) +## tracing.addAsyncListener(asyncListener) + +Returns a constructed `AsyncListener` object and immediately adds it to +the listening queue to begin capturing asynchronous events. + +Function parameters can either be the same as +[`tracing.createAsyncListener()`][], or a constructed `AsyncListener` +object. + +Example usage for capturing errors: + + var fs = require('fs'); + + var cntr = 0; + var key = tracing.addAsyncListener({ + create: function onCreate() { + return { uid: cntr++ }; + }, + before: function onBefore(context, storage) { + // Write directly to stdout or we'll enter a recursive loop + fs.writeSync(1, 'uid: ' + storage.uid + ' is about to run\n'); + }, + after: function onAfter(context, storage) { + fs.writeSync(1, 'uid: ' + storage.uid + ' ran\n'); + }, + error: function onError(storage, err) { + // Handle known errors + if (err.message === 'everything is fine') { + // Writing to stderr this time. + fs.writeSync(2, 'handled error just threw:\n'); + fs.writeSync(2, err.stack + '\n'); + return true; + } + } + }); + + process.nextTick(function() { + throw new Error('everything is fine'); + }); + + // Output: + // uid: 0 is about to run + // handled error just threw: + // Error: really, it's ok + // at /tmp/test2.js:27:9 + // at process._tickCallback (node.js:583:11) + // at Function.Module.runMain (module.js:492:11) + // at startup (node.js:123:16) + // at node.js:1012:3 + +## tracing.removeAsyncListener(asyncListener) + +Removes the `AsyncListener` from the listening queue. + +Removing the `AsyncListener` from the active queue does _not_ mean the +`asyncListener` callbacks will cease to fire on the events they've been +registered. Subsequently, any asynchronous events fired during the +execution of a callback will also have the same `asyncListener` callbacks +attached for future execution. For example: + + var fs = require('fs'); + + var key = tracing.createAsyncListener({ + create: function asyncListener() { + // Write directly to stdout or we'll enter a recursive loop + fs.writeSync(1, 'You summoned me?\n'); + } + }); + + // We want to begin capturing async events some time in the future. + setTimeout(function() { + tracing.addAsyncListener(key); + + // Perform a few additional async events. + setTimeout(function() { + setImmediate(function() { + process.nextTick(function() { }); + }); + }); + + // Removing the listener doesn't mean to stop capturing events that + // have already been added. + tracing.removeAsyncListener(key); + }, 100); + + // Output: + // You summoned me? + // You summoned me? + // You summoned me? + // You summoned me? + +The fact that we logged 4 asynchronous events is an implementation detail +of Node's [Timers][]. + +To stop capturing from a specific asynchronous event stack +`tracing.removeAsyncListener()` must be called from within the call +stack itself. For example: + + var fs = require('fs'); + + var key = tracing.createAsyncListener({ + create: function asyncListener() { + // Write directly to stdout or we'll enter a recursive loop + fs.writeSync(1, 'You summoned me?\n'); + } + }); + + // We want to begin capturing async events some time in the future. + setTimeout(function() { + tracing.addAsyncListener(key); + + // Perform a few additional async events. + setImmediate(function() { + // Stop capturing from this call stack. + tracing.removeAsyncListener(key); + + process.nextTick(function() { }); + }); + }, 100); + + // Output: + // You summoned me? + +The user must be explicit and always pass the `AsyncListener` they wish +to remove. It is not possible to simply remove all listeners at once. + + [EventEmitter]: events.html#events_class_events_eventemitter +[Timers]: timers.html +[`tracing.createAsyncListener()`]: #tracing_tracing_createasynclistener_asynclistener_callbacksobj_storagevalue +[`tracing.addAsyncListener()`]: #tracing_tracing_addasynclistener_asynclistener +[`tracing.removeAsyncListener()`]: #tracing_tracing_removeasynclistener_asynclistener diff --git a/lib/timers.js b/lib/timers.js index df46e8bb5e..644d4c301c 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -30,19 +30,20 @@ var TIMEOUT_MAX = 2147483647; // 2^31-1 var debug = require('util').debuglog('timer'); -var asyncFlags = process._asyncFlags; -var runAsyncQueue = process._runAsyncQueue; -var loadAsyncQueue = process._loadAsyncQueue; -var unloadAsyncQueue = process._unloadAsyncQueue; +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 process._asyncFlags; -delete process._runAsyncQueue; -delete process._loadAsyncQueue; -delete process._unloadAsyncQueue; +delete tracing._asyncFlags; +delete tracing._runAsyncQueue; +delete tracing._loadAsyncQueue; +delete tracing._unloadAsyncQueue; // IDLE TIMEOUTS diff --git a/lib/tracing.js b/lib/tracing.js index 2609630741..75dd52f2a5 100644 --- a/lib/tracing.js +++ b/lib/tracing.js @@ -20,7 +20,31 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. var EventEmitter = require('events'); -var binding = process.binding('v8'); +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(); @@ -32,16 +56,341 @@ function emitGC(before, after) { v8.on('newListener', function(name) { if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - binding.startGarbageCollectionTracking(emitGC); + v8binding.startGarbageCollectionTracking(emitGC); } }); v8.on('removeListener', function(name) { if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - binding.stopGarbageCollectionTracking(); + v8binding.stopGarbageCollectionTracking(); } }); -v8.getHeapStatistics = binding.getHeapStatistics; +// 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; +var kWatchedProviders = 1; + +// 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, item, 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; +} diff --git a/src/node.js b/src/node.js index 7fe714e14e..c9fcb4f445 100644 --- a/src/node.js +++ b/src/node.js @@ -26,7 +26,6 @@ // of the startup process, so many dependencies are invoked lazily. (function(process) { this.global = this; - var _errorHandler; function startup() { var EventEmitter = NativeModule.require('events').EventEmitter; @@ -40,6 +39,9 @@ process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated + // Setup the tracing module + NativeModule.require('tracing')._nodeInitialization(process); + // do this good and early, since it handles errors. startup.processFatal(); @@ -47,7 +49,6 @@ startup.globalTimeouts(); startup.globalConsole(); - startup.processAsyncListener(); startup.processAssert(); startup.processConfig(); startup.processNextTick(); @@ -220,6 +221,11 @@ }; startup.processFatal = function() { + var tracing = NativeModule.require('tracing'); + var _errorHandler = tracing._errorHandler; + // Cleanup + delete tracing._errorHandler; + process._fatalException = function(er) { // First run through error handlers from asyncListener. var caught = _errorHandler(er); @@ -255,339 +261,6 @@ }; }; - startup.processAsyncListener = function() { - // 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; - var kWatchedProviders = 1; - - // 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. - _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. - process._asyncFlags = asyncFlags; - process._runAsyncQueue = runAsyncQueue; - process._loadAsyncQueue = loadAsyncQueue; - process._unloadAsyncQueue = unloadAsyncQueue; - - // Public API. - process.createAsyncListener = createAsyncListener; - process.addAsyncListener = addAsyncListener; - process.removeAsyncListener = removeAsyncListener; - - // Setup shared objects/callbacks with native layer. - process._setupAsyncListener(asyncFlags, - runAsyncQueue, - loadAsyncQueue, - unloadAsyncQueue); - - // 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, item, 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; - } - }; - var assert; startup.processAssert = function() { assert = process.assert = function(x, msg) { @@ -611,11 +284,12 @@ }; startup.processNextTick = function() { + var tracing = NativeModule.require('tracing'); var nextTickQueue = []; - var asyncFlags = process._asyncFlags; - var _runAsyncQueue = process._runAsyncQueue; - var _loadAsyncQueue = process._loadAsyncQueue; - var _unloadAsyncQueue = process._unloadAsyncQueue; + var asyncFlags = tracing._asyncFlags; + var _runAsyncQueue = tracing._runAsyncQueue; + var _loadAsyncQueue = tracing._loadAsyncQueue; + var _unloadAsyncQueue = tracing._unloadAsyncQueue; // This tickInfo thing is used so that the C++ code in src/node.cc // can have easy accesss to our nextTick state, and avoid unnecessary diff --git a/test/simple/test-asynclistener-error-multiple-handled.js b/test/simple/test-asynclistener-error-multiple-handled.js index e4fdf0d321..576ce58e4c 100644 --- a/test/simple/test-asynclistener-error-multiple-handled.js +++ b/test/simple/test-asynclistener-error-multiple-handled.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var active = null; var cntr = 0; @@ -49,16 +50,16 @@ var asyncNoHandleError1 = { }; var listeners = [ - process.addAsyncListener(asyncNoHandleError0), - process.addAsyncListener(asyncNoHandleError1) + tracing.addAsyncListener(asyncNoHandleError0), + tracing.addAsyncListener(asyncNoHandleError1) ]; process.nextTick(function() { throw new Error(); }); -process.removeAsyncListener(listeners[0]); -process.removeAsyncListener(listeners[1]); +tracing.removeAsyncListener(listeners[0]); +tracing.removeAsyncListener(listeners[1]); process.on('exit', function(code) { // If the exit code isn't ok then return early to throw the stack that diff --git a/test/simple/test-asynclistener-error-multiple-mix.js b/test/simple/test-asynclistener-error-multiple-mix.js index 05e46b4656..83716bc281 100644 --- a/test/simple/test-asynclistener-error-multiple-mix.js +++ b/test/simple/test-asynclistener-error-multiple-mix.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var results = []; var asyncNoHandleError = { @@ -37,8 +38,8 @@ var asyncHandleError = { }; var listeners = [ - process.addAsyncListener(asyncHandleError), - process.addAsyncListener(asyncNoHandleError) + tracing.addAsyncListener(asyncHandleError), + tracing.addAsyncListener(asyncNoHandleError) ]; // Even if an error handler returns true, both should fire. @@ -46,8 +47,8 @@ process.nextTick(function() { throw new Error(); }); -process.removeAsyncListener(listeners[0]); -process.removeAsyncListener(listeners[1]); +tracing.removeAsyncListener(listeners[0]); +tracing.removeAsyncListener(listeners[1]); process.on('exit', function(code) { // If the exit code isn't ok then return early to throw the stack that diff --git a/test/simple/test-asynclistener-error-multiple-unhandled.js b/test/simple/test-asynclistener-error-multiple-unhandled.js index aaf635c4e7..33afaaa81b 100644 --- a/test/simple/test-asynclistener-error-multiple-unhandled.js +++ b/test/simple/test-asynclistener-error-multiple-unhandled.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); function onAsync0() { return 0; @@ -45,8 +46,8 @@ var asyncNoHandleError1 = { }; var listeners = [ - process.addAsyncListener(asyncNoHandleError0), - process.addAsyncListener(asyncNoHandleError1) + tracing.addAsyncListener(asyncNoHandleError0), + tracing.addAsyncListener(asyncNoHandleError1) ]; var uncaughtFired = false; @@ -71,7 +72,7 @@ process.on('exit', function(code) { // Need to remove the async listeners or tests will always pass for (var i = 0; i < listeners.length; i++) - process.removeAsyncListener(listeners[i]); + tracing.removeAsyncListener(listeners[i]); assert.ok(uncaughtFired); console.log('ok'); diff --git a/test/simple/test-asynclistener-error-net.js b/test/simple/test-asynclistener-error-net.js index 2aee160aa4..26a337a504 100644 --- a/test/simple/test-asynclistener-error-net.js +++ b/test/simple/test-asynclistener-error-net.js @@ -24,6 +24,7 @@ var assert = require('assert'); var dns = require('dns'); var fs = require('fs'); var net = require('net'); +var tracing = require('tracing'); var errorMsgs = []; var caught = 0; @@ -45,10 +46,10 @@ var callbacksObj = { } }; -var listener = process.addAsyncListener(callbacksObj); +var listener = tracing.addAsyncListener(callbacksObj); process.on('exit', function(code) { - process.removeAsyncListener(listener); + tracing.removeAsyncListener(listener); if (code > 0) return; diff --git a/test/simple/test-asynclistener-error-throw-in-after.js b/test/simple/test-asynclistener-error-throw-in-after.js index 4c20e7ac83..3eb02e165d 100644 --- a/test/simple/test-asynclistener-error-throw-in-after.js +++ b/test/simple/test-asynclistener-error-throw-in-after.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var once = 0; @@ -37,7 +38,7 @@ var handlers = { } } -var key = process.addAsyncListener(handlers); +var key = tracing.addAsyncListener(handlers); var uncaughtFired = false; process.on('uncaughtException', function(err) { @@ -48,7 +49,7 @@ process.on('uncaughtException', function(err) { process.nextTick(function() { }); -process.removeAsyncListener(key); +tracing.removeAsyncListener(key); process.on('exit', function(code) { // If the exit code isn't ok then return early to throw the stack that diff --git a/test/simple/test-asynclistener-error-throw-in-before-multiple.js b/test/simple/test-asynclistener-error-throw-in-before-multiple.js index 628ef9301e..b9aecf3977 100644 --- a/test/simple/test-asynclistener-error-throw-in-before-multiple.js +++ b/test/simple/test-asynclistener-error-throw-in-before-multiple.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var once = 0; @@ -50,8 +51,8 @@ var handlers1 = { } var listeners = [ - process.addAsyncListener(handlers), - process.addAsyncListener(handlers1) + tracing.addAsyncListener(handlers), + tracing.addAsyncListener(handlers1) ]; var uncaughtFired = false; @@ -65,7 +66,7 @@ process.on('uncaughtException', function(err) { process.nextTick(function() { }); for (var i = 0; i < listeners.length; i++) - process.removeAsyncListener(listeners[i]); + tracing.removeAsyncListener(listeners[i]); process.on('exit', function(code) { // If the exit code isn't ok then return early to throw the stack that diff --git a/test/simple/test-asynclistener-error-throw-in-before.js b/test/simple/test-asynclistener-error-throw-in-before.js index e6fb37bb76..fb6b6eeeca 100644 --- a/test/simple/test-asynclistener-error-throw-in-before.js +++ b/test/simple/test-asynclistener-error-throw-in-before.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var once = 0; @@ -37,7 +38,7 @@ var handlers = { } } -var key = process.addAsyncListener(handlers); +var key = tracing.addAsyncListener(handlers); var uncaughtFired = false; process.on('uncaughtException', function(err) { @@ -49,7 +50,7 @@ process.on('uncaughtException', function(err) { process.nextTick(function() { }); -process.removeAsyncListener(key); +tracing.removeAsyncListener(key); process.on('exit', function(code) { // If the exit code isn't ok then return early to throw the stack that diff --git a/test/simple/test-asynclistener-error-throw-in-error.js b/test/simple/test-asynclistener-error-throw-in-error.js index bca9b08ee1..c66d688fbe 100644 --- a/test/simple/test-asynclistener-error-throw-in-error.js +++ b/test/simple/test-asynclistener-error-throw-in-error.js @@ -22,6 +22,7 @@ var common = require('../common'); var assert = require('assert'); var spawn = require('child_process').spawn; +var tracing = require('tracing'); var checkStr = 'WRITTEN ON EXIT'; @@ -34,7 +35,7 @@ else function runChild() { var cntr = 0; - var key = process.addAsyncListener({ + var key = tracing.addAsyncListener({ error: function onError() { cntr++; throw new Error('onError'); diff --git a/test/simple/test-asynclistener-error.js b/test/simple/test-asynclistener-error.js index 8ad217fcb6..6e5f31b034 100644 --- a/test/simple/test-asynclistener-error.js +++ b/test/simple/test-asynclistener-error.js @@ -24,9 +24,10 @@ var assert = require('assert'); var dns = require('dns'); var fs = require('fs'); var net = require('net'); +var tracing = require('tracing'); -var addListener = process.addAsyncListener; -var removeListener = process.removeAsyncListener; +var addListener = tracing.addAsyncListener; +var removeListener = tracing.removeAsyncListener; var errorMsgs = []; var currentMsg = ''; var caught = 0; @@ -46,7 +47,7 @@ var callbacksObj = { } }; -var listener = process.createAsyncListener(callbacksObj); +var listener = tracing.createAsyncListener(callbacksObj); process.on('exit', function(code) { removeListener(listener); diff --git a/test/simple/test-asynclistener-multi-timeout.js b/test/simple/test-asynclistener-multi-timeout.js index 2f81fdbab3..9af4820545 100644 --- a/test/simple/test-asynclistener-multi-timeout.js +++ b/test/simple/test-asynclistener-multi-timeout.js @@ -21,9 +21,10 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); -var addListener = process.addAsyncListener; -var removeListener = process.removeAsyncListener; +var addListener = tracing.addAsyncListener; +var removeListener = tracing.removeAsyncListener; var caught = []; var expect = []; @@ -35,7 +36,7 @@ var callbacksObj = { } }; -var listener = process.createAsyncListener(callbacksObj); +var listener = tracing.createAsyncListener(callbacksObj); process.on('exit', function(code) { removeListener(listener); diff --git a/test/simple/test-asynclistener-remove-add-in-before.js b/test/simple/test-asynclistener-remove-add-in-before.js index b03a86fa2e..af0bc78e0e 100644 --- a/test/simple/test-asynclistener-remove-add-in-before.js +++ b/test/simple/test-asynclistener-remove-add-in-before.js @@ -21,26 +21,27 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var val; var callbacks = { create: function() { return 42; }, before: function() { - process.removeAsyncListener(listener); - process.addAsyncListener(listener); + tracing.removeAsyncListener(listener); + tracing.addAsyncListener(listener); }, after: function(context, storage) { val = storage; } }; -var listener = process.addAsyncListener(callbacks); +var listener = tracing.addAsyncListener(callbacks); process.nextTick(function() {}); process.on('exit', function(status) { - process.removeAsyncListener(listener); + tracing.removeAsyncListener(listener); assert.equal(status, 0); assert.equal(val, 42); }); diff --git a/test/simple/test-asynclistener-remove-before.js b/test/simple/test-asynclistener-remove-before.js index e919c25a45..bc306dbc3c 100644 --- a/test/simple/test-asynclistener-remove-before.js +++ b/test/simple/test-asynclistener-remove-before.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var set = 0; var asyncNoHandleError = { @@ -32,9 +33,9 @@ var asyncNoHandleError = { } } -var key = process.addAsyncListener(asyncNoHandleError); +var key = tracing.addAsyncListener(asyncNoHandleError); -process.removeAsyncListener(key); +tracing.removeAsyncListener(key); process.nextTick(function() { }); diff --git a/test/simple/test-asynclistener-remove-in-before.js b/test/simple/test-asynclistener-remove-in-before.js index e8ba77078e..06f470ce07 100644 --- a/test/simple/test-asynclistener-remove-in-before.js +++ b/test/simple/test-asynclistener-remove-in-before.js @@ -21,22 +21,23 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var done = false; var callbacks = { before: function() { - process.removeAsyncListener(listener); + tracing.removeAsyncListener(listener); }, after: function() { done = true; } }; -var listener = process.addAsyncListener(callbacks); +var listener = tracing.addAsyncListener(callbacks); process.nextTick(function() {}); process.on('exit', function(status) { - process.removeAsyncListener(listener); + tracing.removeAsyncListener(listener); assert.equal(status, 0); assert.ok(done); }); diff --git a/test/simple/test-asynclistener-remove-inflight-error.js b/test/simple/test-asynclistener-remove-inflight-error.js index 77bb391a8f..1b9150152a 100644 --- a/test/simple/test-asynclistener-remove-inflight-error.js +++ b/test/simple/test-asynclistener-remove-inflight-error.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var set = 0; var asyncNoHandleError = { @@ -29,13 +30,13 @@ var asyncNoHandleError = { } } -var key = process.addAsyncListener(asyncNoHandleError); +var key = tracing.addAsyncListener(asyncNoHandleError); process.nextTick(function() { throw 1; }); -process.removeAsyncListener(key); +tracing.removeAsyncListener(key); var uncaughtFired = false; process.on('uncaughtException', function() { diff --git a/test/simple/test-asynclistener-remove-inflight.js b/test/simple/test-asynclistener-remove-inflight.js index 07961a548d..a21b1923f4 100644 --- a/test/simple/test-asynclistener-remove-inflight.js +++ b/test/simple/test-asynclistener-remove-inflight.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var set = 0; var asyncNoHandleError = { @@ -32,11 +33,11 @@ var asyncNoHandleError = { } } -var key = process.addAsyncListener(asyncNoHandleError); +var key = tracing.addAsyncListener(asyncNoHandleError); process.nextTick(function() { }); -process.removeAsyncListener(key); +tracing.removeAsyncListener(key); process.on('exit', function(code) { // If the exit code isn't ok then return early to throw the stack that diff --git a/test/simple/test-asynclistener-run-error-once.js b/test/simple/test-asynclistener-run-error-once.js index 9a090aad7e..cd2703f56f 100644 --- a/test/simple/test-asynclistener-run-error-once.js +++ b/test/simple/test-asynclistener-run-error-once.js @@ -22,9 +22,10 @@ var common = require('../common'); var assert = require('assert'); var net = require('net'); +var tracing = require('tracing'); var cntr = 0; -var al = process.addAsyncListener({ +var al = tracing.addAsyncListener({ error: function(stor, er) { cntr++; process._rawDebug('Handling error: ' + er.message); @@ -33,7 +34,7 @@ var al = process.addAsyncListener({ }); process.on('exit', function(status) { - process.removeAsyncListener(al); + tracing.removeAsyncListener(al); assert.equal(status, 0); assert.equal(cntr, 1); diff --git a/test/simple/test-asynclistener-run-inst-once.js b/test/simple/test-asynclistener-run-inst-once.js index 167473be34..b1492528ee 100644 --- a/test/simple/test-asynclistener-run-inst-once.js +++ b/test/simple/test-asynclistener-run-inst-once.js @@ -21,9 +21,10 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); var cntr = 0; -var al = process.createAsyncListener({ +var al = tracing.createAsyncListener({ create: function() { cntr++; }, }); @@ -32,12 +33,12 @@ process.on('exit', function() { console.log('ok'); }); -process.addAsyncListener(al); +tracing.addAsyncListener(al); process.nextTick(function() { - process.addAsyncListener(al); + tracing.addAsyncListener(al); process.nextTick(function() { - process.addAsyncListener(al); + tracing.addAsyncListener(al); process.nextTick(function() { process.nextTick(function() { }); }); diff --git a/test/simple/test-asynclistener-throw-before-infinite-recursion.js b/test/simple/test-asynclistener-throw-before-infinite-recursion.js index 9d4d03dc63..fdbb50be17 100644 --- a/test/simple/test-asynclistener-throw-before-infinite-recursion.js +++ b/test/simple/test-asynclistener-throw-before-infinite-recursion.js @@ -21,6 +21,7 @@ var common = require('../common'); var assert = require('assert'); +var tracing = require('tracing'); // If there is an uncaughtException listener then the error thrown from // "before" will be considered handled, thus calling setImmediate to @@ -31,7 +32,7 @@ var assert = require('assert'); var cntr = 0; -process.addAsyncListener({ +tracing.addAsyncListener({ before: function() { if (++cntr > 1) { // Can't throw since uncaughtException will also catch that. diff --git a/test/simple/test-asynclistener.js b/test/simple/test-asynclistener.js index 313a3df543..4c29ec9054 100644 --- a/test/simple/test-asynclistener.js +++ b/test/simple/test-asynclistener.js @@ -24,9 +24,10 @@ var assert = require('assert'); var net = require('net'); var fs = require('fs'); var dgram = require('dgram'); +var tracing = require('tracing'); -var addListener = process.addAsyncListener; -var removeListener = process.removeAsyncListener; +var addListener = tracing.addAsyncListener; +var removeListener = tracing.removeAsyncListener; var actualAsync = 0; var expectAsync = 0; @@ -36,7 +37,7 @@ var callbacks = { } }; -var listener = process.createAsyncListener(callbacks); +var listener = tracing.createAsyncListener(callbacks); process.on('exit', function() { process._rawDebug('expected', expectAsync);