-
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
src: schedule unref immediate for uv_close in destructors #18307
src: schedule unref immediate for uv_close in destructors #18307
Conversation
CI: Stress test CI: So far no failures of the test in question... let's hope that remains the case. |
CI & stress test are both clean. |
Can we also make this deterministic by adding explicit gc to the test? That feels less complex and I'd like to be careful about delaying resource cleanup in an unrefed resource; I think this would e.g. lead to a memory leak in embedders that just wait for the loop to finish? |
@addaleax Sorry, missed your comment. The problem is that these (For example, we also don't call To be clear, I agree this is far from ideal but I also don't like papering over the issue by calling |
@apapirovski An embedder would run the loop until its empty if it wants proper cleanup … which is not really exposed by Node right now, that’s true. I know on some level this doesn’t “count”, but it’s what my Workers implementation (in Ayo) does, and I’d like to PR that some time in the next 1 or 2 months or so; for that I would basically have to re-do this PR with that approach. (Which is fine! I can’t expect you to do work just because my PR might need it. 😄) |
@addaleax Just so I'm not misunderstanding, wouldn't the cleanup code run in that case since the unrefed Immediate would run? (Just asking so I have full clarity on this, not trying to poke holes or something. I might be misunderstanding what we're discussing.) But either way, I'll keep thinking on this. I wasn't super happy with this solution but I'm also not super happy with the current approach. |
@apapirovski I guess you are right… my line of thinking was that there could be a situation where only the unrefed immediate was would be active, so the loop would stop. But if we’re spinning it anyway afterwards until everything is closed that doesn’t really matter… Maybe the real question here is what the API contract for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM if you want to land this
I think I’d still prefer the other approach, but I’ll keep thinking about it as well
I don't think it needs to be strictly "visible" but we should minimize arbitrary awakening via stuff like GC (since it's so heavily tied to timing and can also differ from platform to platform). Even just for the sake of avoiding false positives or negatives in our own tests. (For example, something like this can lead to a test involving an unintentionally unref'd handle succeeding because the GC keeps the loop alive for one more run.) Anyway, I'm marking as |
@@ -74,7 +69,12 @@ StatWatcher::StatWatcher(Environment* env, Local<Object> wrap) | |||
|
|||
StatWatcher::~StatWatcher() { | |||
Stop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I look at it... calling Stop() here is probably a minor (if harmless) bug as it in turn calls MakeWeak() when the destructor is almost certainly invoked from a weak callback.
You didn't introduce it so it's fine to leave it be for now but I figured I'd point it out.
I'm curious - was this caused by the |
@Fishrock123 It's likely but we would've had other issues due to the implementation before. That change was before my time but on the whole it seems positive after reviewing it in detail. Ultimately, we just need to be more mindful of GC-triggered operations. But still not sure of a good solution. 🤔 |
By the way, I think for some things we could also use a I think we’d even be allowed to call into JS in such a callback, but I would really prefer not to; having async_hooks callbacks fire at what is essentially a completely arbitrary point in your program doesn’t seem like a good idea… |
What shall we do here to progress further? |
Ping @apapirovski |
@BridgeAR Your guess is as good as mine. I don't love this solution. The issue is an extreme edge case and I haven't seen it on our CI lately. I would prefer to keep it open, if nothing else then as a reminder to myself to continue investigating. |
Investigating further would be great :) |
I am going to close this for now. I guess it would be best to open an issue if a reminder is still necessary. @apapirovski please feel free to reopen in case you want to work on it again. |
Instead of relying on garbage collection to close the timer handle, manage its state more explicitly. PR-URL: #21093 Fixes: #18190 Refs: #18307 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Instead of relying on garbage collection to close the handle, manage its state more explicitly. PR-URL: #21093 Fixes: #18190 Refs: #18307 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Instead of relying on garbage collection to close the timer handle, manage its state more explicitly. PR-URL: #21093 Fixes: #18190 Refs: #18307 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Instead of relying on garbage collection to close the handle, manage its state more explicitly. PR-URL: #21093 Fixes: #18190 Refs: #18307 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Instead of relying on garbage collection to close the timer handle, manage its state more explicitly. PR-URL: #21093 Fixes: #18190 Refs: #18307 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Instead of relying on garbage collection to close the handle, manage its state more explicitly. PR-URL: #21093 Fixes: #18190 Refs: #18307 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Calling
uv_close
directly in destructors seems to be problematic as it can bring a loop back alive afterEmitBeforeExit
. The problem is that this only happens sometimes as it depends on GC timing, making the behaviour of these two classes unpredictable.This PR should fix that behaviour and also (I think?) fix the flaky
sequential/test-async-wrap-getasyncid.js
test.Fixes: #18190
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
src