src: move AsyncListener from process to tracing
The AsyncListener API has been moved into the "tracing" module in order to keep the process object free from unnecessary clutter. Signed-off-by: Timothy J Fontaine <tjfontaine@gmail.com>
This commit is contained in:
parent
d9e1e4c661
commit
6cbfcdad46
@ -684,219 +684,4 @@ a diff reading, useful for benchmarks and measuring intervals:
|
||||
// benchmark took 1000000527 nanoseconds
|
||||
}, 1000);
|
||||
|
||||
|
||||
## Async Listeners
|
||||
|
||||
<!-- type=misc -->
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
357
lib/tracing.js
357
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;
|
||||
}
|
||||
|
352
src/node.js
352
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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');
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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() { });
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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() { });
|
||||
});
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user