Skip to content

Commit 340f1e1

Browse files
committed
Merge pull request #39 from AndreasMadsen/async-wrap-update-3
docs: update after nodejs/node#4600
2 parents 7c0673d + 910f129 commit 340f1e1

File tree

2 files changed

+71
-45
lines changed

2 files changed

+71
-45
lines changed

docs/AsyncWrap/README.md

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ To assign the hooks call:
118118

119119
```javascript
120120
asyncWrap.setupHooks(init, pre, post, destroy);
121-
function init(provider, uid, parent) { /* consumer code */ }
122-
function pre() { /* consumer code */ }
123-
function post() { /* consumer code */ }
121+
function init(uid, provider, parentUid, parentHandle) { /* consumer code */ }
122+
function pre(uid) { /* consumer code */ }
123+
function post(uid) { /* consumer code */ }
124124
function destroy(uid) { /* consumer code */ }
125125
```
126126

@@ -153,21 +153,21 @@ asyncWrap.disable();
153153
#### The Hooks
154154

155155
Currently there are 4 hooks: `init`, `pre`, `post` `destroy`. The `this`
156-
variable refers to the handle object. The `init` hook has three extra arguments
157-
`provider`, `uid` and `parent`. The `destroy` hook also has the `uid` argument.
156+
variable refers to the handle object, they all have a `uid` argument, finally
157+
`init` provides extra information about the creation of the handle object.
158158

159159
```javascript
160-
function init(provider, uid, parent) { }
161-
function pre() { }
162-
function post() { }
160+
function init(uid, provider, parentUid, parentHandle) { }
161+
function pre(uid) { }
162+
function post(uid) { }
163163
function destroy(uid) { }
164164
```
165165

166166
##### this
167167

168168
In the `init`, `pre` and `post` cases the `this` variable is the handle object.
169169
Users may read properties from this object such as `port` and `address` in the
170-
`TCPConnectWrap` case, or set user specific properties.
170+
`TCPConnectWrap` case.
171171

172172
In the `init` hook the handle object is not yet fully constructed, thus some
173173
properties are not safe to read. This causes problems when doing
@@ -211,16 +211,20 @@ At the time of writing this is the current list:
211211

212212
##### uid
213213

214-
The `uid` is a unique integer that identify each handle object. Because the
215-
`destroy` hook isn't called with the handle object, this is particular useful
216-
for storing information related to the handle object, that the user require in
217-
the `destroy` hook.
214+
The `uid` is a unique integer that identifies each handle object. You can use
215+
the `uid` to store information related to the handle object, by using it as
216+
a key for a shared `Map` object.
218217

219-
##### parent
218+
As such the user could also store information on the `this` object, but this
219+
may be unsafe since the user could accidentally overwrite an undocumented
220+
property. The `this` object is also not available in the `destroy` hook, thus
221+
the `uid` is generally the recommended choice.
222+
223+
##### parentUid
220224

221225
In some cases the handle was created from another handle object. In those
222-
cases the `parent` argument is set the creating handle object. If there is
223-
no parent handle then it is just `null`.
226+
cases the `parentUid` argument is set to the uid of the creating handle object.
227+
If there is no parent then it is just `null`.
224228

225229
The most common case is the TCP server. The TCP server itself is a `TCP` handle,
226230
but when receiving new connection it creates another `TCP` handle that is
@@ -235,7 +239,11 @@ post // TCP (server)
235239

236240
This means it is not possible to know in what handle context the new socket
237241
handle was created using the `pre` and `post` hooks. However the
238-
`parent` argument provides this information.
242+
`parentUid` argument provides this information.
243+
244+
##### parentHandle
245+
246+
This is similar to parentUid but is the actual parent handle object.
239247

240248
## Example
241249

@@ -244,38 +252,47 @@ A classic use case for AsyncWrap is to create a long-stack-trace tool.
244252
```javascript
245253
const asyncWrap = process.binding('async_wrap');
246254

247-
asyncWrap.setupHooks(init, pre, post);
255+
asyncWrap.setupHooks(init, before, after, destroy);
248256
asyncWrap.enable();
249257

250-
// global state variable, that contains the current stack trace
251-
let currentStack = '';
258+
// global state variable, that contains the stack traces and the current uid
259+
const stack = new Map();
260+
stack.set(-1, '');
252261

253-
function init(provider, uid, parent) {
262+
let currentUid = -1;
263+
264+
function init(uid, provider, parentUid, parentHandle) {
254265
// When a handle is created, collect the stack trace such that we later
255266
// can see what involved the handle constructor.
256267
const localStack = (new Error()).stack.split('\n').slice(1).join('\n');
257268

258-
// Compute the full stack and store it as a property on the handle object,
259-
// such that it can be fetched later.
260-
const extraStack = parent ? parent._full_init_stack : currentStack;
261-
this._full_init_stack = localStack + '\n' + extraStack;
269+
// Compute the full stack and store on the `Map` using the `uid` as key.
270+
const extraStack = stack.get(parentUid || currentUid);
271+
stack.set(uid, localStack + '\n' + extraStack);
262272
}
263-
function pre() {
264-
// A callback is about to be called, update the `currentStack` such that
273+
function before(uid) {
274+
// A callback is about to be called, update the `currentUid` such that
265275
// it is correct for when another handle is initialized or `getStack` is
266276
// called.
267-
currentStack = this._full_init_stack;
277+
currentUid = uid;
268278
}
269-
function post() {
279+
function after(uid) {
270280
// At the time of writing there are some odd cases where there is no handle
271281
// context, this line prevents that from resulting in wrong stack trace. But
272282
// the stack trace will be shorter compared to what ideally should happen.
273-
currentStack = '';
283+
currentUid = -1;
284+
}
285+
286+
function destroy(uid) {
287+
// Once the handle is destroyed no other handle objects can be created with
288+
// this handle as its immediate context. Thus its associated stack can be
289+
// deleted.
290+
stack.delete(uid);
274291
}
275292

276293
function getStack(message) {
277294
const localStack = new Error(message);
278-
return localStack.stack + '\n' + currentStack;
295+
return localStack.stack + '\n' + stack.get(currentUid);
279296
}
280297
module.exports = getStack;
281298
```

docs/AsyncWrap/example-trace/trace.js

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,46 @@
22

33
const asyncWrap = process.binding('async_wrap');
44

5-
asyncWrap.setupHooks(init, before, after);
5+
asyncWrap.setupHooks(init, before, after, destroy);
66
asyncWrap.enable();
77

8-
// global state variable, that contains the current stack trace
9-
let currentStack = '';
8+
// global state variable, that contains the stack traces and the current uid
9+
const stack = new Map();
10+
stack.set(-1, '');
1011

11-
function init(provider, uid, parent) {
12+
let currentUid = -1;
13+
14+
function init(uid, provider, parentUid, parentHandle) {
1215
// When a handle is created, collect the stack trace such that we later
1316
// can see what involved the handle constructor.
1417
const localStack = (new Error()).stack.split('\n').slice(1).join('\n');
1518

16-
// Compute the full stack and store it as a property on the handle object,
17-
// such that it can be fetched later.
18-
const extraStack = parent ? parent._full_init_stack : currentStack;
19-
this._full_init_stack = localStack + '\n' + extraStack;
19+
// Compute the full stack and store on the `Map` using the `uid` as key.
20+
const extraStack = stack.get(parentUid || currentUid);
21+
stack.set(uid, localStack + '\n' + extraStack);
2022
}
21-
function before() {
22-
// A callback is about to be called, update the `currentStack` such that
23+
function before(uid) {
24+
// A callback is about to be called, update the `currentUid` such that
2325
// it is correct for when another handle is initialized or `getStack` is
2426
// called.
25-
currentStack = this._full_init_stack;
27+
currentUid = uid;
2628
}
27-
function after() {
29+
function after(uid) {
2830
// At the time of writing there are some odd cases where there is no handle
2931
// context, this line prevents that from resulting in wrong stack trace. But
3032
// the stack trace will be shorter compared to what ideally should happen.
31-
currentStack = '';
33+
currentUid = -1;
34+
}
35+
36+
function destroy(uid) {
37+
// Once the handle is destroyed no other handle objects can be created with
38+
// this handle as its immediate context. Thus its associated stack can be
39+
// deleted.
40+
stack.delete(uid);
3241
}
3342

3443
function getStack(message) {
3544
const localStack = new Error(message);
36-
return localStack.stack + '\n' + currentStack;
45+
return localStack.stack + '\n' + stack.get(currentUid);
3746
}
3847
module.exports = getStack;

0 commit comments

Comments
 (0)