Skip to content

Commit 0d60ab3

Browse files
trevnorrispiscisaureus
authored andcommitted
src: remove Async Listener
Async Listener was the name of the user-facing JS API, and is being completely removed. Instead low level hooks directly into the mechanism that AL used will be introduced in a future commit. PR-URL: nodejs/node-v0.x-archive#8110 Signed-off-by: Trevor Norris <[email protected]> Reviewed-by: Fedor Indutny <[email protected]> Reviewed-by: Alexis Campailla <[email protected]> Reviewed-by: Julien Gilli <[email protected]>
1 parent 4d94658 commit 0d60ab3

28 files changed

+8
-2371
lines changed

doc/api/tracing.markdown

+1-223
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,6 @@
55
The tracing module is designed for instrumenting your Node application. It is
66
not meant for general purpose use.
77

8-
***Be very careful with callbacks used in conjunction with this module***
9-
10-
Many of these callbacks interact directly with asynchronous subsystems in a
11-
synchronous fashion. That is to say, you may be in a callback where a call to
12-
`console.log()` could result in an infinite recursive loop. Also of note, many
13-
of these callbacks are in hot execution code paths. That is to say your
14-
callbacks are executed quite often in the normal operation of Node, so be wary
15-
of doing CPU bound or synchronous workloads in these functions. Consider a ring
16-
buffer and a timer to defer processing.
17-
188
`require('tracing')` to use this module.
199

2010
## v8
@@ -73,216 +63,4 @@ v8.setFlagsFromString('--trace_gc');
7363
setTimeout(function() { v8.setFlagsFromString('--notrace_gc'); }, 60e3);
7464
```
7565

76-
77-
# Async Listeners
78-
79-
The `AsyncListener` API is the JavaScript interface for the `AsyncWrap`
80-
class which allows developers to be notified about key events in the
81-
lifetime of an asynchronous event. Node performs a lot of asynchronous
82-
events internally, and significant use of this API may have a
83-
**significant performance impact** on your application.
84-
85-
86-
## tracing.createAsyncListener(callbacksObj[, userData])
87-
88-
* `callbacksObj` {Object} Contains optional callbacks that will fire at
89-
specific times in the life cycle of the asynchronous event.
90-
* `userData` {Value} a value that will be passed to all callbacks.
91-
92-
Returns a constructed `AsyncListener` object.
93-
94-
To begin capturing asynchronous events pass either the `callbacksObj` or
95-
pass an existing `AsyncListener` instance to [`tracing.addAsyncListener()`][].
96-
The same `AsyncListener` instance can only be added once to the active
97-
queue, and subsequent attempts to add the instance will be ignored.
98-
99-
To stop capturing pass the `AsyncListener` instance to
100-
[`tracing.removeAsyncListener()`][]. This does _not_ mean the
101-
`AsyncListener` previously added will stop triggering callbacks. Once
102-
attached to an asynchronous event it will persist with the lifetime of the
103-
asynchronous call stack.
104-
105-
Explanation of function parameters:
106-
107-
108-
`callbacksObj`: An `Object` which may contain several optional fields:
109-
110-
* `create(userData)`: A `Function` called when an asynchronous
111-
event is instantiated. If a `Value` is returned then it will be attached
112-
to the event and overwrite any value that had been passed to
113-
`tracing.createAsyncListener()`'s `userData` argument. If an initial
114-
`userData` was passed when created, then `create()` will
115-
receive that as a function argument.
116-
117-
* `before(context, userData)`: A `Function` that is called immediately
118-
before the asynchronous callback is about to run. It will be passed both
119-
the `context` (i.e. `this`) of the calling function and the `userData`
120-
either returned from `create()` or passed during construction (if
121-
either occurred).
122-
123-
* `after(context, userData)`: A `Function` called immediately after
124-
the asynchronous event's callback has run. Note this will not be called
125-
if the callback throws and the error is not handled.
126-
127-
* `error(userData, error)`: A `Function` called if the event's
128-
callback threw. If this registered callback returns `true` then Node will
129-
assume the error has been properly handled and resume execution normally.
130-
When multiple `error()` callbacks have been registered only **one** of
131-
those callbacks needs to return `true` for `AsyncListener` to accept that
132-
the error has been handled, but all `error()` callbacks will always be run.
133-
134-
`userData`: A `Value` (i.e. anything) that will be, by default,
135-
attached to all new event instances. This will be overwritten if a `Value`
136-
is returned by `create()`.
137-
138-
Here is an example of overwriting the `userData`:
139-
140-
tracing.createAsyncListener({
141-
create: function listener(value) {
142-
// value === true
143-
return false;
144-
}, {
145-
before: function before(context, value) {
146-
// value === false
147-
}
148-
}, true);
149-
150-
**Note:** The [EventEmitter][], while used to emit status of an asynchronous
151-
event, is not itself asynchronous. So `create()` will not fire when
152-
an event is added, and `before()`/`after()` will not fire when emitted
153-
callbacks are called.
154-
155-
156-
## tracing.addAsyncListener(callbacksObj[, userData])
157-
## tracing.addAsyncListener(asyncListener)
158-
159-
Returns a constructed `AsyncListener` object and immediately adds it to
160-
the listening queue to begin capturing asynchronous events.
161-
162-
Function parameters can either be the same as
163-
[`tracing.createAsyncListener()`][], or a constructed `AsyncListener`
164-
object.
165-
166-
Example usage for capturing errors:
167-
168-
var fs = require('fs');
169-
170-
var cntr = 0;
171-
var key = tracing.addAsyncListener({
172-
create: function onCreate() {
173-
return { uid: cntr++ };
174-
},
175-
before: function onBefore(context, storage) {
176-
// Write directly to stdout or we'll enter a recursive loop
177-
fs.writeSync(1, 'uid: ' + storage.uid + ' is about to run\n');
178-
},
179-
after: function onAfter(context, storage) {
180-
fs.writeSync(1, 'uid: ' + storage.uid + ' ran\n');
181-
},
182-
error: function onError(storage, err) {
183-
// Handle known errors
184-
if (err.message === 'everything is fine') {
185-
// Writing to stderr this time.
186-
fs.writeSync(2, 'handled error just threw:\n');
187-
fs.writeSync(2, err.stack + '\n');
188-
return true;
189-
}
190-
}
191-
});
192-
193-
process.nextTick(function() {
194-
throw new Error('everything is fine');
195-
});
196-
197-
// Output:
198-
// uid: 0 is about to run
199-
// handled error just threw:
200-
// Error: really, it's ok
201-
// at /tmp/test2.js:27:9
202-
// at process._tickCallback (node.js:583:11)
203-
// at Function.Module.runMain (module.js:492:11)
204-
// at startup (node.js:123:16)
205-
// at node.js:1012:3
206-
207-
## tracing.removeAsyncListener(asyncListener)
208-
209-
Removes the `AsyncListener` from the listening queue.
210-
211-
Removing the `AsyncListener` from the active queue does _not_ mean the
212-
`asyncListener` callbacks will cease to fire on the events they've been
213-
registered. Subsequently, any asynchronous events fired during the
214-
execution of a callback will also have the same `asyncListener` callbacks
215-
attached for future execution. For example:
216-
217-
var fs = require('fs');
218-
219-
var key = tracing.createAsyncListener({
220-
create: function asyncListener() {
221-
// Write directly to stdout or we'll enter a recursive loop
222-
fs.writeSync(1, 'You summoned me?\n');
223-
}
224-
});
225-
226-
// We want to begin capturing async events some time in the future.
227-
setTimeout(function() {
228-
tracing.addAsyncListener(key);
229-
230-
// Perform a few additional async events.
231-
setTimeout(function() {
232-
setImmediate(function() {
233-
process.nextTick(function() { });
234-
});
235-
});
236-
237-
// Removing the listener doesn't mean to stop capturing events that
238-
// have already been added.
239-
tracing.removeAsyncListener(key);
240-
}, 100);
241-
242-
// Output:
243-
// You summoned me?
244-
// You summoned me?
245-
// You summoned me?
246-
// You summoned me?
247-
248-
The fact that we logged 4 asynchronous events is an implementation detail
249-
of Node's [Timers][].
250-
251-
To stop capturing from a specific asynchronous event stack
252-
`tracing.removeAsyncListener()` must be called from within the call
253-
stack itself. For example:
254-
255-
var fs = require('fs');
256-
257-
var key = tracing.createAsyncListener({
258-
create: function asyncListener() {
259-
// Write directly to stdout or we'll enter a recursive loop
260-
fs.writeSync(1, 'You summoned me?\n');
261-
}
262-
});
263-
264-
// We want to begin capturing async events some time in the future.
265-
setTimeout(function() {
266-
tracing.addAsyncListener(key);
267-
268-
// Perform a few additional async events.
269-
setImmediate(function() {
270-
// Stop capturing from this call stack.
271-
tracing.removeAsyncListener(key);
272-
273-
process.nextTick(function() { });
274-
});
275-
}, 100);
276-
277-
// Output:
278-
// You summoned me?
279-
280-
The user must be explicit and always pass the `AsyncListener` they wish
281-
to remove. It is not possible to simply remove all listeners at once.
282-
283-
284-
[EventEmitter]: events.html#events_class_events_eventemitter
285-
[Timers]: timers.html
286-
[`tracing.createAsyncListener()`]: #tracing_tracing_createasynclistener_asynclistener_callbacksobj_storagevalue
287-
[`tracing.addAsyncListener()`]: #tracing_tracing_addasynclistener_asynclistener
288-
[`tracing.removeAsyncListener()`]: #tracing_tracing_removeasynclistener_asynclistener
66+

lib/timers.js

+3-50
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,6 @@ var TIMEOUT_MAX = 2147483647; // 2^31-1
3232

3333
var debug = require('util').debuglog('timer');
3434

35-
var tracing = require('tracing');
36-
var asyncFlags = tracing._asyncFlags;
37-
var runAsyncQueue = tracing._runAsyncQueue;
38-
var loadAsyncQueue = tracing._loadAsyncQueue;
39-
var unloadAsyncQueue = tracing._unloadAsyncQueue;
40-
41-
// Same as in AsyncListener in env.h
42-
var kHasListener = 0;
43-
44-
// Do a little housekeeping.
45-
delete tracing._asyncFlags;
46-
delete tracing._runAsyncQueue;
47-
delete tracing._loadAsyncQueue;
48-
delete tracing._unloadAsyncQueue;
49-
5035

5136
// IDLE TIMEOUTS
5237
//
@@ -61,11 +46,6 @@ delete tracing._unloadAsyncQueue;
6146
// value = list
6247
var lists = {};
6348

64-
// Make Timer as monomorphic as possible.
65-
Timer.prototype._asyncQueue = undefined;
66-
Timer.prototype._asyncData = undefined;
67-
Timer.prototype._asyncFlags = 0;
68-
6949
// the main function - creates lists on demand and the watchers associated
7050
// with them.
7151
function insert(item, msecs) {
@@ -102,7 +82,7 @@ function listOnTimeout() {
10282
var now = Timer.now();
10383
debug('now: %s', now);
10484

105-
var diff, first, hasQueue, threw;
85+
var diff, first, threw;
10686
while (first = L.peek(list)) {
10787
diff = now - first._idleStart;
10888
if (diff < msecs) {
@@ -124,19 +104,13 @@ function listOnTimeout() {
124104
if (domain && domain._disposed)
125105
continue;
126106

127-
hasQueue = !!first._asyncQueue;
128-
129107
try {
130-
if (hasQueue)
131-
loadAsyncQueue(first);
132108
if (domain)
133109
domain.enter();
134110
threw = true;
135111
first._onTimeout();
136112
if (domain)
137113
domain.exit();
138-
if (hasQueue)
139-
unloadAsyncQueue(first);
140114
threw = false;
141115
} finally {
142116
if (threw) {
@@ -206,11 +180,6 @@ exports.active = function(item) {
206180
L.append(list, item);
207181
}
208182
}
209-
// Whether or not a new TimerWrap needed to be created, this should run
210-
// for each item. This way each "item" (i.e. timer) can properly have
211-
// their own domain assigned.
212-
if (asyncFlags[kHasListener] > 0)
213-
runAsyncQueue(item);
214183
};
215184

216185

@@ -356,18 +325,15 @@ L.init(immediateQueue);
356325

357326
function processImmediate() {
358327
var queue = immediateQueue;
359-
var domain, hasQueue, immediate;
328+
var domain, immediate;
360329

361330
immediateQueue = {};
362331
L.init(immediateQueue);
363332

364333
while (L.isEmpty(queue) === false) {
365334
immediate = L.shift(queue);
366-
hasQueue = !!immediate._asyncQueue;
367335
domain = immediate.domain;
368336

369-
if (hasQueue)
370-
loadAsyncQueue(immediate);
371337
if (domain)
372338
domain.enter();
373339

@@ -391,8 +357,6 @@ function processImmediate() {
391357

392358
if (domain)
393359
domain.exit();
394-
if (hasQueue)
395-
unloadAsyncQueue(immediate);
396360
}
397361

398362
// Only round-trip to C++ land if we have to. Calling clearImmediate() on an
@@ -408,11 +372,8 @@ function Immediate() { }
408372

409373
Immediate.prototype.domain = undefined;
410374
Immediate.prototype._onImmediate = undefined;
411-
Immediate.prototype._asyncQueue = undefined;
412-
Immediate.prototype._asyncData = undefined;
413375
Immediate.prototype._idleNext = undefined;
414376
Immediate.prototype._idlePrev = undefined;
415-
Immediate.prototype._asyncFlags = 0;
416377

417378

418379
exports.setImmediate = function(callback) {
@@ -438,9 +399,6 @@ exports.setImmediate = function(callback) {
438399
process._immediateCallback = processImmediate;
439400
}
440401

441-
// setImmediates are handled more like nextTicks.
442-
if (asyncFlags[kHasListener] > 0)
443-
runAsyncQueue(immediate);
444402
if (process.domain)
445403
immediate.domain = process.domain;
446404

@@ -474,7 +432,7 @@ function unrefTimeout() {
474432

475433
debug('unrefTimer fired');
476434

477-
var diff, domain, first, hasQueue, threw;
435+
var diff, domain, first, threw;
478436
while (first = L.peek(unrefList)) {
479437
diff = now - first._idleStart;
480438

@@ -492,20 +450,15 @@ function unrefTimeout() {
492450

493451
if (!first._onTimeout) continue;
494452
if (domain && domain._disposed) continue;
495-
hasQueue = !!first._asyncQueue;
496453

497454
try {
498-
if (hasQueue)
499-
loadAsyncQueue(first);
500455
if (domain) domain.enter();
501456
threw = true;
502457
debug('unreftimer firing timeout');
503458
first._onTimeout();
504459
threw = false;
505460
if (domain)
506461
domain.exit();
507-
if (hasQueue)
508-
unloadAsyncQueue(first);
509462
} finally {
510463
if (threw) process.nextTick(unrefTimeout);
511464
}

0 commit comments

Comments
 (0)