diff --git a/BUILD.bazel b/BUILD.bazel index 3be7da8f3b..1e0effe2af 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3249,6 +3249,8 @@ filegroup( "src/inspector/v8-debugger.h", "src/inspector/v8-debugger-agent-impl.cc", "src/inspector/v8-debugger-agent-impl.h", + "src/inspector/v8-debugger-barrier.cc", + "src/inspector/v8-debugger-barrier.h", "src/inspector/v8-debugger-id.cc", "src/inspector/v8-debugger-id.h", "src/inspector/v8-debugger-script.cc", diff --git a/include/v8-inspector.h b/include/v8-inspector.h index aa5a044afb..c88b307ef8 100644 --- a/include/v8-inspector.h +++ b/include/v8-inspector.h @@ -365,9 +365,12 @@ class V8_EXPORT V8Inspector { virtual void flushProtocolNotifications() = 0; }; enum ClientTrustLevel { kUntrusted, kFullyTrusted }; + enum SessionPauseState { kWaitingForDebugger, kNotWaitingForDebugger }; + // TODO(chromium:1352175): remove default value once downstream change lands. virtual std::unique_ptr connect( int contextGroupId, Channel*, StringView state, - ClientTrustLevel client_trust_level) { + ClientTrustLevel client_trust_level, + SessionPauseState = kNotWaitingForDebugger) { return nullptr; } diff --git a/src/d8/d8.cc b/src/d8/d8.cc index 31ed6d7526..264106094c 100644 --- a/src/d8/d8.cc +++ b/src/d8/d8.cc @@ -4175,7 +4175,8 @@ class InspectorClient : public v8_inspector::V8InspectorClient { inspector_ = v8_inspector::V8Inspector::create(isolate_, this); session_ = inspector_->connect(1, channel_.get(), v8_inspector::StringView(), - v8_inspector::V8Inspector::kFullyTrusted); + v8_inspector::V8Inspector::kFullyTrusted, + v8_inspector::V8Inspector::kNotWaitingForDebugger); context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this); inspector_->contextCreated(v8_inspector::V8ContextInfo( context, kContextGroupId, v8_inspector::StringView())); diff --git a/src/inspector/BUILD.gn b/src/inspector/BUILD.gn index 0a5e3a25ac..6a6ff4b818 100644 --- a/src/inspector/BUILD.gn +++ b/src/inspector/BUILD.gn @@ -125,6 +125,8 @@ v8_source_set("inspector") { "v8-console.h", "v8-debugger-agent-impl.cc", "v8-debugger-agent-impl.h", + "v8-debugger-barrier.cc", + "v8-debugger-barrier.h", "v8-debugger-id.cc", "v8-debugger-id.h", "v8-debugger-script.cc", diff --git a/src/inspector/v8-debugger-barrier.cc b/src/inspector/v8-debugger-barrier.cc new file mode 100644 index 0000000000..c20f3a19f1 --- /dev/null +++ b/src/inspector/v8-debugger-barrier.cc @@ -0,0 +1,19 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/inspector/v8-debugger-barrier.h" + +#include "include/v8-inspector.h" + +namespace v8_inspector { + +V8DebuggerBarrier::V8DebuggerBarrier(V8InspectorClient* client, + int contextGroupId) + : m_client(client), m_contextGroupId(contextGroupId) {} + +V8DebuggerBarrier::~V8DebuggerBarrier() { + m_client->runIfWaitingForDebugger(m_contextGroupId); +} + +} // namespace v8_inspector diff --git a/src/inspector/v8-debugger-barrier.h b/src/inspector/v8-debugger-barrier.h new file mode 100644 index 0000000000..f4dc29611b --- /dev/null +++ b/src/inspector/v8-debugger-barrier.h @@ -0,0 +1,28 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_INSPECTOR_V8_DEBUGGER_BARRIER_H_ +#define V8_INSPECTOR_V8_DEBUGGER_BARRIER_H_ + +namespace v8_inspector { + +class V8InspectorClient; + +// This class is used to synchronize multiple sessions issuing +// `Runtime.runIfWaitingForDebbuger` so that the global client +// `runIfWaitingForDebugger` method is only invoked when all +// sessions have invoked `Runtime.runIfWaitingForDebugger`. +class V8DebuggerBarrier { + public: + V8DebuggerBarrier(V8InspectorClient* client, int contextGroupId); + ~V8DebuggerBarrier(); + + private: + V8InspectorClient* const m_client; + int m_contextGroupId; +}; + +} // namespace v8_inspector + +#endif // V8_INSPECTOR_V8_DEBUGGER_BARRIER_H_ diff --git a/src/inspector/v8-inspector-impl.cc b/src/inspector/v8-inspector-impl.cc index 27bdd3e812..60ad12aece 100644 --- a/src/inspector/v8-inspector-impl.cc +++ b/src/inspector/v8-inspector-impl.cc @@ -44,6 +44,7 @@ #include "src/inspector/v8-console-message.h" #include "src/inspector/v8-console.h" #include "src/inspector/v8-debugger-agent-impl.h" +#include "src/inspector/v8-debugger-barrier.h" #include "src/inspector/v8-debugger-id.h" #include "src/inspector/v8-debugger.h" #include "src/inspector/v8-inspector-session-impl.h" @@ -147,11 +148,26 @@ std::unique_ptr V8InspectorImpl::createStackTrace( std::unique_ptr V8InspectorImpl::connect( int contextGroupId, V8Inspector::Channel* channel, StringView state, - ClientTrustLevel client_trust_level) { + ClientTrustLevel client_trust_level, SessionPauseState pause_state) { int sessionId = ++m_lastSessionId; + std::shared_ptr debuggerBarrier; + if (pause_state == kWaitingForDebugger) { + auto it = m_debuggerBarriers.find(contextGroupId); + if (it != m_debuggerBarriers.end()) { + // Note this will be empty in case a pre-existent barrier is already + // released. This is by design, as a released throttle is no longer + // efficient. + debuggerBarrier = it->second.lock(); + } else { + debuggerBarrier = + std::make_shared(m_client, contextGroupId); + m_debuggerBarriers.insert(it, {contextGroupId, debuggerBarrier}); + } + } std::unique_ptr session = V8InspectorSessionImpl::create(this, contextGroupId, sessionId, channel, - state, client_trust_level); + state, client_trust_level, + std::move(debuggerBarrier)); m_sessions[contextGroupId][sessionId] = session.get(); return std::move(session); } @@ -159,7 +175,10 @@ std::unique_ptr V8InspectorImpl::connect( void V8InspectorImpl::disconnect(V8InspectorSessionImpl* session) { auto& map = m_sessions[session->contextGroupId()]; map.erase(session->sessionId()); - if (map.empty()) m_sessions.erase(session->contextGroupId()); + if (map.empty()) { + m_sessions.erase(session->contextGroupId()); + m_debuggerBarriers.erase(session->contextGroupId()); + } } InspectedContext* V8InspectorImpl::getContext(int groupId, diff --git a/src/inspector/v8-inspector-impl.h b/src/inspector/v8-inspector-impl.h index 3be16b29f6..0d30cc59f9 100644 --- a/src/inspector/v8-inspector-impl.h +++ b/src/inspector/v8-inspector-impl.h @@ -49,6 +49,7 @@ class V8Console; class V8ConsoleMessageStorage; class V8Debugger; class V8DebuggerAgentImpl; +class V8DebuggerBarrier; class V8InspectorSessionImpl; class V8ProfilerAgentImpl; class V8RuntimeAgentImpl; @@ -81,7 +82,8 @@ class V8InspectorImpl : public V8Inspector { std::unique_ptr connect(int contextGroupId, V8Inspector::Channel*, StringView state, - ClientTrustLevel) override; + ClientTrustLevel, + SessionPauseState) override; void contextCreated(const V8ContextInfo&) override; void contextDestroyed(v8::Local) override; v8::MaybeLocal contextById(int contextId) override; @@ -178,6 +180,8 @@ class V8InspectorImpl : public V8Inspector { // contextGroupId -> sessionId -> session std::unordered_map> m_sessions; + // contextGroupId -> debugger barrier + std::unordered_map> m_debuggerBarriers; using ConsoleStorageMap = std::unordered_map>; diff --git a/src/inspector/v8-inspector-session-impl.cc b/src/inspector/v8-inspector-session-impl.cc index f7f3e10938..35dca5540d 100644 --- a/src/inspector/v8-inspector-session-impl.cc +++ b/src/inspector/v8-inspector-session-impl.cc @@ -17,6 +17,7 @@ #include "src/inspector/string-util.h" #include "src/inspector/v8-console-agent-impl.h" #include "src/inspector/v8-debugger-agent-impl.h" +#include "src/inspector/v8-debugger-barrier.h" #include "src/inspector/v8-debugger.h" #include "src/inspector/v8-heap-profiler-agent-impl.h" #include "src/inspector/v8-inspector-impl.h" @@ -90,15 +91,18 @@ int V8ContextInfo::executionContextId(v8::Local context) { std::unique_ptr V8InspectorSessionImpl::create( V8InspectorImpl* inspector, int contextGroupId, int sessionId, V8Inspector::Channel* channel, StringView state, - V8Inspector::ClientTrustLevel clientTrustLevel) { + V8Inspector::ClientTrustLevel clientTrustLevel, + std::shared_ptr debuggerBarrier) { return std::unique_ptr(new V8InspectorSessionImpl( - inspector, contextGroupId, sessionId, channel, state, clientTrustLevel)); + inspector, contextGroupId, sessionId, channel, state, clientTrustLevel, + std::move(debuggerBarrier))); } V8InspectorSessionImpl::V8InspectorSessionImpl( V8InspectorImpl* inspector, int contextGroupId, int sessionId, V8Inspector::Channel* channel, StringView savedState, - V8Inspector::ClientTrustLevel clientTrustLevel) + V8Inspector::ClientTrustLevel clientTrustLevel, + std::shared_ptr debuggerBarrier) : m_contextGroupId(contextGroupId), m_sessionId(sessionId), m_inspector(inspector), @@ -116,7 +120,8 @@ V8InspectorSessionImpl::V8InspectorSessionImpl( m_state->getBoolean("use_binary_protocol", &use_binary_protocol_); m_runtimeAgent.reset(new V8RuntimeAgentImpl( - this, this, agentState(protocol::Runtime::Metainfo::domainName))); + this, this, agentState(protocol::Runtime::Metainfo::domainName), + std::move(debuggerBarrier))); protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get()); m_debuggerAgent.reset(new V8DebuggerAgentImpl( diff --git a/src/inspector/v8-inspector-session-impl.h b/src/inspector/v8-inspector-session-impl.h index 9de8aa1b49..b5ca62fd52 100644 --- a/src/inspector/v8-inspector-session-impl.h +++ b/src/inspector/v8-inspector-session-impl.h @@ -21,6 +21,7 @@ class InjectedScript; class RemoteObjectIdBase; class V8ConsoleAgentImpl; class V8DebuggerAgentImpl; +class V8DebuggerBarrier; class V8InspectorImpl; class V8HeapProfilerAgentImpl; class V8ProfilerAgentImpl; @@ -35,7 +36,8 @@ class V8InspectorSessionImpl : public V8InspectorSession, static std::unique_ptr create( V8InspectorImpl*, int contextGroupId, int sessionId, V8Inspector::Channel*, StringView state, - v8_inspector::V8Inspector::ClientTrustLevel); + v8_inspector::V8Inspector::ClientTrustLevel, + std::shared_ptr); ~V8InspectorSessionImpl() override; V8InspectorSessionImpl(const V8InspectorSessionImpl&) = delete; V8InspectorSessionImpl& operator=(const V8InspectorSessionImpl&) = delete; @@ -105,7 +107,8 @@ class V8InspectorSessionImpl : public V8InspectorSession, private: V8InspectorSessionImpl(V8InspectorImpl*, int contextGroupId, int sessionId, V8Inspector::Channel*, StringView state, - V8Inspector::ClientTrustLevel); + V8Inspector::ClientTrustLevel, + std::shared_ptr); protocol::DictionaryValue* agentState(const String16& name); // protocol::FrontendChannel implementation. diff --git a/src/inspector/v8-runtime-agent-impl.cc b/src/inspector/v8-runtime-agent-impl.cc index 1a3ee11ba1..bd63fb6e77 100644 --- a/src/inspector/v8-runtime-agent-impl.cc +++ b/src/inspector/v8-runtime-agent-impl.cc @@ -241,11 +241,13 @@ Response ensureContext(V8InspectorImpl* inspector, int contextGroupId, V8RuntimeAgentImpl::V8RuntimeAgentImpl( V8InspectorSessionImpl* session, protocol::FrontendChannel* FrontendChannel, - protocol::DictionaryValue* state) + protocol::DictionaryValue* state, + std::shared_ptr debuggerBarrier) : m_session(session), m_state(state), m_frontend(FrontendChannel), m_inspector(session->inspector()), + m_debuggerBarrier(debuggerBarrier), m_enabled(false) {} V8RuntimeAgentImpl::~V8RuntimeAgentImpl() = default; @@ -491,11 +493,13 @@ Response V8RuntimeAgentImpl::releaseObjectGroup(const String16& objectGroup) { } Response V8RuntimeAgentImpl::runIfWaitingForDebugger() { - if (m_runIfWaitingForDebuggerCalled) return Response::Success(); - m_runIfWaitingForDebuggerCalled = true; - // The client implementation is resposible for checking if the session is - // actually waiting for debugger. m_runIfWaitingForDebuggerCalled only makes - // sure that the client implementation is invoked once per agent instance. + if (m_debuggerBarrier) { + m_debuggerBarrier.reset(); + return Response::Success(); + } + // TODO(chromium:1352175): the below is provisional until client-side changes + // land. The call should come through the barrier only once client properly + // communicates whether the session is waiting for debugger. m_inspector->client()->runIfWaitingForDebugger(m_session->contextGroupId()); return Response::Success(); } diff --git a/src/inspector/v8-runtime-agent-impl.h b/src/inspector/v8-runtime-agent-impl.h index 7ae40221e8..9e2ad27e56 100644 --- a/src/inspector/v8-runtime-agent-impl.h +++ b/src/inspector/v8-runtime-agent-impl.h @@ -49,6 +49,7 @@ class InjectedScript; class InspectedContext; class RemoteObjectIdBase; class V8ConsoleMessage; +class V8DebuggerBarrier; class V8InspectorImpl; class V8InspectorSessionImpl; @@ -58,7 +59,8 @@ using protocol::Maybe; class V8RuntimeAgentImpl : public protocol::Runtime::Backend { public: V8RuntimeAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, - protocol::DictionaryValue* state); + protocol::DictionaryValue* state, + std::shared_ptr); ~V8RuntimeAgentImpl() override; V8RuntimeAgentImpl(const V8RuntimeAgentImpl&) = delete; V8RuntimeAgentImpl& operator=(const V8RuntimeAgentImpl&) = delete; @@ -155,12 +157,12 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { protocol::DictionaryValue* m_state; protocol::Runtime::Frontend m_frontend; V8InspectorImpl* m_inspector; + std::shared_ptr m_debuggerBarrier; bool m_enabled; std::unordered_map>> m_compiledScripts; // Binding name -> executionContextIds mapping. std::unordered_map> m_activeBindings; - bool m_runIfWaitingForDebuggerCalled = false; }; } // namespace v8_inspector diff --git a/test/inspector/inspector-test.cc b/test/inspector/inspector-test.cc index dd78836f3a..f3cbaffa16 100644 --- a/test/inspector/inspector-test.cc +++ b/test/inspector/inspector-test.cc @@ -104,6 +104,9 @@ class UtilsExtension : public InspectorIsolateData::SetupGlobalTask { utils->Set(isolate, "interruptForMessages", v8::FunctionTemplate::New( isolate, &UtilsExtension::InterruptForMessages)); + utils->Set( + isolate, "waitForDebugger", + v8::FunctionTemplate::New(isolate, &UtilsExtension::WaitForDebugger)); global->Set(isolate, "utils", utils); } @@ -404,6 +407,19 @@ class UtilsExtension : public InspectorIsolateData::SetupGlobalTask { backend_runner_->InterruptForMessages(); } + static void WaitForDebugger(const v8::FunctionCallbackInfo& args) { + if (args.Length() != 2 || !args[0]->IsInt32() || !args[1]->IsFunction()) { + FATAL("Internal error: waitForDebugger(context_group_id, callback)."); + } + int context_group_id = args[0].As()->Value(); + RunSimpleAsyncTask( + backend_runner_, + [context_group_id](InspectorIsolateData* data) { + data->WaitForDebugger(context_group_id); + }, + args[1].As()); + } + static std::map> channels_; }; diff --git a/test/inspector/isolate-data.cc b/test/inspector/isolate-data.cc index d20b996e60..4776d45aef 100644 --- a/test/inspector/isolate-data.cc +++ b/test/inspector/isolate-data.cc @@ -163,9 +163,12 @@ int InspectorIsolateData::ConnectSession( v8_inspector::V8Inspector::Channel* channel) { v8::SealHandleScope seal_handle_scope(isolate()); int session_id = ++last_session_id_; - sessions_[session_id] = - inspector_->connect(context_group_id, channel, state, - v8_inspector::V8Inspector::kFullyTrusted); + sessions_[session_id] = inspector_->connect( + context_group_id, channel, state, + v8_inspector::V8Inspector::kFullyTrusted, + waiting_for_debugger_ + ? v8_inspector::V8Inspector::kWaitingForDebugger + : v8_inspector::V8Inspector::kNotWaitingForDebugger); context_group_by_session_[sessions_[session_id].get()] = context_group_id; return session_id; } @@ -438,6 +441,10 @@ void InspectorIsolateData::runMessageLoopOnPause(int) { task_runner_->RunMessageLoop(true); } +void InspectorIsolateData::runIfWaitingForDebugger(int) { + quitMessageLoopOnPause(); +} + void InspectorIsolateData::quitMessageLoopOnPause() { v8::SealHandleScope seal_handle_scope(isolate()); task_runner_->QuitMessageLoop(); @@ -507,6 +514,13 @@ bool InspectorIsolateData::AssociateExceptionData( this->isolate()->GetCurrentContext(), exception, key, value); } +void InspectorIsolateData::WaitForDebugger(int context_group_id) { + DCHECK(!waiting_for_debugger_); + waiting_for_debugger_ = true; + runMessageLoopOnPause(context_group_id); + waiting_for_debugger_ = false; +} + namespace { class StringBufferImpl : public v8_inspector::StringBuffer { public: diff --git a/test/inspector/isolate-data.h b/test/inspector/isolate-data.h index b942d255de..6b500b2ca8 100644 --- a/test/inspector/isolate-data.h +++ b/test/inspector/isolate-data.h @@ -106,6 +106,7 @@ class InspectorIsolateData : public v8_inspector::V8InspectorClient { bool AssociateExceptionData(v8::Local exception, v8::Local key, v8::Local value); + void WaitForDebugger(int context_group_id); private: static v8::MaybeLocal ModuleResolveCallback( @@ -126,6 +127,7 @@ class InspectorIsolateData : public v8_inspector::V8InspectorClient { v8::MaybeLocal memoryInfo(v8::Isolate* isolate, v8::Local) override; void runMessageLoopOnPause(int context_group_id) override; + void runIfWaitingForDebugger(int context_group_id) override; void quitMessageLoopOnPause() override; void installAdditionalCommandLineAPI(v8::Local, v8::Local) override; @@ -169,6 +171,7 @@ class InspectorIsolateData : public v8_inspector::V8InspectorClient { double current_time_ = 0.0; bool log_console_api_message_calls_ = false; bool log_max_async_call_stack_depth_changed_ = false; + bool waiting_for_debugger_ = false; v8::Global not_inspectable_private_; v8::Global resource_name_prefix_; v8::Global additional_console_api_; diff --git a/test/inspector/protocol-test.js b/test/inspector/protocol-test.js index 0e430d8afc..80d1ea982f 100644 --- a/test/inspector/protocol-test.js +++ b/test/inspector/protocol-test.js @@ -142,6 +142,12 @@ InspectorTest.ContextGroup = class { this.id = utils.createContextGroup(); } + waitForDebugger() { + return new Promise(resolve => { + utils.waitForDebugger(this.id, resolve); + }); + } + createContext(name) { utils.createContext(this.id, name || ''); } diff --git a/test/inspector/runtime/run-if-waiting-for-debugger-expected.txt b/test/inspector/runtime/run-if-waiting-for-debugger-expected.txt new file mode 100644 index 0000000000..e90b003193 --- /dev/null +++ b/test/inspector/runtime/run-if-waiting-for-debugger-expected.txt @@ -0,0 +1,12 @@ + +Running test: testTwoSessions +Tests Runtime.runIfWaitingForDebugger +session 1 resumed +session 2 resumed +execution resumed + +Running test: testSessionDisconnect +Tests Runtime.runIfWaitingForDebugger +session 1 resumed +session 2 disconnected +execution resumed diff --git a/test/inspector/runtime/run-if-waiting-for-debugger.js b/test/inspector/runtime/run-if-waiting-for-debugger.js new file mode 100644 index 0000000000..db3036e244 --- /dev/null +++ b/test/inspector/runtime/run-if-waiting-for-debugger.js @@ -0,0 +1,35 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +InspectorTest.runAsyncTestSuite([ + async function testTwoSessions() { + InspectorTest.log('Tests Runtime.runIfWaitingForDebugger'); + + const contextGroup = new InspectorTest.ContextGroup(); + const resumed = contextGroup.waitForDebugger().then(() => InspectorTest.log('execution resumed')); + + const session1 = contextGroup.connect(); + const session2 = contextGroup.connect(); + await session1.Protocol.Runtime.runIfWaitingForDebugger(); + InspectorTest.log('session 1 resumed'); + await session2.Protocol.Runtime.runIfWaitingForDebugger(); + InspectorTest.log('session 2 resumed'); + await resumed; + }, + + async function testSessionDisconnect() { + InspectorTest.log('Tests Runtime.runIfWaitingForDebugger'); + + const contextGroup = new InspectorTest.ContextGroup(); + const resumed = contextGroup.waitForDebugger().then(() => InspectorTest.log('execution resumed')); + + const session1 = contextGroup.connect(); + const session2 = contextGroup.connect(); + await session1.Protocol.Runtime.runIfWaitingForDebugger(); + InspectorTest.log('session 1 resumed'); + session2.disconnect(); + InspectorTest.log('session 2 disconnected'); + await resumed; + } +]); diff --git a/test/inspector/tasks.cc b/test/inspector/tasks.cc index 9a01555b2f..65271c8e78 100644 --- a/test/inspector/tasks.cc +++ b/test/inspector/tasks.cc @@ -14,6 +14,90 @@ namespace v8 { namespace internal { +void RunSyncTask(TaskRunner* task_runner, + std::function callback) { + class SyncTask : public TaskRunner::Task { + public: + SyncTask(v8::base::Semaphore* ready_semaphore, + std::function callback) + : ready_semaphore_(ready_semaphore), callback_(callback) {} + ~SyncTask() override = default; + bool is_priority_task() final { return true; } + + private: + void Run(InspectorIsolateData* data) override { + callback_(data); + if (ready_semaphore_) ready_semaphore_->Signal(); + } + + v8::base::Semaphore* ready_semaphore_; + std::function callback_; + }; + + v8::base::Semaphore ready_semaphore(0); + task_runner->Append(std::make_unique(&ready_semaphore, callback)); + ready_semaphore.Wait(); +} + +void RunSimpleAsyncTask(TaskRunner* task_runner, + std::function task, + v8::Local callback) { + class DispatchResponseTask : public TaskRunner::Task { + public: + explicit DispatchResponseTask(v8::Local callback) + : context_(callback->GetIsolate(), + callback->GetIsolate()->GetCurrentContext()), + client_callback_(callback->GetIsolate(), callback) {} + ~DispatchResponseTask() override = default; + + private: + bool is_priority_task() final { return true; } + void Run(InspectorIsolateData* data) override { + v8::HandleScope handle_scope(data->isolate()); + v8::Local context = context_.Get(data->isolate()); + v8::MicrotasksScope microtasks_scope(context, + v8::MicrotasksScope::kRunMicrotasks); + v8::Context::Scope context_scope(context); + (void)client_callback_.Get(data->isolate()) + ->Call(context, context->Global(), 0, nullptr); + } + v8::Global context_; + v8::Global client_callback_; + }; + + using TaskCallback = std::function; + + class TaskWrapper : public TaskRunner::Task { + public: + TaskWrapper(TaskCallback task, TaskRunner* client_task_runner, + std::unique_ptr response_task) + : task_(std::move(task)), + client_task_runner_(client_task_runner), + response_task_(std::move(response_task)) {} + + ~TaskWrapper() override = default; + + private: + bool is_priority_task() final { return true; } + void Run(InspectorIsolateData* data) override { + task_(data); + client_task_runner_->Append(std::move(response_task_)); + } + + TaskCallback task_; + TaskRunner* client_task_runner_; + std::unique_ptr response_task_; + }; + + v8::Local context = callback->GetIsolate()->GetCurrentContext(); + TaskRunner* response_task_runner = + InspectorIsolateData::FromContext(context)->task_runner(); + + auto response_task = std::make_unique(callback); + task_runner->Append(std::make_unique( + std::move(task), response_task_runner, std::move(response_task))); +} + void ExecuteStringTask::Run(InspectorIsolateData* data) { v8::HandleScope handle_scope(data->isolate()); v8::Local context = data->GetDefaultContext(context_group_id_); diff --git a/test/inspector/tasks.h b/test/inspector/tasks.h index e178c93766..9b909eb12c 100644 --- a/test/inspector/tasks.h +++ b/test/inspector/tasks.h @@ -20,29 +20,11 @@ namespace v8 { namespace internal { -template -void RunSyncTask(TaskRunner* task_runner, T callback) { - class SyncTask : public TaskRunner::Task { - public: - SyncTask(v8::base::Semaphore* ready_semaphore, T callback) - : ready_semaphore_(ready_semaphore), callback_(callback) {} - ~SyncTask() override = default; - bool is_priority_task() final { return true; } - - private: - void Run(InspectorIsolateData* data) override { - callback_(data); - if (ready_semaphore_) ready_semaphore_->Signal(); - } - - v8::base::Semaphore* ready_semaphore_; - T callback_; - }; - - v8::base::Semaphore ready_semaphore(0); - task_runner->Append(std::make_unique(&ready_semaphore, callback)); - ready_semaphore.Wait(); -} +void RunSyncTask(TaskRunner* task_runner, + std::function callback); +void RunSimpleAsyncTask(TaskRunner* task_runner, + std::function task, + v8::Local callback); class SendMessageToBackendTask : public TaskRunner::Task { public: