Skip to content

Commit 29620c4

Browse files
committed
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 Backport-PR-URL: #35241 PR-URL: #32523 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 2e4536e commit 29620c4

File tree

7 files changed

+23
-44
lines changed

7 files changed

+23
-44
lines changed

‎src/env.h‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,9 @@ class Environment : public MemoryRetainer{
12731273
inlinevoidset_process_exit_handler(
12741274
std::function<void(Environment*, int)>&& handler);
12751275

1276+
voidRunAndClearNativeImmediates(bool only_refed = false);
1277+
voidRunAndClearInterrupts();
1278+
12761279
private:
12771280
inlinevoidThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
12781281
const char* errmsg);
@@ -1410,8 +1413,6 @@ class Environment : public MemoryRetainer{
14101413
// yet or already have been destroyed.
14111414
bool task_queues_async_initialized_ = false;
14121415

1413-
voidRunAndClearNativeImmediates(bool only_refed = false);
1414-
voidRunAndClearInterrupts();
14151416
std::atomic<Environment**> interrupt_data_{nullptr};
14161417
voidRequestInterruptFromV8();
14171418
staticvoidCheckImmediate(uv_check_t* handle);

‎src/inspector/main_thread_interface.cc‎

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include"main_thread_interface.h"
22

3+
#include"env-inl.h"
34
#include"node_mutex.h"
45
#include"v8-inspector.h"
56
#include"util-inl.h"
@@ -85,19 +86,6 @@ class CallRequest : public Request{
8586
Fn fn_;
8687
};
8788

88-
classDispatchMessagesTask : publicv8::Task{
89-
public:
90-
explicitDispatchMessagesTask(std::weak_ptr<MainThreadInterface> thread)
91-
: thread_(thread){}
92-
93-
voidRun() override{
94-
if (auto thread = thread_.lock()) thread->DispatchMessages();
95-
}
96-
97-
private:
98-
std::weak_ptr<MainThreadInterface> thread_;
99-
};
100-
10189
template <typename T>
10290
classAnotherThreadObjectReference{
10391
public:
@@ -212,36 +200,23 @@ class ThreadSafeDelegate : public InspectorSessionDelegate{
212200
} // namespace
213201

214202

215-
MainThreadInterface::MainThreadInterface(Agent* agent, uv_loop_t* loop,
216-
v8::Isolate* isolate,
217-
v8::Platform* platform)
218-
: agent_(agent), isolate_(isolate),
219-
platform_(platform){
220-
}
203+
MainThreadInterface::MainThreadInterface(Agent* agent) : agent_(agent){}
221204

222205
MainThreadInterface::~MainThreadInterface(){
223206
if (handle_)
224207
handle_->Reset();
225208
}
226209

227210
voidMainThreadInterface::Post(std::unique_ptr<Request> request){
211+
CHECK_NOT_NULL(agent_);
228212
Mutex::ScopedLock scoped_lock(requests_lock_);
229213
bool needs_notify = requests_.empty();
230214
requests_.push_back(std::move(request));
231215
if (needs_notify){
232-
if (isolate_ != nullptr && platform_ != nullptr){
233-
std::shared_ptr<v8::TaskRunner> taskrunner =
234-
platform_->GetForegroundTaskRunner(isolate_);
235-
std::weak_ptr<MainThreadInterface>* interface_ptr =
236-
new std::weak_ptr<MainThreadInterface>(shared_from_this());
237-
taskrunner->PostTask(
238-
std::make_unique<DispatchMessagesTask>(*interface_ptr));
239-
isolate_->RequestInterrupt([](v8::Isolate* isolate, void* opaque){
240-
std::unique_ptr<std::weak_ptr<MainThreadInterface>> interface_ptr{
241-
static_cast<std::weak_ptr<MainThreadInterface>*>(opaque) };
242-
if (auto iface = interface_ptr->lock()) iface->DispatchMessages();
243-
}, static_cast<void*>(interface_ptr));
244-
}
216+
std::weak_ptr<MainThreadInterface> weak_self{shared_from_this()};
217+
agent_->env()->RequestInterrupt([weak_self](Environment*){
218+
if (auto iface = weak_self.lock()) iface->DispatchMessages();
219+
});
245220
}
246221
incoming_message_cond_.Broadcast(scoped_lock);
247222
}
@@ -274,7 +249,7 @@ void MainThreadInterface::DispatchMessages(){
274249
std::swap(dispatching_message_queue_.front(), task);
275250
dispatching_message_queue_.pop_front();
276251

277-
v8::SealHandleScope seal_handle_scope(isolate_);
252+
v8::SealHandleScope seal_handle_scope(agent_->env()->isolate());
278253
task->Call(this);
279254
}
280255
} while (had_messages);

‎src/inspector/main_thread_interface.h‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ class MainThreadHandle : public std::enable_shared_from_this<MainThreadHandle>{
7272
classMainThreadInterface :
7373
public std::enable_shared_from_this<MainThreadInterface>{
7474
public:
75-
MainThreadInterface(Agent* agent, uv_loop_t*, v8::Isolate* isolate,
76-
v8::Platform* platform);
75+
explicitMainThreadInterface(Agent* agent);
7776
~MainThreadInterface();
7877

7978
voidDispatchMessages();
@@ -98,8 +97,6 @@ class MainThreadInterface :
9897
ConditionVariable incoming_message_cond_;
9998
// Used from any thread
10099
Agent* const agent_;
101-
v8::Isolate* const isolate_;
102-
v8::Platform* const platform_;
103100
std::shared_ptr<MainThreadHandle> handle_;
104101
std::unordered_map<int, std::unique_ptr<Deletable>> managed_objects_;
105102
};

‎src/inspector_agent.cc‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,7 @@ class NodeInspectorClient : public V8InspectorClient{
660660
std::shared_ptr<MainThreadHandle> getThreadHandle(){
661661
if (!interface_){
662662
interface_ = std::make_shared<MainThreadInterface>(
663-
env_->inspector_agent(), env_->event_loop(), env_->isolate(),
664-
env_->isolate_data()->platform());
663+
env_->inspector_agent());
665664
}
666665
return interface_->GetHandle();
667666
}
@@ -697,10 +696,9 @@ class NodeInspectorClient : public V8InspectorClient{
697696

698697
running_nested_loop_ = true;
699698

700-
MultiIsolatePlatform* platform = env_->isolate_data()->platform();
701699
while (shouldRunMessageLoop()){
702700
if (interface_) interface_->WaitForFrontendEvent();
703-
while (platform->FlushForegroundTasks(env_->isolate())){}
701+
env_->RunAndClearInterrupts();
704702
}
705703
running_nested_loop_ = false;
706704
}

‎src/inspector_agent.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class Agent{
116116
// Interface for interacting with inspectors in worker threads
117117
std::shared_ptr<WorkerManager> GetWorkerManager();
118118

119+
inline Environment* env() const{return parent_env_}
120+
119121
private:
120122
voidToggleAsyncHook(v8::Isolate* isolate,
121123
const v8::Global<v8::Function>& fn);

‎src/inspector_js_api.cc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class JSBindingsConnection : public AsyncWrap{
8383

8484
private:
8585
Environment* env_;
86-
JSBindingsConnection* connection_;
86+
BaseObjectPtr<JSBindingsConnection> connection_;
8787
};
8888

8989
JSBindingsConnection(Environment* env,

‎test/parallel/test-inspector-connect-main-thread.js‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ function doConsoleLog(arrayBuffer){
7676
// and do not interrupt the main code. Interrupting the code flow
7777
// can lead to unexpected behaviors.
7878
asyncfunctionensureListenerDoesNotInterrupt(session){
79+
// Make sure that the following code is not affected by the fact that it may
80+
// run inside an inspector message callback, during which other inspector
81+
// message callbacks (such as the one triggered by doConsoleLog()) would
82+
// not be processed.
83+
awaitnewPromise(setImmediate);
84+
7985
constcurrentTime=Date.now();
8086
letconsoleLogHappened=false;
8187
session.once('Runtime.consoleAPICalled',

0 commit comments

Comments
(0)