Skip to content

Commit 52b71a2

Browse files
AndreasMadsengibfahn
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. PR-URL: nodejs#17273 Backport-PR-URL: nodejs#18179 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent ca3260d commit 52b71a2

13 files changed

+144
-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,
@@ -281,13 +280,6 @@ Object.defineProperty(module.exports, 'initTriggerId', {
281280
'Use the AsyncResource default instead.', 'DEP0085')
282281
});
283282

284-
Object.defineProperty(module.exports, 'setInitTriggerId', {
285-
get: internalUtil.deprecate(function() {
286-
return setInitTriggerId;
287-
}, 'async_hooks.setInitTriggerId is deprecated. ' +
288-
'Use the triggerAsyncId parameter in AsyncResource instead.', 'DEP0085')
289-
});
290-
291283
Object.defineProperty(module.exports, 'emitInit', {
292284
get: internalUtil.deprecate(function() {
293285
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
@@ -250,20 +250,27 @@ function newUid() {
250250
// constructor is complete.
251251
function getDefaultTriggerAsyncId() {
252252
var defaultTriggerAsyncId = async_id_fields[kDefaultTriggerAsyncId];
253-
// Reset value after it's been called so the next constructor doesn't
254-
// inherit it by accident.
255-
async_id_fields[kDefaultTriggerAsyncId] = -1;
256253
// If defaultTriggerAsyncId isn't set, use the executionAsyncId
257254
if (defaultTriggerAsyncId < 0)
258255
defaultTriggerAsyncId = async_id_fields[kExecutionAsyncId];
259256
return defaultTriggerAsyncId;
260257
}
261258

262259

263-
function setDefaultTriggerAsyncId(triggerAsyncId) {
260+
function defaultTriggerAsyncIdScope(triggerAsyncId, opaque, block) {
264261
// CHECK(Number.isSafeInteger(triggerAsyncId))
265262
// CHECK(triggerAsyncId > 0)
263+
const oldDefaultTriggerAsyncId = async_id_fields[kDefaultTriggerAsyncId];
266264
async_id_fields[kDefaultTriggerAsyncId] = triggerAsyncId;
265+
266+
var ret;
267+
try {
268+
ret = Reflect.apply(block, null, opaque);
269+
} finally {
270+
async_id_fields[kDefaultTriggerAsyncId] = oldDefaultTriggerAsyncId;
271+
}
272+
273+
return ret;
267274
}
268275

269276

@@ -285,10 +292,6 @@ function emitInitScript(asyncId, type, triggerAsyncId, resource) {
285292
// manually means that the embedder must have used getDefaultTriggerAsyncId().
286293
if (triggerAsyncId === null) {
287294
triggerAsyncId = getDefaultTriggerAsyncId();
288-
} else {
289-
// If a triggerAsyncId was passed, any kDefaultTriggerAsyncId still must be
290-
// null'd.
291-
async_id_fields[kDefaultTriggerAsyncId] = -1;
292295
}
293296

294297
emitInitNative(asyncId, type, triggerAsyncId, resource);
@@ -341,7 +344,7 @@ module.exports = {
341344
// Sensitive Embedder API
342345
newUid,
343346
getDefaultTriggerAsyncId,
344-
setDefaultTriggerAsyncId,
347+
defaultTriggerAsyncIdScope,
345348
emitInit: emitInitScript,
346349
emitBefore: emitBeforeScript,
347350
emitAfter: emitAfterScript,

lib/net.js

+46-45
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const { TCPConnectWrap } = process.binding('tcp_wrap');
3939
const { PipeConnectWrap } = process.binding('pipe_wrap');
4040
const { ShutdownWrap, WriteWrap } = process.binding('stream_wrap');
4141
const { async_id_symbol } = process.binding('async_wrap');
42-
const { newUid, setDefaultTriggerAsyncId } = require('internal/async_hooks');
42+
const { newUid, defaultTriggerAsyncIdScope } = require('internal/async_hooks');
4343
const { nextTick } = require('internal/process/next_tick');
4444
const errors = require('internal/errors');
4545
const dns = require('dns');
@@ -270,6 +270,14 @@ Socket.prototype._unrefTimer = function _unrefTimer() {
270270
timers._unrefActive(s);
271271
};
272272

273+
274+
function shutdownSocket(self, callback) {
275+
var req = new ShutdownWrap();
276+
req.oncomplete = callback;
277+
req.handle = self._handle;
278+
return self._handle.shutdown(req);
279+
}
280+
273281
// the user has called .end(), and all the bytes have been
274282
// sent out to the other side.
275283
function onSocketFinish() {
@@ -291,14 +299,9 @@ function onSocketFinish() {
291299
if (!this._handle || !this._handle.shutdown)
292300
return this.destroy();
293301

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

303306
if (err)
304307
return this.destroy(errnoException(err, 'shutdown'));
@@ -950,23 +953,15 @@ function internalConnect(
950953
req.localAddress = localAddress;
951954
req.localPort = localPort;
952955

953-
// node::TCPConnectWrap isn't instantiated and attached to the JS instance
954-
// of TCPConnectWrap above until connect() is called. So don't set the init
955-
// trigger id until now.
956-
setDefaultTriggerAsyncId(self[async_id_symbol]);
957956
if (addressType === 4)
958957
err = self._handle.connect(req, address, port);
959958
else
960959
err = self._handle.connect6(req, address, port);
961-
962960
} else {
963961
const req = new PipeConnectWrap();
964962
req.address = address;
965963
req.oncomplete = afterConnect;
966-
// node::PipeConnectWrap isn't instantiated and attached to the JS instance
967-
// of PipeConnectWrap above until connect() is called. So don't set the
968-
// init trigger id until now.
969-
setDefaultTriggerAsyncId(self[async_id_symbol]);
964+
970965
err = self._handle.connect(req, address, afterConnect);
971966
}
972967

@@ -1035,7 +1030,9 @@ Socket.prototype.connect = function(...args) {
10351030
'string',
10361031
path);
10371032
}
1038-
internalConnect(this, path);
1033+
defaultTriggerAsyncIdScope(
1034+
this[async_id_symbol], [this, path], internalConnect
1035+
);
10391036
} else {
10401037
lookupAndConnect(this, options);
10411038
}
@@ -1074,7 +1071,11 @@ function lookupAndConnect(self, options) {
10741071
if (addressType) {
10751072
nextTick(self[async_id_symbol], function() {
10761073
if (self.connecting)
1077-
internalConnect(self, host, port, addressType, localAddress, localPort);
1074+
defaultTriggerAsyncIdScope(
1075+
self[async_id_symbol],
1076+
[self, host, port, addressType, localAddress, localPort],
1077+
internalConnect
1078+
);
10781079
});
10791080
return;
10801081
}
@@ -1095,33 +1096,33 @@ function lookupAndConnect(self, options) {
10951096
debug('connect: dns options', dnsopts);
10961097
self._host = host;
10971098
var lookup = options.lookup || dns.lookup;
1098-
setDefaultTriggerAsyncId(self[async_id_symbol]);
1099-
lookup(host, dnsopts, function emitLookup(err, ip, addressType) {
1100-
self.emit('lookup', err, ip, addressType, host);
1099+
defaultTriggerAsyncIdScope(self[async_id_symbol], [], function() {
1100+
lookup(host, dnsopts, function emitLookup(err, ip, addressType) {
1101+
self.emit('lookup', err, ip, addressType, host);
11011102

1102-
// It's possible we were destroyed while looking this up.
1103-
// XXX it would be great if we could cancel the promise returned by
1104-
// the look up.
1105-
if (!self.connecting) return;
1103+
// It's possible we were destroyed while looking this up.
1104+
// XXX it would be great if we could cancel the promise returned by
1105+
// the look up.
1106+
if (!self.connecting) return;
11061107

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

src/async_wrap.cc

+6-5
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,13 @@ static void PromiseHook(PromiseHookType type, Local<Promise> promise,
330330
if (parent_wrap == nullptr) {
331331
parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true);
332332
}
333-
// get id from parentWrap
334-
double trigger_async_id = parent_wrap->get_async_id();
335-
env->set_default_trigger_async_id(trigger_async_id);
336-
}
337333

338-
wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
334+
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(
335+
env, parent_wrap->get_async_id());
336+
wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
337+
} else {
338+
wrap = PromiseWrap::New(env, promise, nullptr, silent);
339+
}
339340
}
340341

341342
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
@@ -197,23 +197,27 @@ inline void Environment::AsyncHooks::clear_async_id_stack() {
197197
async_id_fields_[kTriggerAsyncId] = 0;
198198
}
199199

200-
inline Environment::AsyncHooks::InitScope::InitScope(
201-
Environment* env, double init_trigger_async_id)
202-
: env_(env),
203-
async_id_fields_ref_(env->async_hooks()->async_id_fields()) {
204-
if (env_->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
205-
CHECK_GE(init_trigger_async_id, -1);
200+
inline Environment::AsyncHooks::DefaultTriggerAsyncIdScope
201+
::DefaultTriggerAsyncIdScope(Environment* env,
202+
double default_trigger_async_id)
203+
: async_id_fields_ref_(env->async_hooks()->async_id_fields()) {
204+
if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
205+
CHECK_GE(default_trigger_async_id, 0);
206206
}
207-
env->async_hooks()->push_async_ids(
208-
async_id_fields_ref_[AsyncHooks::kExecutionAsyncId],
209-
init_trigger_async_id);
207+
208+
old_default_trigger_async_id_ =
209+
async_id_fields_ref_[AsyncHooks::kDefaultTriggerAsyncId];
210+
async_id_fields_ref_[AsyncHooks::kDefaultTriggerAsyncId] =
211+
default_trigger_async_id;
210212
}
211213

212-
inline Environment::AsyncHooks::InitScope::~InitScope() {
213-
env_->async_hooks()->pop_async_id(
214-
async_id_fields_ref_[AsyncHooks::kExecutionAsyncId]);
214+
inline Environment::AsyncHooks::DefaultTriggerAsyncIdScope
215+
::~DefaultTriggerAsyncIdScope() {
216+
async_id_fields_ref_[AsyncHooks::kDefaultTriggerAsyncId] =
217+
old_default_trigger_async_id_;
215218
}
216219

220+
217221
inline Environment::AsyncCallbackScope::AsyncCallbackScope(Environment* env)
218222
: env_(env) {
219223
env_->makecallback_cntr_++;
@@ -473,17 +477,12 @@ inline double Environment::trigger_async_id() {
473477
inline double Environment::get_default_trigger_async_id() {
474478
double default_trigger_async_id =
475479
async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
476-
async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] = -1;
477480
// If defaultTriggerAsyncId isn't set, use the executionAsyncId
478481
if (default_trigger_async_id < 0)
479482
default_trigger_async_id = execution_async_id();
480483
return default_trigger_async_id;
481484
}
482485

483-
inline void Environment::set_default_trigger_async_id(const double id) {
484-
async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] = id;
485-
}
486-
487486
inline double* Environment::heap_statistics_buffer() const {
488487
CHECK_NE(heap_statistics_buffer_, nullptr);
489488
return heap_statistics_buffer_;

0 commit comments

Comments
 (0)