mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
src: fix Worker termination in inspector.waitForDebugger
Signed-off-by: Daeyeon Jeong <daeyeon.dev@gmail.com> PR-URL: https://github.com/nodejs/node/pull/52527 Fixes: https://github.com/nodejs/node/issues/52467 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Kohei Ueno <kohei.ueno119@gmail.com>
This commit is contained in:
1 parent
78dbda1bd3
commit
ac5f8f0516
6 files changed
+91
-1
No files matched your search
@@ -1110,6 +1110,13 @@ void Environment::InitializeCompileCache() {
|
||||
void Environment::ExitEnv(StopFlags::Flags flags) {
|
||||
// Should not access non-thread-safe methods here.
|
||||
set_stopping(true);
|
||||
|
||||
#if HAVE_INSPECTOR
|
||||
if (inspector_agent_) {
|
||||
inspector_agent_->StopIfWaitingForConnect();
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((flags & StopFlags::kDoNotTerminateIsolate) == 0)
|
||||
isolate_->TerminateExecution();
|
||||
SetImmediateThreadsafe([](Environment* env) {
|
||||
|
||||
@@ -225,11 +225,20 @@ bool MainThreadInterface::WaitForFrontendEvent() {
|
||||
dispatching_messages_ = false;
|
||||
if (dispatching_message_queue_.empty()) {
|
||||
Mutex::ScopedLock scoped_lock(requests_lock_);
|
||||
while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock);
|
||||
while (!stop_waiting_for_frontend_event_requested_ && requests_.empty()) {
|
||||
incoming_message_cond_.Wait(scoped_lock);
|
||||
}
|
||||
stop_waiting_for_frontend_event_requested_ = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainThreadInterface::StopWaitingForFrontendEvent() {
|
||||
Mutex::ScopedLock scoped_lock(requests_lock_);
|
||||
stop_waiting_for_frontend_event_requested_ = true;
|
||||
incoming_message_cond_.Broadcast(scoped_lock);
|
||||
}
|
||||
|
||||
void MainThreadInterface::DispatchMessages() {
|
||||
if (dispatching_messages_)
|
||||
return;
|
||||
|
||||
@@ -78,6 +78,7 @@ class MainThreadInterface :
|
||||
void DispatchMessages();
|
||||
void Post(std::unique_ptr<Request> request);
|
||||
bool WaitForFrontendEvent();
|
||||
void StopWaitingForFrontendEvent();
|
||||
std::shared_ptr<MainThreadHandle> GetHandle();
|
||||
Agent* inspector_agent() {
|
||||
return agent_;
|
||||
@@ -94,6 +95,10 @@ class MainThreadInterface :
|
||||
// when we reenter the DispatchMessages function.
|
||||
MessageQueue dispatching_message_queue_;
|
||||
bool dispatching_messages_ = false;
|
||||
// This flag indicates an internal request to exit the loop in
|
||||
// WaitForFrontendEvent(). It's set to true by calling
|
||||
// StopWaitingForFrontendEvent().
|
||||
bool stop_waiting_for_frontend_event_requested_ = false;
|
||||
ConditionVariable incoming_message_cond_;
|
||||
// Used from any thread
|
||||
Agent* const agent_;
|
||||
|
||||
@@ -477,6 +477,20 @@ class NodeInspectorClient : public V8InspectorClient {
|
||||
}
|
||||
}
|
||||
|
||||
void StopIfWaitingForFrontendEvent() {
|
||||
if (!waiting_for_frontend_) {
|
||||
return;
|
||||
}
|
||||
waiting_for_frontend_ = false;
|
||||
for (const auto& id_channel : channels_) {
|
||||
id_channel.second->unsetWaitingForDebugger();
|
||||
}
|
||||
|
||||
if (interface_) {
|
||||
interface_->StopWaitingForFrontendEvent();
|
||||
}
|
||||
}
|
||||
|
||||
int connectFrontend(std::unique_ptr<InspectorSessionDelegate> delegate,
|
||||
bool prevent_shutdown) {
|
||||
int session_id = next_session_id_++;
|
||||
@@ -1024,6 +1038,13 @@ void Agent::WaitForConnect() {
|
||||
client_->waitForFrontend();
|
||||
}
|
||||
|
||||
void Agent::StopIfWaitingForConnect() {
|
||||
if (client_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
client_->StopIfWaitingForFrontendEvent();
|
||||
}
|
||||
|
||||
std::shared_ptr<WorkerManager> Agent::GetWorkerManager() {
|
||||
THROW_IF_INSUFFICIENT_PERMISSIONS(parent_env_,
|
||||
permission::PermissionScope::kInspector,
|
||||
|
||||
@@ -61,6 +61,8 @@ class Agent {
|
||||
|
||||
// Blocks till frontend connects and sends "runIfWaitingForDebugger"
|
||||
void WaitForConnect();
|
||||
void StopIfWaitingForConnect();
|
||||
|
||||
// Blocks till all the sessions with "WaitForDisconnectOnShutdown" disconnect
|
||||
void WaitForDisconnect();
|
||||
void ReportUncaughtException(v8::Local<v8::Value> error,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
common.skipIfInspectorDisabled();
|
||||
|
||||
const { parentPort, workerData, Worker } = require('node:worker_threads');
|
||||
if (!workerData) {
|
||||
common.skipIfWorker();
|
||||
}
|
||||
|
||||
const inspector = require('node:inspector');
|
||||
const assert = require('node:assert');
|
||||
|
||||
let TIMEOUT = common.platformTimeout(5000);
|
||||
if (common.isWindows) {
|
||||
// Refs: https://github.com/nodejs/build/issues/3014
|
||||
TIMEOUT = common.platformTimeout(15000);
|
||||
}
|
||||
|
||||
// Refs: https://github.com/nodejs/node/issues/52467
|
||||
|
||||
(async () => {
|
||||
if (!workerData) {
|
||||
// worker.terminate() should terminate the worker and the pending
|
||||
// inspector.waitForDebugger().
|
||||
{
|
||||
const worker = new Worker(__filename, { workerData: {} });
|
||||
await new Promise((r) => worker.on('message', r));
|
||||
await new Promise((r) => setTimeout(r, TIMEOUT));
|
||||
worker.on('exit', common.mustCall());
|
||||
await worker.terminate();
|
||||
}
|
||||
// process.exit() should kill the process.
|
||||
{
|
||||
const worker = new Worker(__filename, { workerData: {} });
|
||||
await new Promise((r) => worker.on('message', r));
|
||||
await new Promise((r) => setTimeout(r, TIMEOUT));
|
||||
process.on('exit', (status) => assert.strictEqual(status, 0));
|
||||
setImmediate(() => process.exit());
|
||||
}
|
||||
} else {
|
||||
inspector.open(0, undefined, false);
|
||||
parentPort.postMessage('open');
|
||||
inspector.waitForDebugger();
|
||||
}
|
||||
})().then(common.mustCall());
|
||||
Reference in new issue
Block a user