Skip to content

Commit a880e27

Browse files
AndreasMadsenevanlucas
authored andcommitted
async_hooks: use scope for defaultTriggerAsyncId
Previously the getter would mutate the kDefaultTriggerAsncId value. This refactor changes the setter to bind the current kDefaultTriggerAsncId to a scope, such that the getter doesn't have to mutate its own value. Backport-PR-URL: #18079 PR-URL: #17273 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent f56eb2a commit a880e27

13 files changed

+142
-129
lines changed

lib/async_hooks.js

-8
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ const {
2020
// Sensitive Embedder API
2121
newUid,
2222
getDefaultTriggerAsyncId,
23-
setInitTriggerId,
2423
emitInit,
2524
emitBefore,
2625
emitAfter,
@@ -250,13 +249,6 @@ Object.defineProperty(module.exports, 'initTriggerId', {
250249
'Use the AsyncResource default instead.', 'DEP0085')
251250
});
252251

253-
Object.defineProperty(module.exports, 'setInitTriggerId', {
254-
get: internalUtil.deprecate(function() {
255-
return setInitTriggerId;
256-
}, 'async_hooks.setInitTriggerId is deprecated. ' +
257-
'Use the triggerAsyncId parameter in AsyncResource instead.', 'DEP0085')
258-
});
259-
260252
Object.defineProperty(module.exports, 'emitInit', {
261253
get: internalUtil.deprecate(function() {
262254
return emitInit;

lib/dgram.js

+11-10
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const dns = require('dns');
2828
const util = require('util');
2929
const { isUint8Array } = require('internal/util/types');
3030
const EventEmitter = require('events');
31-
const { setDefaultTriggerAsyncId } = require('internal/async_hooks');
31+
const { defaultTriggerAsyncIdScope } = require('internal/async_hooks');
3232
const { UV_UDP_REUSEADDR } = process.binding('constants').os;
3333
const { async_id_symbol } = process.binding('async_wrap');
3434
const { nextTick } = require('internal/process/next_tick');
@@ -448,21 +448,24 @@ Socket.prototype.send = function(buffer,
448448
}
449449

450450
const afterDns = (ex, ip) => {
451-
doSend(ex, this, ip, list, address, port, callback);
451+
defaultTriggerAsyncIdScope(
452+
this[async_id_symbol],
453+
[ex, this, ip, list, address, port, callback],
454+
doSend
455+
);
452456
};
453457

454458
this._handle.lookup(address, afterDns);
455459
};
456460

457-
458461
function doSend(ex, self, ip, list, address, port, callback) {
459462
if (ex) {
460463
if (typeof callback === 'function') {
461-
callback(ex);
464+
process.nextTick(callback, ex);
462465
return;
463466
}
464467

465-
self.emit('error', ex);
468+
process.nextTick(() => self.emit('error', ex));
466469
return;
467470
} else if (!self._handle) {
468471
return;
@@ -476,20 +479,18 @@ function doSend(ex, self, ip, list, address, port, callback) {
476479
req.callback = callback;
477480
req.oncomplete = afterSend;
478481
}
479-
// node::SendWrap isn't instantiated and attached to the JS instance of
480-
// SendWrap above until send() is called. So don't set the init trigger id
481-
// until now.
482-
setDefaultTriggerAsyncId(self[async_id_symbol]);
482+
483483
var err = self._handle.send(req,
484484
list,
485485
list.length,
486486
port,
487487
ip,
488488
!!callback);
489+
489490
if (err && callback) {
490491
// don't emit as error, dgram_legacy.js compatibility
491492
const ex = exceptionWithHostPort(err, 'send', address, port);
492-
nextTick(self[async_id_symbol], callback, ex);
493+
process.nextTick(callback, ex);
493494
}
494495
}
495496

lib/internal/async_hooks.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -247,20 +247,27 @@ function newUid() {
247247
// constructor is complete.
248248
function getDefaultTriggerAsyncId() {
249249
var defaultTriggerAsyncId = async_id_fields[kDefaultTriggerAsyncId];
250-
// Reset value after it's been called so the next constructor doesn't
251-
// inherit it by accident.
252-
async_id_fields[kDefaultTriggerAsyncId] = -1;
253250
// If defaultTriggerAsyncId isn't set, use the executionAsyncId
254251
if (defaultTriggerAsyncId < 0)
255252
defaultTriggerAsyncId = async_id_fields[kExecutionAsyncId];
256253
return defaultTriggerAsyncId;
257254
}
258255

259256

260-
function setDefaultTriggerAsyncId(triggerAsyncId) {
257+
function defaultTriggerAsyncIdScope(triggerAsyncId, opaque, block) {
261258
// CHECK(Number.isSafeInteger(triggerAsyncId))
262259
// CHECK(triggerAsyncId > 0)
260+
const oldDefaultTriggerAsyncId = async_id_fields[kDefaultTriggerAsyncId];
263261
async_id_fields[kDefaultTriggerAsyncId] = triggerAsyncId;
262+
263+
var ret;
264+
try {
265+
ret = Reflect.apply(block, null, opaque);
266+
} finally {
267+
async_id_fields[kDefaultTriggerAsyncId] = oldDefaultTriggerAsyncId;
268+
}
269+
270+
return ret;
264271
}
265272

266273

@@ -282,10 +289,6 @@ function emitInitScript(asyncId, type, triggerAsyncId, resource) {
282289
// manually means that the embedder must have used getDefaultTriggerAsyncId().
283290
if (triggerAsyncId === null) {
284291
triggerAsyncId = getDefaultTriggerAsyncId();
285-
} else {
286-
// If a triggerAsyncId was passed, any kDefaultTriggerAsyncId still must be
287-
// null'd.
288-
async_id_fields[kDefaultTriggerAsyncId] = -1;
289292
}
290293

291294
emitInitNative(asyncId, type, triggerAsyncId, resource);
@@ -338,7 +341,7 @@ module.exports = {
338341
// Sensitive Embedder API
339342
newUid,
340343
getDefaultTriggerAsyncId,
341-
setDefaultTriggerAsyncId,
344+
defaultTriggerAsyncIdScope,
342345
emitInit: emitInitScript,
343346
emitBefore: emitBeforeScript,
344347
emitAfter: emitAfterScript,

lib/net.js

+46-45
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const { TCPConnectWrap } = process.binding('tcp_wrap');
4343
const { PipeConnectWrap } = process.binding('pipe_wrap');
4444
const { ShutdownWrap, WriteWrap } = process.binding('stream_wrap');
4545
const { async_id_symbol } = process.binding('async_wrap');
46-
const { newUid, setDefaultTriggerAsyncId } = require('internal/async_hooks');
46+
const { newUid, defaultTriggerAsyncIdScope } = require('internal/async_hooks');
4747
const { nextTick } = require('internal/process/next_tick');
4848
const errors = require('internal/errors');
4949
const dns = require('dns');
@@ -274,6 +274,14 @@ Socket.prototype._unrefTimer = function _unrefTimer() {
274274
timers._unrefActive(s);
275275
};
276276

277+
278+
function shutdownSocket(self, callback) {
279+
var req = new ShutdownWrap();
280+
req.oncomplete = callback;
281+
req.handle = self._handle;
282+
return self._handle.shutdown(req);
283+
}
284+
277285
// the user has called .end(), and all the bytes have been
278286
// sent out to the other side.
279287
function onSocketFinish() {
@@ -295,14 +303,9 @@ function onSocketFinish() {
295303
if (!this._handle || !this._handle.shutdown)
296304
return this.destroy();
297305

298-
var req = new ShutdownWrap();
299-
req.oncomplete = afterShutdown;
300-
req.handle = this._handle;
301-
// node::ShutdownWrap isn't instantiated and attached to the JS instance of
302-
// ShutdownWrap above until shutdown() is called. So don't set the init
303-
// trigger id until now.
304-
setDefaultTriggerAsyncId(this[async_id_symbol]);
305-
var err = this._handle.shutdown(req);
306+
var err = defaultTriggerAsyncIdScope(
307+
this[async_id_symbol], [this, afterShutdown], shutdownSocket
308+
);
306309

307310
if (err)
308311
return this.destroy(errnoException(err, 'shutdown'));
@@ -936,23 +939,15 @@ function internalConnect(
936939
req.localAddress = localAddress;
937940
req.localPort = localPort;
938941

939-
// node::TCPConnectWrap isn't instantiated and attached to the JS instance
940-
// of TCPConnectWrap above until connect() is called. So don't set the init
941-
// trigger id until now.
942-
setDefaultTriggerAsyncId(self[async_id_symbol]);
943942
if (addressType === 4)
944943
err = self._handle.connect(req, address, port);
945944
else
946945
err = self._handle.connect6(req, address, port);
947-
948946
} else {
949947
const req = new PipeConnectWrap();
950948
req.address = address;
951949
req.oncomplete = afterConnect;
952-
// node::PipeConnectWrap isn't instantiated and attached to the JS instance
953-
// of PipeConnectWrap above until connect() is called. So don't set the
954-
// init trigger id until now.
955-
setDefaultTriggerAsyncId(self[async_id_symbol]);
950+
956951
err = self._handle.connect(req, address, afterConnect);
957952
}
958953

@@ -1021,7 +1016,9 @@ Socket.prototype.connect = function(...args) {
10211016
'string',
10221017
path);
10231018
}
1024-
internalConnect(this, path);
1019+
defaultTriggerAsyncIdScope(
1020+
this[async_id_symbol], [this, path], internalConnect
1021+
);
10251022
} else {
10261023
lookupAndConnect(this, options);
10271024
}
@@ -1064,7 +1061,11 @@ function lookupAndConnect(self, options) {
10641061
if (addressType) {
10651062
nextTick(self[async_id_symbol], function() {
10661063
if (self.connecting)
1067-
internalConnect(self, host, port, addressType, localAddress, localPort);
1064+
defaultTriggerAsyncIdScope(
1065+
self[async_id_symbol],
1066+
[self, host, port, addressType, localAddress, localPort],
1067+
internalConnect
1068+
);
10681069
});
10691070
return;
10701071
}
@@ -1091,33 +1092,33 @@ function lookupAndConnect(self, options) {
10911092
debug('connect: dns options', dnsopts);
10921093
self._host = host;
10931094
var lookup = options.lookup || dns.lookup;
1094-
setDefaultTriggerAsyncId(self[async_id_symbol]);
1095-
lookup(host, dnsopts, function emitLookup(err, ip, addressType) {
1096-
self.emit('lookup', err, ip, addressType, host);
1095+
defaultTriggerAsyncIdScope(self[async_id_symbol], [], function() {
1096+
lookup(host, dnsopts, function emitLookup(err, ip, addressType) {
1097+
self.emit('lookup', err, ip, addressType, host);
10971098

1098-
// It's possible we were destroyed while looking this up.
1099-
// XXX it would be great if we could cancel the promise returned by
1100-
// the look up.
1101-
if (!self.connecting) return;
1099+
// It's possible we were destroyed while looking this up.
1100+
// XXX it would be great if we could cancel the promise returned by
1101+
// the look up.
1102+
if (!self.connecting) return;
11021103

1103-
if (err) {
1104-
// net.createConnection() creates a net.Socket object and
1105-
// immediately calls net.Socket.connect() on it (that's us).
1106-
// There are no event listeners registered yet so defer the
1107-
// error event to the next tick.
1108-
err.host = options.host;
1109-
err.port = options.port;
1110-
err.message = err.message + ' ' + options.host + ':' + options.port;
1111-
process.nextTick(connectErrorNT, self, err);
1112-
} else {
1113-
self._unrefTimer();
1114-
internalConnect(self,
1115-
ip,
1116-
port,
1117-
addressType,
1118-
localAddress,
1119-
localPort);
1120-
}
1104+
if (err) {
1105+
// net.createConnection() creates a net.Socket object and
1106+
// immediately calls net.Socket.connect() on it (that's us).
1107+
// There are no event listeners registered yet so defer the
1108+
// error event to the next tick.
1109+
err.host = options.host;
1110+
err.port = options.port;
1111+
err.message = err.message + ' ' + options.host + ':' + options.port;
1112+
process.nextTick(connectErrorNT, self, err);
1113+
} else {
1114+
self._unrefTimer();
1115+
defaultTriggerAsyncIdScope(
1116+
self[async_id_symbol],
1117+
[self, ip, port, addressType, localAddress, localPort],
1118+
internalConnect
1119+
);
1120+
}
1121+
});
11211122
});
11221123
}
11231124

src/async_wrap.cc

+6-5
Original file line numberDiff line numberDiff line change
@@ -308,12 +308,13 @@ static void PromiseHook(PromiseHookType type, Local<Promise> promise,
308308
if (parent_wrap == nullptr) {
309309
parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true);
310310
}
311-
// get id from parentWrap
312-
double trigger_async_id = parent_wrap->get_async_id();
313-
env->set_default_trigger_async_id(trigger_async_id);
314-
}
315311

316-
wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
312+
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(
313+
env, parent_wrap->get_async_id());
314+
wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
315+
} else {
316+
wrap = PromiseWrap::New(env, promise, nullptr, silent);
317+
}
317318
}
318319

319320
CHECK_NE(wrap, nullptr);

src/connection_wrap.cc

-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ void ConnectionWrap<WrapType, UVType>::OnConnection(uv_stream_t* handle,
4949
};
5050

5151
if (status == 0) {
52-
env->set_default_trigger_async_id(wrap_data->get_async_id());
5352
// Instantiate the client javascript object and handle.
5453
Local<Object> client_obj = WrapType::Instantiate(env,
5554
wrap_data,

src/env-inl.h

+16-17
Original file line numberDiff line numberDiff line change
@@ -168,23 +168,27 @@ inline void Environment::AsyncHooks::clear_async_id_stack() {
168168
async_id_fields_[kTriggerAsyncId] = 0;
169169
}
170170

171-
inline Environment::AsyncHooks::InitScope::InitScope(
172-
Environment* env, double init_trigger_async_id)
173-
: env_(env),
174-
async_id_fields_ref_(env->async_hooks()->async_id_fields()) {
175-
if (env_->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
176-
CHECK_GE(init_trigger_async_id, -1);
171+
inline Environment::AsyncHooks::DefaultTriggerAsyncIdScope
172+
::DefaultTriggerAsyncIdScope(Environment* env,
173+
double default_trigger_async_id)
174+
: async_id_fields_ref_(env->async_hooks()->async_id_fields()) {
175+
if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
176+
CHECK_GE(default_trigger_async_id, 0);
177177
}
178-
env->async_hooks()->push_async_ids(
179-
async_id_fields_ref_[AsyncHooks::kExecutionAsyncId],
180-
init_trigger_async_id);
178+
179+
old_default_trigger_async_id_ =
180+
async_id_fields_ref_[AsyncHooks::kDefaultTriggerAsyncId];
181+
async_id_fields_ref_[AsyncHooks::kDefaultTriggerAsyncId] =
182+
default_trigger_async_id;
181183
}
182184

183-
inline Environment::AsyncHooks::InitScope::~InitScope() {
184-
env_->async_hooks()->pop_async_id(
185-
async_id_fields_ref_[AsyncHooks::kExecutionAsyncId]);
185+
inline Environment::AsyncHooks::DefaultTriggerAsyncIdScope
186+
::~DefaultTriggerAsyncIdScope() {
187+
async_id_fields_ref_[AsyncHooks::kDefaultTriggerAsyncId] =
188+
old_default_trigger_async_id_;
186189
}
187190

191+
188192
inline Environment::AsyncCallbackScope::AsyncCallbackScope(Environment* env)
189193
: env_(env) {
190194
env_->makecallback_cntr_++;
@@ -449,17 +453,12 @@ inline double Environment::trigger_async_id() {
449453
inline double Environment::get_default_trigger_async_id() {
450454
double default_trigger_async_id =
451455
async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
452-
async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] = -1;
453456
// If defaultTriggerAsyncId isn't set, use the executionAsyncId
454457
if (default_trigger_async_id < 0)
455458
default_trigger_async_id = execution_async_id();
456459
return default_trigger_async_id;
457460
}
458461

459-
inline void Environment::set_default_trigger_async_id(const double id) {
460-
async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] = id;
461-
}
462-
463462
inline double* Environment::heap_statistics_buffer() const {
464463
CHECK_NE(heap_statistics_buffer_, nullptr);
465464
return heap_statistics_buffer_;

0 commit comments

Comments
 (0)