pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/nodejs/node/commit/b2291296efb942f863f69b4be4d7059a123ebd7c

imer-b69241e157469407.css" /> inspector: split main thread interface from transport · nodejs/node@b229129 · GitHub
Skip to content

Commit b229129

Browse files
Eugene Ostroukhovtargos
authored andcommitted
inspector: split main thread interface from transport
Workers debugging will require interfacing between the "main" inspector and per-worker isolate inspectors. This is consistent with what WS interface does. This change is a refactoring change and does not change the functionality. PR-URL: #21182 Fixes: #21725 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 42d7539 commit b229129

14 files changed

+890
-634
lines changed

node.gyp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,12 +490,14 @@
490490
'src/inspector_js_api.cc',
491491
'src/inspector_socket.cc',
492492
'src/inspector_socket_server.cc',
493-
'src/inspector/tracing_agent.cc',
493+
'src/inspector/main_thread_interface.cc',
494494
'src/inspector/node_string.cc',
495+
'src/inspector/tracing_agent.cc',
495496
'src/inspector_agent.h',
496497
'src/inspector_io.h',
497498
'src/inspector_socket.h',
498499
'src/inspector_socket_server.h',
500+
'src/inspector/main_thread_interface.h',
499501
'src/inspector/node_string.h',
500502
'src/inspector/tracing_agent.h',
501503
'<@(node_inspector_generated_sources)'
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
#include "main_thread_interface.h"
2+
3+
#include "node_mutex.h"
4+
#include "v8-inspector.h"
5+
6+
#include <unicode/unistr.h>
7+
8+
namespace node {
9+
namespace inspector {
10+
namespace {
11+
12+
using v8_inspector::StringView;
13+
using v8_inspector::StringBuffer;
14+
15+
template <typename T>
16+
class DeleteRequest : public Request {
17+
public:
18+
explicit DeleteRequest(T* object) : object_(object) {}
19+
void Call() override {
20+
delete object_;
21+
}
22+
23+
private:
24+
T* object_;
25+
};
26+
27+
template <typename Target, typename Arg>
28+
class SingleArgumentFunctionCall : public Request {
29+
public:
30+
using Fn = void (Target::*)(Arg);
31+
32+
SingleArgumentFunctionCall(Target* target, Fn fn, Arg argument)
33+
: target_(target),
34+
fn_(fn),
35+
arg_(std::move(argument)) {}
36+
37+
void Call() override {
38+
Apply(target_, fn_, std::move(arg_));
39+
}
40+
41+
private:
42+
template <typename Element>
43+
void Apply(Element* target, Fn fn, Arg arg) {
44+
(target->*fn)(std::move(arg));
45+
}
46+
47+
Target* target_;
48+
Fn fn_;
49+
Arg arg_;
50+
};
51+
52+
class PostMessageRequest : public Request {
53+
public:
54+
PostMessageRequest(InspectorSessionDelegate* delegate,
55+
StringView message)
56+
: delegate_(delegate),
57+
message_(StringBuffer::create(message)) {}
58+
59+
void Call() override {
60+
delegate_->SendMessageToFrontend(message_->string());
61+
}
62+
63+
private:
64+
InspectorSessionDelegate* delegate_;
65+
std::unique_ptr<StringBuffer> message_;
66+
};
67+
68+
class DispatchMessagesTask : public v8::Task {
69+
public:
70+
explicit DispatchMessagesTask(MainThreadInterface* thread)
71+
: thread_(thread) {}
72+
73+
void Run() override {
74+
thread_->DispatchMessages();
75+
}
76+
77+
private:
78+
MainThreadInterface* thread_;
79+
};
80+
81+
void DisposePairCallback(uv_handle_t* ref) {
82+
using AsyncAndInterface = std::pair<uv_async_t, MainThreadInterface*>;
83+
AsyncAndInterface* pair = node::ContainerOf(
84+
&AsyncAndInterface::first, reinterpret_cast<uv_async_t*>(ref));
85+
delete pair;
86+
}
87+
88+
template <typename T>
89+
class AnotherThreadObjectReference {
90+
public:
91+
// We create it on whatever thread, just make sure it gets disposed on the
92+
// proper thread.
93+
AnotherThreadObjectReference(std::shared_ptr<MainThreadHandle> thread,
94+
T* object)
95+
: thread_(thread), object_(object) {
96+
}
97+
AnotherThreadObjectReference(AnotherThreadObjectReference&) = delete;
98+
99+
~AnotherThreadObjectReference() {
100+
// Disappearing thread may cause a memory leak
101+
CHECK(thread_->Post(
102+
std::unique_ptr<DeleteRequest<T>>(new DeleteRequest<T>(object_))));
103+
object_ = nullptr;
104+
}
105+
106+
template <typename Fn, typename Arg>
107+
void Post(Fn fn, Arg argument) const {
108+
using R = SingleArgumentFunctionCall<T, Arg>;
109+
thread_->Post(std::unique_ptr<R>(new R(object_, fn, std::move(argument))));
110+
}
111+
112+
T* get() const {
113+
return object_;
114+
}
115+
116+
private:
117+
std::shared_ptr<MainThreadHandle> thread_;
118+
T* object_;
119+
};
120+
121+
class MainThreadSessionState {
122+
public:
123+
MainThreadSessionState(
124+
std::shared_ptr<MainThreadHandle> thread,
125+
bool prevent_shutdown) : thread_(thread),
126+
prevent_shutdown_(prevent_shutdown) {}
127+
128+
void Connect(std::unique_ptr<InspectorSessionDelegate> delegate) {
129+
Agent* agent = thread_->GetInspectorAgent();
130+
if (agent != nullptr)
131+
session_ = agent->Connect(std::move(delegate), prevent_shutdown_);
132+
}
133+
134+
void Dispatch(std::unique_ptr<StringBuffer> message) {
135+
session_->Dispatch(message->string());
136+
}
137+
138+
private:
139+
std::shared_ptr<MainThreadHandle> thread_;
140+
bool prevent_shutdown_;
141+
std::unique_ptr<InspectorSession> session_;
142+
};
143+
144+
class CrossThreadInspectorSession : public InspectorSession {
145+
public:
146+
CrossThreadInspectorSession(
147+
int id,
148+
std::shared_ptr<MainThreadHandle> thread,
149+
std::unique_ptr<InspectorSessionDelegate> delegate,
150+
bool prevent_shutdown)
151+
: state_(thread, new MainThreadSessionState(thread, prevent_shutdown)) {
152+
state_.Post(&MainThreadSessionState::Connect, std::move(delegate));
153+
}
154+
155+
void Dispatch(const StringView& message) override {
156+
state_.Post(&MainThreadSessionState::Dispatch,
157+
StringBuffer::create(message));
158+
}
159+
160+
private:
161+
AnotherThreadObjectReference<MainThreadSessionState> state_;
162+
};
163+
164+
class ThreadSafeDelegate : public InspectorSessionDelegate {
165+
public:
166+
ThreadSafeDelegate(std::shared_ptr<MainThreadHandle> thread,
167+
std::unique_ptr<InspectorSessionDelegate> delegate)
168+
: thread_(thread), delegate_(thread, delegate.release()) {}
169+
170+
void SendMessageToFrontend(const v8_inspector::StringView& message) override {
171+
thread_->Post(std::unique_ptr<Request>(
172+
new PostMessageRequest(delegate_.get(), message)));
173+
}
174+
175+
private:
176+
std::shared_ptr<MainThreadHandle> thread_;
177+
AnotherThreadObjectReference<InspectorSessionDelegate> delegate_;
178+
};
179+
} // namespace
180+
181+
182+
MainThreadInterface::MainThreadInterface(Agent* agent, uv_loop_t* loop,
183+
v8::Isolate* isolate,
184+
v8::Platform* platform)
185+
: agent_(agent), isolate_(isolate),
186+
platform_(platform) {
187+
main_thread_request_.reset(new AsyncAndInterface(uv_async_t(), this));
188+
CHECK_EQ(0, uv_async_init(loop, &main_thread_request_->first,
189+
DispatchMessagesAsyncCallback));
190+
// Inspector uv_async_t should not prevent main loop shutdown.
191+
uv_unref(reinterpret_cast<uv_handle_t*>(&main_thread_request_->first));
192+
}
193+
194+
MainThreadInterface::~MainThreadInterface() {
195+
if (handle_)
196+
handle_->Reset();
197+
}
198+
199+
// static
200+
void MainThreadInterface::DispatchMessagesAsyncCallback(uv_async_t* async) {
201+
AsyncAndInterface* asyncAndInterface =
202+
node::ContainerOf(&AsyncAndInterface::first, async);
203+
asyncAndInterface->second->DispatchMessages();
204+
}
205+
206+
// static
207+
void MainThreadInterface::CloseAsync(AsyncAndInterface* pair) {
208+
uv_close(reinterpret_cast<uv_handle_t*>(&pair->first), DisposePairCallback);
209+
}
210+
211+
void MainThreadInterface::Post(std::unique_ptr<Request> request) {
212+
Mutex::ScopedLock scoped_lock(requests_lock_);
213+
bool needs_notify = requests_.empty();
214+
requests_.push_back(std::move(request));
215+
if (needs_notify) {
216+
CHECK_EQ(0, uv_async_send(&main_thread_request_->first));
217+
if (isolate_ != nullptr && platform_ != nullptr) {
218+
platform_->CallOnForegroundThread(isolate_,
219+
new DispatchMessagesTask(this));
220+
isolate_->RequestInterrupt([](v8::Isolate* isolate, void* thread) {
221+
static_cast<MainThreadInterface*>(thread)->DispatchMessages();
222+
}, this);
223+
}
224+
}
225+
incoming_message_cond_.Broadcast(scoped_lock);
226+
}
227+
228+
bool MainThreadInterface::WaitForFrontendEvent() {
229+
// We allow DispatchMessages reentry as we enter the pause. This is important
230+
// to support debugging the code invoked by an inspector call, such
231+
// as Runtime.evaluate
232+
dispatching_messages_ = false;
233+
if (dispatching_message_queue_.empty()) {
234+
Mutex::ScopedLock scoped_lock(requests_lock_);
235+
while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock);
236+
}
237+
return true;
238+
}
239+
240+
void MainThreadInterface::DispatchMessages() {
241+
if (dispatching_messages_)
242+
return;
243+
dispatching_messages_ = true;
244+
bool had_messages = false;
245+
do {
246+
if (dispatching_message_queue_.empty()) {
247+
Mutex::ScopedLock scoped_lock(requests_lock_);
248+
requests_.swap(dispatching_message_queue_);
249+
}
250+
had_messages = !dispatching_message_queue_.empty();
251+
while (!dispatching_message_queue_.empty()) {
252+
MessageQueue::value_type task;
253+
std::swap(dispatching_message_queue_.front(), task);
254+
dispatching_message_queue_.pop_front();
255+
task->Call();
256+
}
257+
} while (had_messages);
258+
dispatching_messages_ = false;
259+
}
260+
261+
std::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() {
262+
if (handle_ == nullptr)
263+
handle_ = std::make_shared<MainThreadHandle>(this);
264+
return handle_;
265+
}
266+
267+
std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string& message) {
268+
icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(
269+
icu::StringPiece(message.data(), message.length()));
270+
StringView view(reinterpret_cast<const uint16_t*>(utf16.getBuffer()),
271+
utf16.length());
272+
return StringBuffer::create(view);
273+
}
274+
275+
std::unique_ptr<InspectorSession> MainThreadHandle::Connect(
276+
std::unique_ptr<InspectorSessionDelegate> delegate,
277+
bool prevent_shutdown) {
278+
return std::unique_ptr<InspectorSession>(
279+
new CrossThreadInspectorSession(++next_session_id_,
280+
shared_from_this(),
281+
std::move(delegate),
282+
prevent_shutdown));
283+
}
284+
285+
bool MainThreadHandle::Post(std::unique_ptr<Request> request) {
286+
Mutex::ScopedLock scoped_lock(block_lock_);
287+
if (!main_thread_)
288+
return false;
289+
main_thread_->Post(std::move(request));
290+
return true;
291+
}
292+
293+
void MainThreadHandle::Reset() {
294+
Mutex::ScopedLock scoped_lock(block_lock_);
295+
main_thread_ = nullptr;
296+
}
297+
298+
Agent* MainThreadHandle::GetInspectorAgent() {
299+
Mutex::ScopedLock scoped_lock(block_lock_);
300+
if (main_thread_ == nullptr)
301+
return nullptr;
302+
return main_thread_->inspector_agent();
303+
}
304+
305+
std::unique_ptr<InspectorSessionDelegate>
306+
MainThreadHandle::MakeThreadSafeDelegate(
307+
std::unique_ptr<InspectorSessionDelegate> delegate) {
308+
return std::unique_ptr<InspectorSessionDelegate>(
309+
new ThreadSafeDelegate(shared_from_this(), std::move(delegate)));
310+
}
311+
312+
bool MainThreadHandle::Expired() {
313+
Mutex::ScopedLock scoped_lock(block_lock_);
314+
return main_thread_ == nullptr;
315+
}
316+
} // namespace inspector
317+
} // namespace node

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy