-
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: use env’s instead of isolate’s RequestInterrupt() + v8::Platform #32523
Conversation
Otherwise this potentially leads to race conditions when used in a multi-threaded environment (i.e. when used for its very purpose).
Fix this to account for the fact that `Stop()` may already have been called from a cleanup hook when the `inspector::Agent` is deleted along with the `Environment`, at which point cleanup hooks are no longer available.
This cleans up `Agent::RequestIoThreadStart()` significantly.
This simplifies the code significantly, and removes the dependency of the inspector code on the availability of a `MultiIsolatePlatform` (by removing the dependency on a platform altogether). It also fixes a memory leak that occurs when `RequestInterrupt()` is used, but the interrupt handler is never called before the Isolate is destroyed. One downside is that this leads to a slight change in timing, because inspector messages are not dispatched in a re-entrant way. This means having to harden one test to account for that possibility by making sure that the stack is always clear through a `setImmediate()`. This does not affect the assertion made by the test, which is that messages will not be delivered synchronously while other code is executing. nodejs#32415
@@ -84,7 +84,7 @@ class JSBindingsConnection : public AsyncWrap { | |||
|
|||
private: | |||
Environment* env_; | |||
JSBindingsConnection* connection_; | |||
BaseObjectPtr<JSBindingsConnection> connection_; |
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.
Btw, I’m not sure whether this is necessary anymore, but it was at one point while working on this, and it doesn’t hurt for the code to be a bit more robust here.
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, but someone more familiar with inspector code should review it as well.
Environment** interrupt_data = new Environment*(this); | ||
Environment** dummy = nullptr; | ||
if (!interrupt_data_.compare_exchange_strong(dummy, interrupt_data)) { | ||
delete interrupt_data; | ||
return; // Already scheduled. | ||
} |
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.
Maybe it's worth adding a comment here explaining what this code does.
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.
@mmarchini Done, PTAL :)
if (!interrupt_data_.compare_exchange_strong(dummy, interrupt_data)) { | ||
delete interrupt_data; | ||
return; // Already scheduled. | ||
} | ||
|
||
isolate()->RequestInterrupt([](Isolate* isolate, void* data) { |
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.
I don't remember if this callback runs asynchronously. Any chance we could get a situation where we request the interrupt here but don't run it before the Isolate is deleted? If that's possible, we would have a leak on interrupt_data
.
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.
Right – that is a possibility, but I don’t quite know what to do about it (without changing V8 APIs). The leak was already there before, too, and it’s limited to the size of a pointer…
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.
Actually, I have an idea. Let me see. :)
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.
Sure. If ASAN starts to complain, we can force it to ignore this pointer (for now ASAN is happy, so we can leave it as is).
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.
@mmarchini 7e75cc1 should address this by flushing interrupts when freeing the Environment instance … feels a bit like a hack to me but I think it’s the best we can do :)
This avoids an edge-case memory leak. Refs: nodejs#32523 (comment)
CI: https://ci.nodejs.org/job/node-test-pull-request/30145/ (:heavy_check_mark:) |
ping @mmarchini |
Otherwise this potentially leads to race conditions when used in a multi-threaded environment (i.e. when used for its very purpose). PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
Fix this to account for the fact that `Stop()` may already have been called from a cleanup hook when the `inspector::Agent` is deleted along with the `Environment`, at which point cleanup hooks are no longer available. PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This cleans up `Agent::RequestIoThreadStart()` significantly. PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This simplifies the code significantly, and removes the dependency of the inspector code on the availability of a `MultiIsolatePlatform` (by removing the dependency on a platform altogether). It also fixes a memory leak that occurs when `RequestInterrupt()` is used, but the interrupt handler is never called before the Isolate is destroyed. One downside is that this leads to a slight change in timing, because inspector messages are not dispatched in a re-entrant way. This means having to harden one test to account for that possibility by making sure that the stack is always clear through a `setImmediate()`. This does not affect the assertion made by the test, which is that messages will not be delivered synchronously while other code is executing. #32415 PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This avoids an edge-case memory leak. Refs: #32523 (comment) PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
Landed in d0a3bf1...a173473 |
Otherwise this potentially leads to race conditions when used in a multi-threaded environment (i.e. when used for its very purpose). PR-URL: nodejs#32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
Fix this to account for the fact that `Stop()` may already have been called from a cleanup hook when the `inspector::Agent` is deleted along with the `Environment`, at which point cleanup hooks are no longer available. PR-URL: nodejs#32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This cleans up `Agent::RequestIoThreadStart()` significantly. PR-URL: nodejs#32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This simplifies the code significantly, and removes the dependency of the inspector code on the availability of a `MultiIsolatePlatform` (by removing the dependency on a platform altogether). It also fixes a memory leak that occurs when `RequestInterrupt()` is used, but the interrupt handler is never called before the Isolate is destroyed. One downside is that this leads to a slight change in timing, because inspector messages are not dispatched in a re-entrant way. This means having to harden one test to account for that possibility by making sure that the stack is always clear through a `setImmediate()`. This does not affect the assertion made by the test, which is that messages will not be delivered synchronously while other code is executing. nodejs#32415 PR-URL: nodejs#32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This avoids an edge-case memory leak. Refs: nodejs#32523 (comment) PR-URL: nodejs#32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This ensures that microtasks scheduled by native immediates are run after the tasks are done. In particular, this affects the inspector integration since 6f9f546. Fixes: nodejs#33002 Refs: nodejs#32523 PR-URL: nodejs#34366 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: James M Snell <[email protected]>
Otherwise this potentially leads to race conditions when used in a multi-threaded environment (i.e. when used for its very purpose). Backport-PR-URL: #35241 PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
Fix this to account for the fact that `Stop()` may already have been called from a cleanup hook when the `inspector::Agent` is deleted along with the `Environment`, at which point cleanup hooks are no longer available. Backport-PR-URL: #35241 PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This cleans up `Agent::RequestIoThreadStart()` significantly. Backport-PR-URL: #35241 PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This simplifies the code significantly, and removes the dependency of the inspector code on the availability of a `MultiIsolatePlatform` (by removing the dependency on a platform altogether). It also fixes a memory leak that occurs when `RequestInterrupt()` is used, but the interrupt handler is never called before the Isolate is destroyed. One downside is that this leads to a slight change in timing, because inspector messages are not dispatched in a re-entrant way. This means having to harden one test to account for that possibility by making sure that the stack is always clear through a `setImmediate()`. This does not affect the assertion made by the test, which is that messages will not be delivered synchronously while other code is executing. #32415 Backport-PR-URL: #35241 PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This avoids an edge-case memory leak. Refs: #32523 (comment) Backport-PR-URL: #35241 PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
This ensures that microtasks scheduled by native immediates are run after the tasks are done. In particular, this affects the inspector integration since 6f9f546. Fixes: #33002 Refs: #32523 Backport-PR-URL: #35241 PR-URL: #34366 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: James M Snell <[email protected]>
src: make
Environment::interrupt_data_
atomicOtherwise this potentially leads to race conditions when used in a
multi-threaded environment (i.e. when used for its very purpose).
src: fix cleanup hook removal for InspectorTimer
Fix this to account for the fact that
Stop()
may already have beencalled from a cleanup hook when the
inspector::Agent
is deletedalong with the
Environment
, at which point cleanup hooks are nolonger available.
src: use env->RequestInterrupt() for inspector io thread start
This cleans up
Agent::RequestIoThreadStart()
significantly.src: use env->RequestInterrupt() for inspector MainThreadInterface
This simplifies the code significantly, and removes the dependency of
the inspector code on the availability of a
MultiIsolatePlatform
(by removing the dependency on a platform altogether).
It also fixes a memory leak that occurs when
RequestInterrupt()
is used, but the interrupt handler is never called before the Isolate
is destroyed.
One downside is that this leads to a slight change in timing, because
inspector messages are not dispatched in a re-entrant way. This means
having to harden one test to account for that possibility by making
sure that the stack is always clear through a
setImmediate()
.This does not affect the assertion made by the test, which is that
messages will not be delivered synchronously while other code is
executing.
#32415
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes