Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async_hooks: unmerge resource_symbol from owner_symbol #40741

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/_http_agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ function asyncResetHandle(socket) {
const handle = socket._handle;
if (handle && typeof handle.asyncReset === 'function') {
// Assign the handle a new asyncId and run any destroy()/init() hooks.
handle.asyncReset(new ReusedHandle(handle.getProviderType(), socket));
handle.asyncReset(new ReusedHandle(handle.getProviderType(), handle));
socket[async_id_symbol] = handle.getAsyncId();
}
}
Expand Down
12 changes: 5 additions & 7 deletions lib/internal/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const active_hooks = {

const { registerDestroyHook } = async_wrap;
const { enqueueMicrotask } = internalBinding('task_queue');
const { owner_symbol } = internalBinding('symbols');
const { resource_symbol, owner_symbol } = internalBinding('symbols');

// Each constant tracks how many callbacks there are for any given step of
// async execution. These are tracked so if the user didn't include callbacks
Expand Down Expand Up @@ -178,13 +178,11 @@ function fatalError(e) {

function lookupPublicResource(resource) {
if (typeof resource !== 'object' || resource === null) return resource;

const publicResource = resource[owner_symbol];

if (publicResource != null) {
// TODO(addaleax): Merge this with owner_symbol and use it across all
// AsyncWrap instances.
const publicResource = resource[resource_symbol];
if (publicResource !== undefined)
Flarna marked this conversation as resolved.
Show resolved Hide resolved
return publicResource;
}

return resource;
}

Expand Down
39 changes: 5 additions & 34 deletions lib/internal/js_stream_socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,15 @@ const kCurrentWriteRequest = Symbol('kCurrentWriteRequest');
const kCurrentShutdownRequest = Symbol('kCurrentShutdownRequest');
const kPendingShutdownRequest = Symbol('kPendingShutdownRequest');

function checkReusedHandle(self) {
let socket = self[owner_symbol];
function isClosing() { return this[owner_symbol].isClosing(); }

if (socket.constructor.name === 'ReusedHandle')
socket = socket.handle;
function onreadstart() { return this[owner_symbol].readStart(); }

return socket;
}

function isClosing() {
const socket = checkReusedHandle(this);

return socket.isClosing();
}

function onreadstart() {
const socket = checkReusedHandle(this);

return socket.readStart();
}
function onreadstop() { return this[owner_symbol].readStop(); }

function onreadstop() {
const socket = checkReusedHandle(this);
function onshutdown(req) { return this[owner_symbol].doShutdown(req); }

return socket.readStop();
}

function onshutdown(req) {
const socket = checkReusedHandle(this);

return socket.doShutdown(req);
}

function onwrite(req, bufs) {
const socket = checkReusedHandle(this);

return socket.doWrite(req, bufs);
}
function onwrite(req, bufs) { return this[owner_symbol].doWrite(req, bufs); }

/* This class serves as a wrapper for when the C++ side of Node wants access
* to a standard JS stream. For example, TLS or HTTP do not operate on network
Expand Down
13 changes: 2 additions & 11 deletions lib/internal/stream_base_commons.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,7 @@ function handleWriteReq(req, data, encoding) {
function onWriteComplete(status) {
debug('onWriteComplete', status, this.error);

let stream = this.handle[owner_symbol];

if (stream.constructor.name === 'ReusedHandle') {
stream = stream.handle;
}
const stream = this.handle[owner_symbol];

if (stream.destroyed) {
if (typeof this.callback === 'function')
Expand Down Expand Up @@ -172,12 +168,7 @@ function onStreamRead(arrayBuffer) {
const nread = streamBaseState[kReadBytesOrError];

const handle = this;

let stream = this[owner_symbol];

if (stream.constructor.name === 'ReusedHandle') {
stream = stream.handle;
}
const stream = this[owner_symbol];

stream[kUpdateTimer]();

Expand Down
6 changes: 1 addition & 5 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -1117,11 +1117,7 @@ Socket.prototype.unref = function() {


function afterConnect(status, handle, req, readable, writable) {
let self = handle[owner_symbol];

if (self.constructor.name === 'ReusedHandle') {
self = self.handle;
}
const self = handle[owner_symbol];

// Callback may come after call to destroy
if (self.destroyed) {
Expand Down
4 changes: 2 additions & 2 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ void AsyncWrap::EmitDestroy(bool from_gc) {

if (!persistent().IsEmpty() && !from_gc) {
HandleScope handle_scope(env()->isolate());
USE(object()->Set(env()->context(), env()->owner_symbol(), object()));
USE(object()->Set(env()->context(), env()->resource_symbol(), object()));
}
}

Expand Down Expand Up @@ -586,7 +586,7 @@ void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
Local<Object> obj = object();
CHECK(!obj.IsEmpty());
if (resource != obj) {
USE(obj->Set(env()->context(), env()->owner_symbol(), resource));
USE(obj->Set(env()->context(), env()->resource_symbol(), resource));
}
}

Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ constexpr size_t kFsStatsBufferLength =
V(oninit_symbol, "oninit") \
V(owner_symbol, "owner_symbol") \
V(onpskexchange_symbol, "onpskexchange") \
V(resource_symbol, "resource_symbol") \
V(trigger_async_id_symbol, "trigger_async_id_symbol") \

// Strings are per-isolate primitives but Environment proxies them
Expand Down
26 changes: 26 additions & 0 deletions test/async-hooks/test-async-local-storage-dgram.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict';

require('../common');

// Regression tests for https://github.com/nodejs/node/issues/40693

const assert = require('assert');
const dgram = require('dgram');
const { AsyncLocalStorage } = require('async_hooks');

dgram.createSocket('udp4')
.on('message', function(msg, rinfo) { this.send(msg, rinfo.port); })
.on('listening', function() {
const asyncLocalStorage = new AsyncLocalStorage();
const store = { val: 'abcd' };
asyncLocalStorage.run(store, () => {
const client = dgram.createSocket('udp4');
client.on('message', (msg, rinfo) => {
assert.deepStrictEqual(asyncLocalStorage.getStore(), store);
client.close();
this.close();
});
client.send('Hello, world!', this.address().port);
});
})
.bind(0);
27 changes: 27 additions & 0 deletions test/async-hooks/test-async-local-storage-socket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

require('../common');

// Regression tests for https://github.com/nodejs/node/issues/40693

const assert = require('assert');
const net = require('net');
const { AsyncLocalStorage } = require('async_hooks');

net
.createServer((socket) => {
socket.write('Hello, world!');
socket.pipe(socket);
RaisinTen marked this conversation as resolved.
Show resolved Hide resolved
})
.listen(0, function() {
const asyncLocalStorage = new AsyncLocalStorage();
const store = { val: 'abcd' };
asyncLocalStorage.run(store, () => {
const client = net.connect({ port: this.address().port });
client.on('data', () => {
assert.deepStrictEqual(asyncLocalStorage.getStore(), store);
client.end();
this.close();
});
});
});
36 changes: 36 additions & 0 deletions test/async-hooks/test-async-local-storage-tlssocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

// Regression tests for https://github.com/nodejs/node/issues/40693

const assert = require('assert');
const fixtures = require('../common/fixtures');
const tls = require('tls');
const { AsyncLocalStorage } = require('async_hooks');

const options = {
cert: fixtures.readKey('rsa_cert.crt'),
key: fixtures.readKey('rsa_private.pem'),
rejectUnauthorized: false
};

tls
.createServer(options, (socket) => {
socket.write('Hello, world!');
socket.pipe(socket);
})
.listen(0, function() {
const asyncLocalStorage = new AsyncLocalStorage();
const store = { val: 'abcd' };
asyncLocalStorage.run(store, () => {
const client = tls.connect({ port: this.address().port, ...options });
client.on('data', () => {
assert.deepStrictEqual(asyncLocalStorage.getStore(), store);
client.end();
this.close();
});
});
});
2 changes: 2 additions & 0 deletions test/async-hooks/test-http-agent-handle-reuse-parallel.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,6 @@ function onExit() {
// Verify reuse handle has been wrapped
assert.strictEqual(first.type, second.type);
assert.ok(first.handle !== second.handle, 'Resource reused');
assert.ok(first.handle === second.handle.handle,
'Resource not wrapped correctly');
}
2 changes: 2 additions & 0 deletions test/async-hooks/test-http-agent-handle-reuse-serial.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,6 @@ function onExit() {
// Verify reuse handle has been wrapped
assert.strictEqual(first.type, second.type);
assert.ok(first.handle !== second.handle, 'Resource reused');
assert.ok(first.handle === second.handle.handle,
'Resource not wrapped correctly');
}