From f972bd81c677782c0439b63cafa436f91eeffd78 Mon Sep 17 00:00:00 2001 From: Eugene Ostroukhov Date: Thu, 16 Feb 2017 14:45:56 -0800 Subject: [PATCH] inspector: libuv notification on incoming message Currently Inspector posts a V8 "task" when a message is incoming. To make sure messages are processed even when no JS is executed (e.g. while waiting for I/O or timer), inspector will now post a libuv request. Fixes: https://github.com/nodejs/node/issues/11589 PR-URL: https://github.com/nodejs/node/pull/11617 Reviewed-By: Ben Noordhuis --- src/inspector_agent.cc | 17 +++++++++++++---- test/inspector/inspector-helper.js | 21 ++++++++++++++++++--- test/inspector/test-not-blocked-on-idle.js | 20 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 test/inspector/test-not-blocked-on-idle.js diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index ae2e666384b5af..229bdfa36c6f55 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -159,6 +159,7 @@ class AgentImpl { static void ThreadCbIO(void* agent); static void WriteCbIO(uv_async_t* async); + static void MainThreadAsyncCb(uv_async_t* req); void InstallInspectorOnProcess(); @@ -190,6 +191,7 @@ class AgentImpl { node::Environment* parent_env_; uv_async_t io_thread_req_; + uv_async_t main_thread_req_; V8NodeInspector* inspector_; v8::Platform* platform_; MessageQueue incoming_message_queue_; @@ -334,6 +336,9 @@ AgentImpl::AgentImpl(Environment* env) : delegate_(nullptr), dispatching_messages_(false), session_id_(0), server_(nullptr) { + CHECK_EQ(0, uv_async_init(env->event_loop(), &main_thread_req_, + AgentImpl::MainThreadAsyncCb)); + uv_unref(reinterpret_cast(&main_thread_req_)); CHECK_EQ(0, uv_sem_init(&start_sem_, 0)); memset(&io_thread_req_, 0, sizeof(io_thread_req_)); } @@ -416,10 +421,7 @@ bool AgentImpl::Start(v8::Platform* platform, const char* path, InstallInspectorOnProcess(); - int err = uv_loop_init(&child_loop_); - CHECK_EQ(err, 0); - - err = uv_thread_create(&thread_, AgentImpl::ThreadCbIO, this); + int err = uv_thread_create(&thread_, AgentImpl::ThreadCbIO, this); CHECK_EQ(err, 0); uv_sem_wait(&start_sem_); @@ -606,6 +608,7 @@ void AgentImpl::PostIncomingMessage(InspectorAction action, int session_id, platform_->CallOnForegroundThread(isolate, new DispatchOnInspectorBackendTask(this)); isolate->RequestInterrupt(InterruptCallback, this); + CHECK_EQ(0, uv_async_send(&main_thread_req_)); } NotifyMessageReceived(); } @@ -662,6 +665,12 @@ void AgentImpl::DispatchMessages() { dispatching_messages_ = false; } +// static +void AgentImpl::MainThreadAsyncCb(uv_async_t* req) { + AgentImpl* agent = node::ContainerOf(&AgentImpl::main_thread_req_, req); + agent->DispatchMessages(); +} + void AgentImpl::Write(TransportAction action, int session_id, const StringView& inspector_message) { AppendMessage(&outgoing_message_queue_, action, session_id, diff --git a/test/inspector/inspector-helper.js b/test/inspector/inspector-helper.js index 3f3fe17e2e043e..beaf1a8aa1a3fd 100644 --- a/test/inspector/inspector-helper.js +++ b/test/inspector/inspector-helper.js @@ -427,9 +427,24 @@ Harness.prototype.expectShutDown = function(errorCode) { }); }; -exports.startNodeForInspectorTest = function(callback) { - const child = spawn(process.execPath, - [ '--inspect-brk', mainScript ]); +Harness.prototype.kill = function() { + return this.enqueue_((callback) => { + this.process_.kill(); + callback(); + }); +}; + +exports.startNodeForInspectorTest = function(callback, + inspectorFlag = '--inspect-brk', + opt_script_contents) { + const args = [inspectorFlag]; + if (opt_script_contents) { + args.push('-e', opt_script_contents); + } else { + args.push(mainScript); + } + + const child = spawn(process.execPath, args); const timeoutId = timeout('Child process did not start properly', 4); diff --git a/test/inspector/test-not-blocked-on-idle.js b/test/inspector/test-not-blocked-on-idle.js new file mode 100644 index 00000000000000..6d32888b44b802 --- /dev/null +++ b/test/inspector/test-not-blocked-on-idle.js @@ -0,0 +1,20 @@ +'use strict'; +require('../common'); +const helper = require('./inspector-helper.js'); + +function shouldShutDown(session) { + session + .sendInspectorCommands([ + { 'method': 'Debugger.enable' }, + { 'method': 'Debugger.pause' }, + ]) + .disconnect(true); +} + +function runTests(harness) { + // 1 second wait to make sure the inferior began running the script + setTimeout(() => harness.runFrontendSession([shouldShutDown]).kill(), 1000); +} + +const script = 'setInterval(() => {debugger;}, 60000);'; +helper.startNodeForInspectorTest(runTests, '--inspect', script);