Skip to content

Commit fb88c0d

Browse files
committedMay 29, 2017
async_hooks: run destroy cbs before normal exit
Run destroy callbacks before a normal application exit happens. Fixes: nodejs#13262
1 parent 1091327 commit fb88c0d

5 files changed

+74
-3
lines changed
 

‎src/async-wrap.cc

+5-3
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,13 @@ static void DestroyIdsCb(uv_idle_t* handle) {
142142
uv_idle_stop(handle);
143143

144144
Environment* env = Environment::from_destroy_ids_idle_handle(handle);
145-
146145
HandleScope handle_scope(env->isolate());
147146
Context::Scope context_scope(env->context());
147+
148+
AsyncWrap::RunDestroyCbs(env);
149+
}
150+
151+
void AsyncWrap::RunDestroyCbs(Environment* env) {
148152
Local<Function> fn = env->async_hooks_destroy_function();
149153

150154
TryCatch try_catch(env->isolate());
@@ -164,8 +168,6 @@ static void DestroyIdsCb(uv_idle_t* handle) {
164168
FatalException(env->isolate(), try_catch);
165169
}
166170
}
167-
168-
env->destroy_ids_list()->clear();
169171
}
170172

171173

‎src/async-wrap.h

+2
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class AsyncWrap : public BaseObject {
111111
static bool EmitBefore(Environment* env, double id);
112112
static bool EmitAfter(Environment* env, double id);
113113

114+
static void RunDestroyCbs(Environment* env);
115+
114116
inline ProviderType provider_type() const;
115117

116118
inline double get_id() const;

‎src/node.cc

+2
Original file line numberDiff line numberDiff line change
@@ -4531,6 +4531,8 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
45314531
} while (more == true);
45324532
}
45334533

4534+
AsyncWrap::RunDestroyCbs(&env);
4535+
45344536
env.set_trace_sync_io(false);
45354537

45364538
const int exit_code = EmitExit(&env);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
// Test that async ids that are added to the destroy queue while running a
3+
// `destroy` callback are handled correctly.
4+
5+
const common = require('../common');
6+
const assert = require('assert');
7+
const net = require('net');
8+
const async_hooks = require('async_hooks');
9+
10+
const initCalls = new Set();
11+
let destroyTcpWrapCallCount = 0;
12+
let srv2;
13+
14+
async_hooks.createHook({
15+
init: common.mustCallAtLeast((id, provider, triggerId) => {
16+
if (provider === 'TCPWRAP')
17+
initCalls.add(id);
18+
}, 2),
19+
destroy: common.mustCallAtLeast((id) => {
20+
if (!initCalls.has(id)) return;
21+
22+
switch (destroyTcpWrapCallCount++) {
23+
case 0:
24+
// Trigger the second `destroy` call.
25+
srv2.close();
26+
break;
27+
case 2:
28+
assert.fail('More than 2 destroy() invocations');
29+
break;
30+
}
31+
}, 2)
32+
}).enable();
33+
34+
// Create a server to trigger the first `destroy` callback.
35+
net.createServer().listen(0).close();
36+
srv2 = net.createServer().listen(0);
37+
38+
process.on('exit', () => assert.strictEqual(destroyTcpWrapCallCount, 2));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
// Regression test for https://github.com/nodejs/node/issues/13262
4+
5+
const common = require('../common');
6+
const assert = require('assert');
7+
const async_hooks = require('async_hooks');
8+
9+
let seenId, seenResource;
10+
11+
async_hooks.createHook({
12+
init: common.mustCall((id, provider, triggerId, resource) => {
13+
seenId = id;
14+
seenResource = resource;
15+
assert.strictEqual(provider, 'Immediate');
16+
assert.strictEqual(triggerId, 1);
17+
}),
18+
before: common.mustNotCall(),
19+
after: common.mustNotCall(),
20+
destroy: common.mustCall((id) => {
21+
assert.strictEqual(seenId, id);
22+
})
23+
}).enable();
24+
25+
const immediate = setImmediate(common.mustNotCall());
26+
assert.strictEqual(immediate, seenResource);
27+
clearImmediate(immediate);

0 commit comments

Comments
 (0)
Please sign in to comment.