@@ -189,9 +189,9 @@ const int CONTEXT_GROUP_ID = 1;
189
189
190
190
class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
191
191
public:
192
- explicit ChannelImpl (V8Inspector* inspector,
193
- InspectorSessionDelegate* delegate)
194
- : delegate_(delegate) {
192
+ explicit ChannelImpl (const std::unique_ptr< V8Inspector>& inspector,
193
+ std::unique_ptr< InspectorSessionDelegate> delegate)
194
+ : delegate_(std::move( delegate) ) {
195
195
session_ = inspector->connect (1 , this , StringView ());
196
196
}
197
197
@@ -201,19 +201,11 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
201
201
session_->dispatchProtocolMessage (message);
202
202
}
203
203
204
- bool waitForFrontendMessage () {
205
- return delegate_->WaitForFrontendMessageWhilePaused ();
206
- }
207
-
208
204
void schedulePauseOnNextStatement (const std::string& reason) {
209
205
std::unique_ptr<StringBuffer> buffer = Utf8ToStringView (reason);
210
206
session_->schedulePauseOnNextStatement (buffer->string (), buffer->string ());
211
207
}
212
208
213
- InspectorSessionDelegate* delegate () {
214
- return delegate_;
215
- }
216
-
217
209
private:
218
210
void sendResponse (
219
211
int callId,
@@ -232,7 +224,7 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
232
224
delegate_->SendMessageToFrontend (message);
233
225
}
234
226
235
- InspectorSessionDelegate* const delegate_;
227
+ std::unique_ptr< InspectorSessionDelegate> delegate_;
236
228
std::unique_ptr<v8_inspector::V8InspectorSession> session_;
237
229
};
238
230
@@ -300,8 +292,7 @@ class InspectorTimerHandle {
300
292
class NodeInspectorClient : public V8InspectorClient {
301
293
public:
302
294
NodeInspectorClient (node::Environment* env, node::NodePlatform* platform)
303
- : env_(env), platform_(platform), terminated_(false ),
304
- running_nested_loop_ (false ) {
295
+ : env_(env), platform_(platform) {
305
296
client_ = V8Inspector::create (env->isolate (), this );
306
297
// TODO(bnoordhuis) Make name configurable from src/node.cc.
307
298
ContextInfo info (GetHumanReadableProcessName ());
@@ -310,18 +301,28 @@ class NodeInspectorClient : public V8InspectorClient {
310
301
}
311
302
312
303
void runMessageLoopOnPause (int context_group_id) override {
313
- CHECK_NE (channel_, nullptr );
304
+ runMessageLoop (false );
305
+ }
306
+
307
+ void runMessageLoop (bool ignore_terminated) {
314
308
if (running_nested_loop_)
315
309
return ;
316
310
terminated_ = false ;
317
311
running_nested_loop_ = true ;
318
- while (!terminated_ && channel_-> waitForFrontendMessage ()) {
312
+ while ((ignore_terminated || !terminated_) && waitForFrontendEvent ()) {
319
313
while (platform_->FlushForegroundTasks (env_->isolate ())) {}
320
314
}
321
315
terminated_ = false ;
322
316
running_nested_loop_ = false ;
323
317
}
324
318
319
+ bool waitForFrontendEvent () {
320
+ InspectorIo* io = env_->inspector_agent ()->io ();
321
+ if (io == nullptr )
322
+ return false ;
323
+ return io->WaitForFrontendEvent ();
324
+ }
325
+
325
326
double currentTimeMS () override {
326
327
return uv_hrtime () * 1.0 / NANOS_PER_MSEC;
327
328
}
@@ -363,20 +364,22 @@ class NodeInspectorClient : public V8InspectorClient {
363
364
terminated_ = true ;
364
365
}
365
366
366
- void connectFrontend (InspectorSessionDelegate* delegate) {
367
- CHECK_EQ (channel_, nullptr );
368
- channel_ = std::unique_ptr<ChannelImpl>(
369
- new ChannelImpl (client_.get (), delegate));
367
+ int connectFrontend (std::unique_ptr<InspectorSessionDelegate> delegate) {
368
+ events_dispatched_ = true ;
369
+ int session_id = next_session_id_++;
370
+ channels_[session_id] =
371
+ std::make_unique<ChannelImpl>(client_, std::move (delegate));
372
+ return session_id;
370
373
}
371
374
372
- void disconnectFrontend () {
373
- quitMessageLoopOnPause () ;
374
- channel_. reset ( );
375
+ void disconnectFrontend (int session_id ) {
376
+ events_dispatched_ = true ;
377
+ channels_. erase (session_id );
375
378
}
376
379
377
- void dispatchMessageFromFrontend (const StringView& message) {
378
- CHECK_NE (channel_, nullptr ) ;
379
- channel_ ->dispatchProtocolMessage (message);
380
+ void dispatchMessageFromFrontend (int session_id, const StringView& message) {
381
+ events_dispatched_ = true ;
382
+ channels_[session_id] ->dispatchProtocolMessage (message);
380
383
}
381
384
382
385
Local<Context> ensureDefaultContextInGroup (int contextGroupId) override {
@@ -426,10 +429,6 @@ class NodeInspectorClient : public V8InspectorClient {
426
429
script_id);
427
430
}
428
431
429
- ChannelImpl* channel () {
430
- return channel_.get ();
431
- }
432
-
433
432
void startRepeatingTimer (double interval_s,
434
433
TimerCallback callback,
435
434
void * data) override {
@@ -464,20 +463,31 @@ class NodeInspectorClient : public V8InspectorClient {
464
463
client_->allAsyncTasksCanceled ();
465
464
}
466
465
466
+ void schedulePauseOnNextStatement (const std::string& reason) {
467
+ for (const auto & id_channel : channels_) {
468
+ id_channel.second ->schedulePauseOnNextStatement (reason);
469
+ }
470
+ }
471
+
472
+ bool hasConnectedSessions () {
473
+ return !channels_.empty ();
474
+ }
475
+
467
476
private:
468
477
node::Environment* env_;
469
478
node::NodePlatform* platform_;
470
- bool terminated_;
471
- bool running_nested_loop_;
479
+ bool terminated_ = false ;
480
+ bool running_nested_loop_ = false ;
472
481
std::unique_ptr<V8Inspector> client_;
473
- std::unique_ptr<ChannelImpl> channel_ ;
482
+ std::unordered_map< int , std:: unique_ptr<ChannelImpl>> channels_ ;
474
483
std::unordered_map<void *, InspectorTimerHandle> timers_;
484
+ int next_session_id_ = 1 ;
485
+ bool events_dispatched_ = false ;
475
486
};
476
487
477
488
Agent::Agent (Environment* env) : parent_env_(env),
478
489
client_ (nullptr ),
479
490
platform_(nullptr ),
480
- enabled_(false ),
481
491
pending_enable_async_hook_(false ),
482
492
pending_disable_async_hook_(false ) {}
483
493
@@ -491,7 +501,7 @@ bool Agent::Start(node::NodePlatform* platform, const char* path,
491
501
path_ = path == nullptr ? " " : path;
492
502
debug_options_ = options;
493
503
client_ =
494
- std::unique_ptr <NodeInspectorClient>(
504
+ std::shared_ptr <NodeInspectorClient>(
495
505
new NodeInspectorClient (parent_env_, platform));
496
506
platform_ = platform;
497
507
CHECK_EQ (0 , uv_async_init (uv_default_loop (),
@@ -515,7 +525,6 @@ bool Agent::StartIoThread(bool wait_for_connect) {
515
525
516
526
CHECK_NE (client_, nullptr );
517
527
518
- enabled_ = true ;
519
528
io_ = std::unique_ptr<InspectorIo>(
520
529
new InspectorIo (parent_env_, platform_, path_, debug_options_,
521
530
wait_for_connect));
@@ -554,20 +563,25 @@ void Agent::Stop() {
554
563
if (io_ != nullptr ) {
555
564
io_->Stop ();
556
565
io_.reset ();
557
- enabled_ = false ;
558
566
}
559
567
}
560
568
561
- void Agent::Connect (InspectorSessionDelegate* delegate) {
562
- enabled_ = true ;
563
- client_->connectFrontend (delegate);
569
+ std::unique_ptr<InspectorSession> Agent::Connect (
570
+ std::unique_ptr<InspectorSessionDelegate> delegate) {
571
+ int session_id = client_->connectFrontend (std::move (delegate));
572
+ return std::make_unique<InspectorSession>(session_id, client_);
564
573
}
565
574
566
575
void Agent::WaitForDisconnect () {
567
576
CHECK_NE (client_, nullptr );
568
577
client_->contextDestroyed (parent_env_->context ());
569
578
if (io_ != nullptr ) {
570
579
io_->WaitForDisconnect ();
580
+ // There is a bug in V8 Inspector (https://crbug.com/834056) that
581
+ // calls V8InspectorClient::quitMessageLoopOnPause when a session
582
+ // disconnects. We are using this flag to ignore those calls so the message
583
+ // loop is spinning as long as there's a reason to expect inspector messages
584
+ client_->runMessageLoop (true );
571
585
}
572
586
}
573
587
@@ -578,33 +592,8 @@ void Agent::FatalException(Local<Value> error, Local<v8::Message> message) {
578
592
WaitForDisconnect ();
579
593
}
580
594
581
- void Agent::Dispatch (const StringView& message) {
582
- CHECK_NE (client_, nullptr );
583
- client_->dispatchMessageFromFrontend (message);
584
- }
585
-
586
- void Agent::Disconnect () {
587
- CHECK_NE (client_, nullptr );
588
- client_->disconnectFrontend ();
589
- }
590
-
591
- void Agent::RunMessageLoop () {
592
- CHECK_NE (client_, nullptr );
593
- client_->runMessageLoopOnPause (CONTEXT_GROUP_ID);
594
- }
595
-
596
- InspectorSessionDelegate* Agent::delegate () {
597
- CHECK_NE (client_, nullptr );
598
- ChannelImpl* channel = client_->channel ();
599
- if (channel == nullptr )
600
- return nullptr ;
601
- return channel->delegate ();
602
- }
603
-
604
595
void Agent::PauseOnNextJavascriptStatement (const std::string& reason) {
605
- ChannelImpl* channel = client_->channel ();
606
- if (channel != nullptr )
607
- channel->schedulePauseOnNextStatement (reason);
596
+ client_->schedulePauseOnNextStatement (reason);
608
597
}
609
598
610
599
void Agent::RegisterAsyncHook (Isolate* isolate,
@@ -699,5 +688,20 @@ bool Agent::IsWaitingForConnect() {
699
688
return debug_options_.wait_for_connect ();
700
689
}
701
690
691
+ bool Agent::HasConnectedSessions () {
692
+ return client_->hasConnectedSessions ();
693
+ }
694
+
695
+ InspectorSession::InspectorSession (int session_id,
696
+ std::shared_ptr<NodeInspectorClient> client)
697
+ : session_id_(session_id), client_(client) {}
698
+
699
+ InspectorSession::~InspectorSession () {
700
+ client_->disconnectFrontend (session_id_);
701
+ }
702
+
703
+ void InspectorSession::Dispatch (const StringView& message) {
704
+ client_->dispatchMessageFromFrontend (session_id_, message);
705
+ }
702
706
} // namespace inspector
703
707
} // namespace node
0 commit comments