mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
Our inspector implementation dispatches inspector messages from a V8 interrupt handler, so they could be handled during an arbitrary point of JS execution where re-calling into another irrelevant JS code is not safe. This patch tracks V8 interrupt state in this case and rewrite the async hook toggling as state reconciliation, so requests only record the desired state, which is applied once calling into JS is possible and safe, and the actual invocation is deferred to an immediate when inside an interrupt. This simplifies the previous mechanism and makes re-entracy and early termination safer. Drive-by: skip installing command line API extensions during teardown when calling into JS is no longer safe. Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: https://github.com/nodejs/node/pull/65028 Refs: https://issues.chromium.org/u/1/issues/42212250 Refs: https://chromium-review.googlesource.com/c/v8/v8/+/8173727 Refs: https://github.com/nodejs/node/pull/26935 Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
69 lines
2.1 KiB
JavaScript
69 lines
2.1 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
|
|
common.skipIfInspectorDisabled();
|
|
|
|
const { isMainThread } = require('worker_threads');
|
|
|
|
if (!isMainThread) {
|
|
common.skip('This test only works on a main thread');
|
|
}
|
|
|
|
const assert = require('assert');
|
|
const { Worker } = require('worker_threads');
|
|
const { Session } = require('inspector');
|
|
|
|
const session = new Session();
|
|
|
|
let done = false;
|
|
|
|
function onAttachToWorker({ params: { sessionId } }) {
|
|
let id = 1;
|
|
function postToWorkerInspector(method, params) {
|
|
session.post('NodeWorker.sendMessageToWorker', {
|
|
sessionId,
|
|
message: JSON.stringify({ id: id++, method, params })
|
|
}, () => console.log(`Message ${method} received the response`));
|
|
}
|
|
|
|
// Wait for the notification
|
|
function onMessageReceived({ params: { message } }) {
|
|
if (!message ||
|
|
JSON.parse(message).method !== 'NodeRuntime.waitingForDisconnect') {
|
|
session.once('NodeWorker.receivedMessageFromWorker', onMessageReceived);
|
|
return;
|
|
}
|
|
// Force a call to node::inspector::Agent::SyncAsyncHookState by changing
|
|
// the async call stack depth
|
|
postToWorkerInspector('Debugger.setAsyncCallStackDepth', { maxDepth: 1 });
|
|
// This is were the original crash happened
|
|
session.post('NodeWorker.detach', { sessionId }, () => {
|
|
done = true;
|
|
});
|
|
}
|
|
|
|
onMessageReceived({ params: { message: null } });
|
|
// Enable the debugger, otherwise setAsyncCallStackDepth does nothing
|
|
postToWorkerInspector('Debugger.enable');
|
|
// Start waiting for disconnect notification
|
|
postToWorkerInspector('NodeRuntime.notifyWhenWaitingForDisconnect',
|
|
{ enabled: true });
|
|
// start worker
|
|
postToWorkerInspector('Runtime.runIfWaitingForDebugger');
|
|
}
|
|
|
|
session.connect();
|
|
|
|
session.on('NodeWorker.attachedToWorker', common.mustCall(onAttachToWorker));
|
|
|
|
session.post('NodeWorker.enable', { waitForDebuggerOnStart: true }, common.mustCall(() => {
|
|
new Worker('console.log("Worker is done")', { eval: true })
|
|
.once('exit', common.mustCall(() => {
|
|
setTimeout(common.mustCall(() => {
|
|
assert.strictEqual(done, true);
|
|
console.log('Test is done');
|
|
}), 0);
|
|
}));
|
|
}));
|