-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
AsyncWrap: TCPWrap created before MakeCallback #2986
Comments
The timing of all three callbacks are correct, but this an obvious deficiency in functionality. What if the parent was passed as an argument to the |
I did actually implement that locally. The only issue is that see: http://bl.ocks.org/AndreasMadsen/raw/4354435e99e8f7c35a5d/ One could properly "fix" the timings for |
This I hadn't considered. Was only thinking about making sure information about handle "ownership" propagated properly.
Can't ATM. Page dies w/ a JS error showing in the console. Could you write a basic test case w/ comments on what you'd expect to happen? I'm not fully understanding if you're using some sort of global state to keep track of what init callback are called while the before/after callbacks are called. Or what you're using that for. |
Yeah, sorry. At this stage it only works in Chrome. Here is a picture:
That is exactly what I'm doing. Here is the code If you are interested: https://github.com/AndreasMadsen/dprof/blob/master/dprof.js#L82L94
Sure, shouldn't be a problem. |
Here is a simple test case for what I initially expected to happen: https://gist.github.com/AndreasMadsen/ca42b0e7477d7209d4d7 |
Thanks for the example and reproduction. What about doing something like so instead: function asyncInit(parent) {
if (parent)
parent.owner._dprofState.add(this);
} I'm making the assumption that |
Now, I believe there's a bug properly propagating the parent, but if that sort of solution would work for you then I'll investigate getting that working sooner. |
Hmm, I'm not sure I understand what PS: |
@AndreasMadsen When you run: var server = net.createServer(); It returns a JS object. Once you call listen it internally does: this._handle = new TCP();
this._handle.owner = this; So they reference each other. What we can pass to JS from native is the |
Okay, I think we are on the same page then. But adding a property in There is a work around from the userland perspective. Assuming that the new handle belongs to the next callback of the parent handle, one could keep track of child handles and then backtrack what has happened. But it is not ideal. I did already try it, this is what I'm talking about in #2986 (comment). |
I think this is where the wires are mostly crossed. Internally it doesn't belong to any callback. It belongs to a handle instance. The handle just happens to call a callback to let us know that another handle has been created. But this isn't consistent. For example, with the http module the user isn't alerted that a connection has been received until all the headers have been parsed. But async wrap will let you know the moment a connection was received. Likewise, any |
What I'm trying to say is that I would like that to be consistent. But maybe we should take that as a separate issue and just ensure that the handle context is always known for now. Adding the parent handle as an argument as I have done in AndreasMadsen@04d4fad, is however not enough to always know the context. For example in the HTTP case you mentioned, I'm still missing the handle context in a few cases. It appears to be because the I guess it makes sense, because the HTTPParser is invoked though a pool of parsers, so the handle parent changes, but it is a big issue in terms of handle context. However you properly know more about. example and result: 'use strict';
const http = require('http');
const server = http.createServer(function (req, res) {
res.end('hallo world');
});
server.listen(0, 'localhost', function () {
const addr = server.address();
const req = http.get(`http://${addr.address}:${addr.port}`, function (res) {
res.resume();
res.once('end', server.close.bind(server));
});
}); dprof dump: http://bl.ocks.org/AndreasMadsen/raw/e2a9fb08ee6813c5663a/ |
Not trying to say that it is enough. Simply that both approaches are necessary because neither can capture all cases. I agree that consistency would be optimal, but it's technically not possible. The reason I implemented passing the parent is so you can capture which Server an incoming Socket came from: https://github.com/nodejs/node/blob/v4.1.1/src/tcp_wrap.cc#L258-L260
Its' because |
#3216 solves this particular issue. |
Previous logic didn't allow parent to propagate to the init callback properly. The fix now allows the init callback to be called and receive the parent if: - async wrap callbacks are enabled and parent exists - the init callback has been called on the parent and an init callback exists then it will be called regardless of whether async wrap callbacks are disabled. Change the init/pre/post callback checks to see if it has been properly set. This allows removal of the Environment "using_asyncwrap" variable. Pass Isolate to a TryCatch instance. Fixes: #2986 PR-URL: #3216 Reviewed-By: Rod Vagg <rod@vagg.org>
Previous logic didn't allow parent to propagate to the init callback properly. The fix now allows the init callback to be called and receive the parent if: - async wrap callbacks are enabled and parent exists - the init callback has been called on the parent and an init callback exists then it will be called regardless of whether async wrap callbacks are disabled. Change the init/pre/post callback checks to see if it has been properly set. This allows removal of the Environment "using_asyncwrap" variable. Pass Isolate to a TryCatch instance. Fixes: #2986 PR-URL: #3216 Reviewed-By: Rod Vagg <rod@vagg.org>
When creating a TCP server, the TCP handles there holds the socket is created in C++ land. The socket handle is then send to the
onconnection
server handle event using MakeCallback.code link: https://github.com/nodejs/node/blob/master/src/tcp_wrap.cc#L259L272
Because the socket handle is created before
MakeCallback
, theasync_hooks_init_function
for the socket handle is called beforeasync_hooks_before_function
for the server handle. This makes it impossible to trace back the origin of the socket handle.dprof dump: http://bl.ocks.org/AndreasMadsen/raw/da3adb776bdfcf30f97f/ - Notice the free hanging blue line, which has an origin from nowhere.
edit: the link is only tested in Chrome, so here is a picture
The visualization/test was done with the following code:
This issue appears to be caused by 7dde95a8bd. I agree that is is wired to call
async_hooks_before_function
in theAsyncWrap
constructor, particularly in this case because it suggests that the creation of theTCPWrap
object andonconnection
happens in two different async turns.However I'm not sure what the proper fix would be.
/cc @trevnorris
The text was updated successfully, but these errors were encountered: