17
17
#include " libplatform/libplatform.h"
18
18
19
19
#include < string.h>
20
+ #include < utility>
20
21
#include < vector>
21
22
22
23
// We need pid to use as ID with Chrome
31
32
namespace node {
32
33
namespace {
33
34
35
+ const char TAG_CONNECT[] = " #connect" ;
36
+ const char TAG_DISCONNECT[] = " #disconnect" ;
37
+
34
38
const char DEVTOOLS_PATH[] = " /node" ;
35
39
const char DEVTOOLS_HASH[] = " 521e5b7e2b7cc66b4006a8a54cb9c4e57494a5ef" ;
36
40
@@ -154,7 +158,6 @@ bool RespondToGet(inspector_socket_t* socket, const char* path, int port) {
154
158
namespace inspector {
155
159
156
160
using blink::protocol::DictionaryValue;
157
- using blink::protocol::String16;
158
161
159
162
class AgentImpl {
160
163
public:
@@ -171,24 +174,27 @@ class AgentImpl {
171
174
void WaitForDisconnect ();
172
175
173
176
private:
177
+ using MessageQueue = std::vector<std::pair<int , String16>>;
178
+
174
179
static void ThreadCbIO (void * agent);
175
180
static void OnSocketConnectionIO (uv_stream_t * server, int status);
176
181
static bool OnInspectorHandshakeIO (inspector_socket_t * socket,
177
182
enum inspector_handshake_event state,
178
183
const char * path);
179
- static void OnRemoteDataIO (uv_stream_t * stream, ssize_t read,
180
- const uv_buf_t * b);
181
184
static void WriteCbIO (uv_async_t * async);
182
185
183
186
void WorkerRunIO ();
184
187
void OnInspectorConnectionIO (inspector_socket_t * socket);
185
- void PushPendingMessage (std::vector<std::string>* queue,
186
- const std::string& message);
187
- void SwapBehindLock (std::vector<std::string> AgentImpl::*queue,
188
- std::vector<std::string>* output);
188
+ void OnRemoteDataIO (inspector_socket_t * stream, ssize_t read,
189
+ const uv_buf_t * b);
189
190
void PostMessages ();
190
191
void SetConnected (bool connected);
191
- void Write (const std::string& message);
192
+ void DispatchMessages ();
193
+ void Write (int session_id, const String16& message);
194
+ void AppendMessage (MessageQueue* vector, int session_id,
195
+ const String16& message);
196
+ void SwapBehindLock (MessageQueue* vector1, MessageQueue* vector2);
197
+ void PostIncomingMessage (const String16& message);
192
198
193
199
uv_sem_t start_sem_;
194
200
ConditionVariable pause_cond_;
@@ -208,27 +214,36 @@ class AgentImpl {
208
214
inspector_socket_t * client_socket_;
209
215
blink::V8Inspector* inspector_;
210
216
v8::Platform* platform_;
211
- std::vector<std::string> message_queue_ ;
212
- std::vector<std::string> outgoing_message_queue_;
217
+ MessageQueue incoming_message_queue_ ;
218
+ MessageQueue outgoing_message_queue_;
213
219
bool dispatching_messages_;
220
+ int frontend_session_id_;
221
+ int backend_session_id_;
214
222
215
223
friend class ChannelImpl ;
216
224
friend class DispatchOnInspectorBackendTask ;
217
225
friend class SetConnectedTask ;
218
226
friend class V8NodeInspector ;
219
227
friend void InterruptCallback (v8::Isolate*, void * agent);
228
+ friend void DataCallback (uv_stream_t * stream, ssize_t read,
229
+ const uv_buf_t * buf);
220
230
};
221
231
222
232
void InterruptCallback (v8::Isolate*, void * agent) {
223
- static_cast <AgentImpl*>(agent)->PostMessages ();
233
+ static_cast <AgentImpl*>(agent)->DispatchMessages ();
234
+ }
235
+
236
+ void DataCallback (uv_stream_t * stream, ssize_t read, const uv_buf_t * buf) {
237
+ inspector_socket_t * socket = static_cast <inspector_socket_t *>(stream->data );
238
+ static_cast <AgentImpl*>(socket->data )->OnRemoteDataIO (socket, read , buf);
224
239
}
225
240
226
241
class DispatchOnInspectorBackendTask : public v8 ::Task {
227
242
public:
228
243
explicit DispatchOnInspectorBackendTask (AgentImpl* agent) : agent_(agent) {}
229
244
230
245
void Run () override {
231
- agent_->PostMessages ();
246
+ agent_->DispatchMessages ();
232
247
}
233
248
234
249
private:
@@ -251,27 +266,12 @@ class ChannelImpl final : public blink::protocol::FrontendChannel {
251
266
void flushProtocolNotifications () override { }
252
267
253
268
void sendMessageToFrontend (const String16& message) {
254
- agent_->Write (message. utf8 () );
269
+ agent_->Write (agent_-> frontend_session_id_ , message);
255
270
}
256
271
257
272
AgentImpl* const agent_;
258
273
};
259
274
260
- class SetConnectedTask : public v8 ::Task {
261
- public:
262
- SetConnectedTask (AgentImpl* agent, bool connected)
263
- : agent_(agent),
264
- connected_ (connected) {}
265
-
266
- void Run () override {
267
- agent_->SetConnected (connected_);
268
- }
269
-
270
- private:
271
- AgentImpl* agent_;
272
- bool connected_;
273
- };
274
-
275
275
class V8NodeInspector : public blink ::V8Inspector {
276
276
public:
277
277
V8NodeInspector (AgentImpl* agent, node::Environment* env,
@@ -320,7 +320,9 @@ AgentImpl::AgentImpl(Environment* env) : port_(0),
320
320
client_socket_(nullptr ),
321
321
inspector_(nullptr ),
322
322
platform_(nullptr ),
323
- dispatching_messages_(false ) {
323
+ dispatching_messages_(false ),
324
+ frontend_session_id_(0 ),
325
+ backend_session_id_(0 ) {
324
326
CHECK_EQ (0 , uv_sem_init (&start_sem_, 0 ));
325
327
memset (&data_written_, 0 , sizeof (data_written_));
326
328
memset (&io_thread_req_, 0 , sizeof (io_thread_req_));
@@ -355,10 +357,7 @@ void AgentImpl::Start(v8::Platform* platform, int port, bool wait) {
355
357
uv_sem_wait (&start_sem_);
356
358
357
359
if (wait ) {
358
- // Flush messages in case of wait to connect, see OnRemoteDataIO on how it
359
- // should be fixed.
360
- SetConnected (true );
361
- PostMessages ();
360
+ DispatchMessages ();
362
361
}
363
362
}
364
363
@@ -424,67 +423,54 @@ bool AgentImpl::OnInspectorHandshakeIO(inspector_socket_t* socket,
424
423
}
425
424
}
426
425
427
- // static
428
- void AgentImpl::OnRemoteDataIO (uv_stream_t * stream,
429
- ssize_t read,
430
- const uv_buf_t * b) {
431
- inspector_socket_t * socket = static_cast <inspector_socket_t *>(stream->data );
432
- AgentImpl* agent = static_cast <AgentImpl*>(socket->data );
433
- Mutex::ScopedLock scoped_lock (agent->pause_lock_ );
426
+ void AgentImpl::OnRemoteDataIO (inspector_socket_t * socket,
427
+ ssize_t read,
428
+ const uv_buf_t * buf) {
429
+ Mutex::ScopedLock scoped_lock (pause_lock_);
434
430
if (read > 0 ) {
435
- std::string str (b->base , read );
436
- agent->PushPendingMessage (&agent->message_queue_ , str);
437
- free (b->base );
438
-
431
+ String16 str = String16::fromUTF8 (buf->base , read );
432
+ PostIncomingMessage (str);
439
433
// TODO(pfeldman): Instead of blocking execution while debugger
440
434
// engages, node should wait for the run callback from the remote client
441
435
// and initiate its startup. This is a change to node.cc that should be
442
436
// upstreamed separately.
443
- if (agent-> wait_ && str.find (" \" Runtime.run\" " ) != std::string::npos) {
444
- agent-> wait_ = false ;
445
- uv_sem_post (&agent-> start_sem_ );
437
+ if (wait_ && str.find (" \" Runtime.run\" " ) != std::string::npos) {
438
+ wait_ = false ;
439
+ uv_sem_post (&start_sem_);
446
440
}
447
441
448
- agent->platform_ ->CallOnForegroundThread (agent->parent_env_ ->isolate (),
449
- new DispatchOnInspectorBackendTask (agent));
450
- agent->parent_env_ ->isolate ()
451
- ->RequestInterrupt (InterruptCallback, agent);
452
- uv_async_send (&agent->data_written_ );
442
+ platform_->CallOnForegroundThread (parent_env_->isolate (),
443
+ new DispatchOnInspectorBackendTask (this ));
444
+ parent_env_->isolate ()->RequestInterrupt (InterruptCallback, this );
445
+ uv_async_send (&data_written_);
453
446
} else if (read <= 0 ) {
454
447
// EOF
455
- if (agent->client_socket_ == socket) {
456
- agent->client_socket_ = nullptr ;
457
- agent->platform_ ->CallOnForegroundThread (agent->parent_env_ ->isolate (),
458
- new SetConnectedTask (agent, false ));
459
- uv_async_send (&agent->data_written_ );
448
+ if (client_socket_ == socket) {
449
+ String16 message (TAG_DISCONNECT, sizeof (TAG_DISCONNECT) - 1 );
450
+ client_socket_ = nullptr ;
451
+ PostIncomingMessage (message);
460
452
}
461
453
DisconnectAndDisposeIO (socket);
462
454
}
463
- agent->pause_cond_ .Broadcast (scoped_lock);
464
- }
465
-
466
- void AgentImpl::PushPendingMessage (std::vector<std::string>* queue,
467
- const std::string& message) {
468
- Mutex::ScopedLock scoped_lock (queue_lock_);
469
- queue->push_back (message);
470
- }
471
-
472
- void AgentImpl::SwapBehindLock (std::vector<std::string> AgentImpl::*queue,
473
- std::vector<std::string>* output) {
474
- Mutex::ScopedLock scoped_lock (queue_lock_);
475
- (this ->*queue).swap (*output);
455
+ if (buf) {
456
+ free (buf->base );
457
+ }
458
+ pause_cond_.Broadcast (scoped_lock);
476
459
}
477
460
478
461
// static
479
462
void AgentImpl::WriteCbIO (uv_async_t * async) {
480
463
AgentImpl* agent = static_cast <AgentImpl*>(async->data );
481
464
inspector_socket_t * socket = agent->client_socket_ ;
482
465
if (socket) {
483
- std::vector<std::string> outgoing_messages;
484
- agent->SwapBehindLock (&AgentImpl::outgoing_message_queue_,
485
- &outgoing_messages);
486
- for (auto const & message : outgoing_messages)
487
- inspector_write (socket, message.c_str (), message.length ());
466
+ MessageQueue outgoing_messages;
467
+ agent->SwapBehindLock (&agent->outgoing_message_queue_ , &outgoing_messages);
468
+ for (const MessageQueue::value_type& outgoing : outgoing_messages) {
469
+ if (outgoing.first == agent->frontend_session_id_ ) {
470
+ std::string message = outgoing.second .utf8 ();
471
+ inspector_write (socket, message.c_str (), message.length ());
472
+ }
473
+ }
488
474
}
489
475
}
490
476
@@ -518,49 +504,70 @@ void AgentImpl::WorkerRunIO() {
518
504
uv_run (&child_loop_, UV_RUN_DEFAULT);
519
505
}
520
506
507
+ void AgentImpl::AppendMessage (MessageQueue* queue, int session_id,
508
+ const String16& message) {
509
+ Mutex::ScopedLock scoped_lock (queue_lock_);
510
+ queue->push_back (std::make_pair (session_id, message));
511
+ }
512
+
513
+ void AgentImpl::SwapBehindLock (MessageQueue* vector1, MessageQueue* vector2) {
514
+ Mutex::ScopedLock scoped_lock (queue_lock_);
515
+ vector1->swap (*vector2);
516
+ }
517
+
518
+ void AgentImpl::PostIncomingMessage (const String16& message) {
519
+ AppendMessage (&incoming_message_queue_, frontend_session_id_, message);
520
+ v8::Isolate* isolate = parent_env_->isolate ();
521
+ platform_->CallOnForegroundThread (isolate,
522
+ new DispatchOnInspectorBackendTask (this ));
523
+ isolate->RequestInterrupt (InterruptCallback, this );
524
+ uv_async_send (&data_written_);
525
+ }
526
+
521
527
void AgentImpl::OnInspectorConnectionIO (inspector_socket_t * socket) {
522
528
if (client_socket_) {
523
529
DisconnectAndDisposeIO (socket);
524
530
return ;
525
531
}
526
532
client_socket_ = socket;
527
- inspector_read_start (socket, OnBufferAlloc, AgentImpl::OnRemoteDataIO );
528
- platform_-> CallOnForegroundThread (parent_env_-> isolate (),
529
- new SetConnectedTask ( this , true ));
533
+ inspector_read_start (socket, OnBufferAlloc, DataCallback );
534
+ frontend_session_id_++;
535
+ PostIncomingMessage ( String16 (TAG_CONNECT, sizeof (TAG_CONNECT) - 1 ));
530
536
}
531
537
532
- void AgentImpl::PostMessages () {
538
+ void AgentImpl::DispatchMessages () {
533
539
if (dispatching_messages_)
534
540
return ;
535
541
dispatching_messages_ = true ;
536
- std::vector<std::string> messages;
537
- SwapBehindLock (&AgentImpl::message_queue_, &messages);
538
- for (auto const & message : messages)
539
- inspector_->dispatchMessageFromFrontend (
540
- String16::fromUTF8 (message.c_str (), message.length ()));
542
+ MessageQueue tasks;
543
+ SwapBehindLock (&incoming_message_queue_, &tasks);
544
+ for (const MessageQueue::value_type& pair : tasks) {
545
+ const String16& message = pair.second ;
546
+ if (message == TAG_CONNECT) {
547
+ CHECK_EQ (false , connected_);
548
+ backend_session_id_++;
549
+ connected_ = true ;
550
+ fprintf (stderr, " Debugger attached.\n " );
551
+ inspector_->connectFrontend (new ChannelImpl (this ));
552
+ } else if (message == TAG_DISCONNECT) {
553
+ CHECK (connected_);
554
+ connected_ = false ;
555
+ if (!shutting_down_)
556
+ PrintDebuggerReadyMessage (port_);
557
+ inspector_->quitMessageLoopOnPause ();
558
+ inspector_->disconnectFrontend ();
559
+ } else {
560
+ inspector_->dispatchMessageFromFrontend (message);
561
+ }
562
+ }
541
563
uv_async_send (&data_written_);
542
564
dispatching_messages_ = false ;
543
565
}
544
566
545
- void AgentImpl::SetConnected (bool connected) {
546
- if (connected_ == connected)
547
- return ;
548
-
549
- connected_ = connected;
550
- if (connected) {
551
- fprintf (stderr, " Debugger attached.\n " );
552
- inspector_->connectFrontend (new ChannelImpl (this ));
553
- } else {
554
- if (!shutting_down_)
555
- PrintDebuggerReadyMessage (port_);
556
- inspector_->quitMessageLoopOnPause ();
557
- inspector_->disconnectFrontend ();
558
- }
559
- }
560
-
561
- void AgentImpl::Write (const std::string& message) {
562
- PushPendingMessage (&outgoing_message_queue_, message);
563
- ASSERT_EQ (0 , uv_async_send (&io_thread_req_));
567
+ void AgentImpl::Write (int session_id, const String16& message) {
568
+ AppendMessage (&outgoing_message_queue_, session_id, message);
569
+ int err = uv_async_send (&io_thread_req_);
570
+ CHECK_EQ (0 , err);
564
571
}
565
572
566
573
// Exported class Agent
0 commit comments