2020namespace node {
2121namespace inspector {
2222namespace {
23+ using AsyncAndAgent = std::pair<uv_async_t , Agent*>;
2324using v8_inspector::StringBuffer;
2425using v8_inspector::StringView;
2526
@@ -96,6 +97,12 @@ int CloseAsyncAndLoop(uv_async_t* async) {
9697 return uv_loop_close (async->loop );
9798}
9899
100+ void ReleasePairOnAsyncClose (uv_handle_t * async) {
101+ AsyncAndAgent* pair = node::ContainerOf (&AsyncAndAgent::first,
102+ reinterpret_cast <uv_async_t *>(async));
103+ delete pair;
104+ }
105+
99106} // namespace
100107
101108std::unique_ptr<StringBuffer> Utf8ToStringView (const std::string& message) {
@@ -127,6 +134,9 @@ class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
127134 std::string GetTargetTitle (const std::string& id) override ;
128135 std::string GetTargetUrl (const std::string& id) override ;
129136 bool IsConnected () { return connected_; }
137+ void ServerDone () override {
138+ io_->ServerDone ();
139+ }
130140 private:
131141 InspectorIo* io_;
132142 bool connected_;
@@ -137,53 +147,70 @@ class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
137147 bool waiting_;
138148};
139149
140- void InterruptCallback (v8::Isolate*, void * io) {
141- static_cast <InspectorIo*>(io)->DispatchMessages ();
150+ void InterruptCallback (v8::Isolate*, void * agent) {
151+ InspectorIo* io = static_cast <Agent*>(agent)->io ();
152+ if (io != nullptr )
153+ io->DispatchMessages ();
142154}
143155
144- class DispatchOnInspectorBackendTask : public v8 ::Task {
156+ class DispatchMessagesTask : public v8 ::Task {
145157 public:
146- explicit DispatchOnInspectorBackendTask (InspectorIo* io ) : io_(io ) {}
158+ explicit DispatchMessagesTask (Agent* agent ) : agent_(agent ) {}
147159
148160 void Run () override {
149- io_->DispatchMessages ();
161+ InspectorIo* io = agent_->io ();
162+ if (io != nullptr )
163+ io->DispatchMessages ();
150164 }
151165
152166 private:
153- InspectorIo* io_ ;
167+ Agent* agent_ ;
154168};
155169
156170InspectorIo::InspectorIo (Environment* env, v8::Platform* platform,
157- const std::string& path, const DebugOptions& options)
171+ const std::string& path, const DebugOptions& options,
172+ bool wait_for_connect)
158173 : options_(options), thread_(), delegate_(nullptr ),
159- shutting_down_ (false ), state_(State::kNew ),
160- parent_env_(env), io_thread_req_(),
161- platform_(platform), dispatching_messages_(false ),
162- session_id_(0 ), script_name_(path) {
163- CHECK_EQ (0 , uv_async_init (env->event_loop (), &main_thread_req_,
174+ state_ (State::kNew ), parent_env_(env),
175+ io_thread_req_(), platform_(platform),
176+ dispatching_messages_(false ), session_id_(0 ),
177+ script_name_(path),
178+ wait_for_connect_(wait_for_connect) {
179+ main_thread_req_ = new AsyncAndAgent ({uv_async_t (), env->inspector_agent ()});
180+ CHECK_EQ (0 , uv_async_init (env->event_loop (), &main_thread_req_->first ,
164181 InspectorIo::MainThreadAsyncCb));
165- uv_unref (reinterpret_cast <uv_handle_t *>(&main_thread_req_));
182+ uv_unref (reinterpret_cast <uv_handle_t *>(&main_thread_req_-> first ));
166183 CHECK_EQ (0 , uv_sem_init (&start_sem_, 0 ));
167184}
168185
186+ InspectorIo::~InspectorIo () {
187+ uv_sem_destroy (&start_sem_);
188+ uv_close (reinterpret_cast <uv_handle_t *>(&main_thread_req_->first ),
189+ ReleasePairOnAsyncClose);
190+ }
191+
169192bool InspectorIo::Start () {
193+ CHECK_EQ (state_, State::kNew );
170194 CHECK_EQ (uv_thread_create (&thread_, InspectorIo::ThreadCbIO, this ), 0 );
171195 uv_sem_wait (&start_sem_);
172196
173197 if (state_ == State::kError ) {
174- Stop ();
175198 return false ;
176199 }
177200 state_ = State::kAccepting ;
178- if (options_. wait_for_connect () ) {
201+ if (wait_for_connect_ ) {
179202 DispatchMessages ();
180203 }
181204 return true ;
182205}
183206
184207void InspectorIo::Stop () {
208+ CHECK (state_ == State::kAccepting || state_ == State::kConnected );
209+ Write (TransportAction::kKill , 0 , StringView ());
185210 int err = uv_thread_join (&thread_);
186211 CHECK_EQ (err, 0 );
212+ state_ = State::kShutDown ;
213+ DispatchMessages ();
187214}
188215
189216bool InspectorIo::IsConnected () {
@@ -195,8 +222,10 @@ bool InspectorIo::IsStarted() {
195222}
196223
197224void InspectorIo::WaitForDisconnect () {
225+ if (state_ == State::kAccepting )
226+ state_ = State::kDone ;
198227 if (state_ == State::kConnected ) {
199- shutting_down_ = true ;
228+ state_ = State:: kShutDown ;
200229 Write (TransportAction::kStop , 0 , StringView ());
201230 fprintf (stderr, " Waiting for the debugger to disconnect...\n " );
202231 fflush (stderr);
@@ -222,6 +251,9 @@ void InspectorIo::WriteCbIO(uv_async_t* async) {
222251 io->SwapBehindLock (&io->outgoing_message_queue_ , &outgoing_messages);
223252 for (const auto & outgoing : outgoing_messages) {
224253 switch (std::get<0 >(outgoing)) {
254+ case TransportAction::kKill :
255+ io_and_transport->first ->TerminateConnections ();
256+ // Fallthrough
225257 case TransportAction::kStop :
226258 io_and_transport->first ->Stop (nullptr );
227259 break ;
@@ -253,7 +285,7 @@ void InspectorIo::WorkerRunIO() {
253285 uv_fs_req_cleanup (&req);
254286 }
255287 InspectorIoDelegate delegate (this , script_path, script_name_,
256- options_. wait_for_connect () );
288+ wait_for_connect_ );
257289 delegate_ = &delegate;
258290 InspectorSocketServer server (&delegate,
259291 options_.host_name (),
@@ -266,14 +298,12 @@ void InspectorIo::WorkerRunIO() {
266298 uv_sem_post (&start_sem_);
267299 return ;
268300 }
269- if (!options_. wait_for_connect () ) {
301+ if (!wait_for_connect_ ) {
270302 uv_sem_post (&start_sem_);
271303 }
272304 uv_run (&loop, UV_RUN_DEFAULT);
273305 io_thread_req_.data = nullptr ;
274- server.Stop (nullptr );
275- server.TerminateConnections (nullptr );
276- CHECK_EQ (CloseAsyncAndLoop (&io_thread_req_), 0 );
306+ CHECK_EQ (uv_loop_close (&loop), 0 );
277307 delegate_ = nullptr ;
278308}
279309
@@ -298,11 +328,12 @@ void InspectorIo::PostIncomingMessage(InspectorAction action, int session_id,
298328 const std::string& message) {
299329 if (AppendMessage (&incoming_message_queue_, action, session_id,
300330 Utf8ToStringView (message))) {
331+ Agent* agent = main_thread_req_->second ;
301332 v8::Isolate* isolate = parent_env_->isolate ();
302333 platform_->CallOnForegroundThread (isolate,
303- new DispatchOnInspectorBackendTask ( this ));
304- isolate->RequestInterrupt (InterruptCallback, this );
305- CHECK_EQ (0 , uv_async_send (&main_thread_req_));
334+ new DispatchMessagesTask (agent ));
335+ isolate->RequestInterrupt (InterruptCallback, agent );
336+ CHECK_EQ (0 , uv_async_send (&main_thread_req_-> first ));
306337 }
307338 NotifyMessageReceived ();
308339}
@@ -344,7 +375,7 @@ void InspectorIo::DispatchMessages() {
344375 break ;
345376 case InspectorAction::kEndSession :
346377 CHECK_NE (session_delegate_, nullptr );
347- if (shutting_down_ ) {
378+ if (state_ == State:: kShutDown ) {
348379 state_ = State::kDone ;
349380 } else {
350381 state_ = State::kAccepting ;
@@ -363,12 +394,18 @@ void InspectorIo::DispatchMessages() {
363394
364395// static
365396void InspectorIo::MainThreadAsyncCb (uv_async_t * req) {
366- InspectorIo* io = node::ContainerOf (&InspectorIo::main_thread_req_, req);
367- io->DispatchMessages ();
397+ AsyncAndAgent* pair = node::ContainerOf (&AsyncAndAgent::first, req);
398+ // Note that this may be called after io was closed or even after a new
399+ // one was created and ran.
400+ InspectorIo* io = pair->second ->io ();
401+ if (io != nullptr )
402+ io->DispatchMessages ();
368403}
369404
370405void InspectorIo::Write (TransportAction action, int session_id,
371406 const StringView& inspector_message) {
407+ if (state_ == State::kShutDown )
408+ return ;
372409 AppendMessage (&outgoing_message_queue_, action, session_id,
373410 StringBuffer::create (inspector_message));
374411 int err = uv_async_send (&io_thread_req_);
0 commit comments