зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1281040
- Make sure we detach from worker client when target is destroyed. r=jlongster
This commit is contained in:
Родитель
5b35b60ada
Коммит
f2ee475ad4
|
@ -616,7 +616,11 @@ skip-if = e10s && debug
|
||||||
skip-if = e10s && debug
|
skip-if = e10s && debug
|
||||||
[browser_dbg_watch-expressions-02.js]
|
[browser_dbg_watch-expressions-02.js]
|
||||||
skip-if = e10s && debug
|
skip-if = e10s && debug
|
||||||
[browser_dbg_worker-console.js]
|
[browser_dbg_worker-console-01.js]
|
||||||
|
skip-if = e10s && debug
|
||||||
|
[browser_dbg_worker-console-02.js]
|
||||||
|
skip-if = e10s && debug
|
||||||
|
[browser_dbg_worker-console-03.js]
|
||||||
skip-if = e10s && debug
|
skip-if = e10s && debug
|
||||||
[browser_dbg_worker-source-map.js]
|
[browser_dbg_worker-source-map.js]
|
||||||
skip-if = e10s && debug
|
skip-if = e10s && debug
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Check to make sure that a worker can be attached to a toolbox
|
||||||
|
// and that the console works.
|
||||||
|
|
||||||
|
var TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
|
||||||
|
var WORKER_URL = "code_WorkerActor.attachThread-worker.js";
|
||||||
|
|
||||||
|
add_task(function* testNormalExecution() {
|
||||||
|
let {client, tab, tabClient, workerClient, toolbox, gDebugger} =
|
||||||
|
yield initWorkerDebugger(TAB_URL, WORKER_URL);
|
||||||
|
|
||||||
|
let jsterm = yield getSplitConsole(toolbox);
|
||||||
|
let executed = yield jsterm.execute("this.location.toString()");
|
||||||
|
ok(executed.textContent.includes(WORKER_URL),
|
||||||
|
"Evaluating the global's location works");
|
||||||
|
|
||||||
|
terminateWorkerInTab(tab, WORKER_URL);
|
||||||
|
yield waitForWorkerClose(workerClient);
|
||||||
|
yield gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
|
||||||
|
yield close(client);
|
||||||
|
yield removeTab(tab);
|
||||||
|
});
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Check to make sure that a worker can be attached to a toolbox
|
||||||
|
// and that the console works.
|
||||||
|
|
||||||
|
var TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
|
||||||
|
var WORKER_URL = "code_WorkerActor.attachThread-worker.js";
|
||||||
|
|
||||||
|
add_task(function* testWhilePaused() {
|
||||||
|
let {client, tab, tabClient, workerClient, toolbox, gDebugger} =
|
||||||
|
yield initWorkerDebugger(TAB_URL, WORKER_URL);
|
||||||
|
|
||||||
|
let gTarget = gDebugger.gTarget;
|
||||||
|
let gResumeButton = gDebugger.document.getElementById("resume");
|
||||||
|
let gResumeKey = gDebugger.document.getElementById("resumeKey");
|
||||||
|
|
||||||
|
// Execute some basic math to make sure evaluations are working.
|
||||||
|
let jsterm = yield getSplitConsole(toolbox);
|
||||||
|
let executed = yield jsterm.execute("10000+1");
|
||||||
|
ok(executed.textContent.includes("10001"), "Text for message appeared correct");
|
||||||
|
|
||||||
|
// Pause the worker by waiting for next execution and then sending a message to
|
||||||
|
// it from the main thread.
|
||||||
|
let oncePaused = gTarget.once("thread-paused");
|
||||||
|
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
||||||
|
once(gDebugger.gClient, "willInterrupt").then(() => {
|
||||||
|
info("Posting message to worker, then waiting for a pause");
|
||||||
|
postMessageToWorkerInTab(tab, WORKER_URL, "ping");
|
||||||
|
});
|
||||||
|
yield oncePaused;
|
||||||
|
|
||||||
|
let command1 = jsterm.execute("10000+2");
|
||||||
|
let command2 = jsterm.execute("10000+3");
|
||||||
|
let command3 = jsterm.execute("foobar"); // throw an error
|
||||||
|
|
||||||
|
info("Trying to get the result of command1");
|
||||||
|
executed = yield command1;
|
||||||
|
ok(executed.textContent.includes("10002"),
|
||||||
|
"command1 executed successfully");
|
||||||
|
|
||||||
|
info("Trying to get the result of command2");
|
||||||
|
executed = yield command2;
|
||||||
|
ok(executed.textContent.includes("10003"),
|
||||||
|
"command2 executed successfully");
|
||||||
|
|
||||||
|
info("Trying to get the result of command3");
|
||||||
|
executed = yield command3;
|
||||||
|
// XXXworkers This is failing until Bug 1215120 is resolved.
|
||||||
|
todo(executed.textContent.includes("ReferenceError: foobar is not defined"),
|
||||||
|
"command3 executed successfully");
|
||||||
|
|
||||||
|
let onceResumed = gTarget.once("thread-resumed");
|
||||||
|
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
||||||
|
yield onceResumed;
|
||||||
|
|
||||||
|
terminateWorkerInTab(tab, WORKER_URL);
|
||||||
|
yield waitForWorkerClose(workerClient);
|
||||||
|
yield gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
|
||||||
|
yield close(client);
|
||||||
|
yield removeTab(tab);
|
||||||
|
});
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Check to make sure that a worker can be attached to a toolbox
|
||||||
|
// and that the console works.
|
||||||
|
|
||||||
|
var TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
|
||||||
|
var WORKER_URL = "code_WorkerActor.attachThread-worker.js";
|
||||||
|
|
||||||
|
// Test to see if creating the pause from the console works.
|
||||||
|
add_task(function* testPausedByConsole() {
|
||||||
|
let {client, tab, tabClient, workerClient, toolbox, gDebugger} =
|
||||||
|
yield initWorkerDebugger(TAB_URL, WORKER_URL);
|
||||||
|
|
||||||
|
let gTarget = gDebugger.gTarget;
|
||||||
|
let gResumeButton = gDebugger.document.getElementById("resume");
|
||||||
|
let gResumeKey = gDebugger.document.getElementById("resumeKey");
|
||||||
|
|
||||||
|
let jsterm = yield getSplitConsole(toolbox);
|
||||||
|
let executed = yield jsterm.execute("10000+1");
|
||||||
|
ok(executed.textContent.includes("10001"),
|
||||||
|
"Text for message appeared correct");
|
||||||
|
|
||||||
|
let oncePaused = gTarget.once("thread-paused");
|
||||||
|
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
||||||
|
let pausedExecution = jsterm.execute("10000+2");
|
||||||
|
|
||||||
|
info("Executed a command with 'break on next' active, waiting for pause");
|
||||||
|
yield oncePaused;
|
||||||
|
|
||||||
|
executed = yield jsterm.execute("10000+3");
|
||||||
|
ok(executed.textContent.includes("10003"),
|
||||||
|
"Text for message appeared correct");
|
||||||
|
|
||||||
|
info("Waiting for a resume");
|
||||||
|
let onceResumed = gTarget.once("thread-resumed");
|
||||||
|
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
||||||
|
yield onceResumed;
|
||||||
|
|
||||||
|
executed = yield pausedExecution;
|
||||||
|
ok(executed.textContent.includes("10002"),
|
||||||
|
"Text for message appeared correct");
|
||||||
|
|
||||||
|
terminateWorkerInTab(tab, WORKER_URL);
|
||||||
|
yield waitForWorkerClose(workerClient);
|
||||||
|
yield gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
|
||||||
|
yield close(client);
|
||||||
|
yield removeTab(tab);
|
||||||
|
});
|
|
@ -1,145 +0,0 @@
|
||||||
// Check to make sure that a worker can be attached to a toolbox
|
|
||||||
// and that the console works.
|
|
||||||
|
|
||||||
var TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
|
|
||||||
var WORKER_URL = "code_WorkerActor.attachThread-worker.js";
|
|
||||||
|
|
||||||
function* initWorkerDebugger(TAB_URL, WORKER_URL) {
|
|
||||||
if (!DebuggerServer.initialized) {
|
|
||||||
DebuggerServer.init();
|
|
||||||
DebuggerServer.addBrowserActors();
|
|
||||||
}
|
|
||||||
|
|
||||||
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
|
||||||
yield connect(client);
|
|
||||||
|
|
||||||
let tab = yield addTab(TAB_URL);
|
|
||||||
let { tabs } = yield listTabs(client);
|
|
||||||
let [, tabClient] = yield attachTab(client, findTab(tabs, TAB_URL));
|
|
||||||
|
|
||||||
yield createWorkerInTab(tab, WORKER_URL);
|
|
||||||
|
|
||||||
let { workers } = yield listWorkers(tabClient);
|
|
||||||
let [, workerClient] = yield attachWorker(tabClient,
|
|
||||||
findWorker(workers, WORKER_URL));
|
|
||||||
|
|
||||||
let toolbox = yield gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
|
|
||||||
"jsdebugger",
|
|
||||||
Toolbox.HostType.WINDOW);
|
|
||||||
|
|
||||||
let debuggerPanel = toolbox.getCurrentPanel();
|
|
||||||
let gDebugger = debuggerPanel.panelWin;
|
|
||||||
|
|
||||||
return {client, tab, tabClient, workerClient, toolbox, gDebugger};
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(function* testNormalExecution() {
|
|
||||||
let {client, tab, tabClient, workerClient, toolbox, gDebugger} =
|
|
||||||
yield initWorkerDebugger(TAB_URL, WORKER_URL);
|
|
||||||
|
|
||||||
let jsterm = yield getSplitConsole(toolbox);
|
|
||||||
let executed = yield jsterm.execute("this.location.toString()");
|
|
||||||
ok(executed.textContent.includes(WORKER_URL),
|
|
||||||
"Evaluating the global's location works");
|
|
||||||
|
|
||||||
yield gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
|
|
||||||
terminateWorkerInTab(tab, WORKER_URL);
|
|
||||||
yield waitForWorkerClose(workerClient);
|
|
||||||
yield close(client);
|
|
||||||
yield removeTab(tab);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(function* testWhilePaused() {
|
|
||||||
let {client, tab, tabClient, workerClient, toolbox, gDebugger} =
|
|
||||||
yield initWorkerDebugger(TAB_URL, WORKER_URL);
|
|
||||||
|
|
||||||
let gTarget = gDebugger.gTarget;
|
|
||||||
let gResumeButton = gDebugger.document.getElementById("resume");
|
|
||||||
let gResumeKey = gDebugger.document.getElementById("resumeKey");
|
|
||||||
|
|
||||||
// Execute some basic math to make sure evaluations are working.
|
|
||||||
let jsterm = yield getSplitConsole(toolbox);
|
|
||||||
let executed = yield jsterm.execute("10000+1");
|
|
||||||
ok(executed.textContent.includes("10001"), "Text for message appeared correct");
|
|
||||||
|
|
||||||
// Pause the worker by waiting for next execution and then sending a message to
|
|
||||||
// it from the main thread.
|
|
||||||
let oncePaused = gTarget.once("thread-paused");
|
|
||||||
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
|
||||||
once(gDebugger.gClient, "willInterrupt").then(() => {
|
|
||||||
info("Posting message to worker, then waiting for a pause");
|
|
||||||
postMessageToWorkerInTab(tab, WORKER_URL, "ping");
|
|
||||||
});
|
|
||||||
yield oncePaused;
|
|
||||||
|
|
||||||
let command1 = jsterm.execute("10000+2");
|
|
||||||
let command2 = jsterm.execute("10000+3");
|
|
||||||
let command3 = jsterm.execute("foobar"); // throw an error
|
|
||||||
|
|
||||||
info("Trying to get the result of command1");
|
|
||||||
executed = yield command1;
|
|
||||||
ok(executed.textContent.includes("10002"),
|
|
||||||
"command1 executed successfully");
|
|
||||||
|
|
||||||
info("Trying to get the result of command2");
|
|
||||||
executed = yield command2;
|
|
||||||
ok(executed.textContent.includes("10003"),
|
|
||||||
"command2 executed successfully");
|
|
||||||
|
|
||||||
info("Trying to get the result of command3");
|
|
||||||
executed = yield command3;
|
|
||||||
// XXXworkers This is failing until Bug 1215120 is resolved.
|
|
||||||
todo(executed.textContent.includes("ReferenceError: foobar is not defined"),
|
|
||||||
"command3 executed successfully");
|
|
||||||
|
|
||||||
let onceResumed = gTarget.once("thread-resumed");
|
|
||||||
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
|
||||||
yield onceResumed;
|
|
||||||
|
|
||||||
yield gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
|
|
||||||
terminateWorkerInTab(tab, WORKER_URL);
|
|
||||||
yield waitForWorkerClose(workerClient);
|
|
||||||
yield close(client);
|
|
||||||
yield removeTab(tab);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Test to see if creating the pause from the console works.
|
|
||||||
add_task(function* testPausedByConsole() {
|
|
||||||
let {client, tab, tabClient, workerClient, toolbox, gDebugger} =
|
|
||||||
yield initWorkerDebugger(TAB_URL, WORKER_URL);
|
|
||||||
|
|
||||||
let gTarget = gDebugger.gTarget;
|
|
||||||
let gResumeButton = gDebugger.document.getElementById("resume");
|
|
||||||
let gResumeKey = gDebugger.document.getElementById("resumeKey");
|
|
||||||
|
|
||||||
let jsterm = yield getSplitConsole(toolbox);
|
|
||||||
let executed = yield jsterm.execute("10000+1");
|
|
||||||
ok(executed.textContent.includes("10001"),
|
|
||||||
"Text for message appeared correct");
|
|
||||||
|
|
||||||
let oncePaused = gTarget.once("thread-paused");
|
|
||||||
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
|
||||||
let pausedExecution = jsterm.execute("10000+2");
|
|
||||||
|
|
||||||
info("Executed a command with 'break on next' active, waiting for pause");
|
|
||||||
yield oncePaused;
|
|
||||||
|
|
||||||
executed = yield jsterm.execute("10000+3");
|
|
||||||
ok(executed.textContent.includes("10003"),
|
|
||||||
"Text for message appeared correct");
|
|
||||||
|
|
||||||
info("Waiting for a resume");
|
|
||||||
let onceResumed = gTarget.once("thread-resumed");
|
|
||||||
EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
|
|
||||||
yield onceResumed;
|
|
||||||
|
|
||||||
executed = yield pausedExecution;
|
|
||||||
ok(executed.textContent.includes("10002"),
|
|
||||||
"Text for message appeared correct");
|
|
||||||
|
|
||||||
yield gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
|
|
||||||
terminateWorkerInTab(tab, WORKER_URL);
|
|
||||||
yield waitForWorkerClose(workerClient);
|
|
||||||
yield close(client);
|
|
||||||
yield removeTab(tab);
|
|
||||||
});
|
|
|
@ -44,8 +44,9 @@ add_task(function* () {
|
||||||
is(activeTools.join(","), "webconsole,jsdebugger,scratchpad,options",
|
is(activeTools.join(","), "webconsole,jsdebugger,scratchpad,options",
|
||||||
"Correct set of tools supported by worker");
|
"Correct set of tools supported by worker");
|
||||||
|
|
||||||
yield toolbox.destroy();
|
|
||||||
terminateWorkerInTab(tab, WORKER_URL);
|
terminateWorkerInTab(tab, WORKER_URL);
|
||||||
yield waitForWorkerClose(workerClient);
|
yield waitForWorkerClose(workerClient);
|
||||||
yield close(client);
|
yield close(client);
|
||||||
|
|
||||||
|
yield toolbox.destroy();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1324,3 +1324,33 @@ function waitForDispatch(panel, type, eventRepeat = 1) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* initWorkerDebugger(TAB_URL, WORKER_URL) {
|
||||||
|
if (!DebuggerServer.initialized) {
|
||||||
|
DebuggerServer.init();
|
||||||
|
DebuggerServer.addBrowserActors();
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||||
|
yield connect(client);
|
||||||
|
|
||||||
|
let tab = yield addTab(TAB_URL);
|
||||||
|
let { tabs } = yield listTabs(client);
|
||||||
|
let [, tabClient] = yield attachTab(client, findTab(tabs, TAB_URL));
|
||||||
|
|
||||||
|
yield createWorkerInTab(tab, WORKER_URL);
|
||||||
|
|
||||||
|
let { workers } = yield listWorkers(tabClient);
|
||||||
|
let [, workerClient] = yield attachWorker(tabClient,
|
||||||
|
findWorker(workers, WORKER_URL));
|
||||||
|
|
||||||
|
let toolbox = yield gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
|
||||||
|
"jsdebugger",
|
||||||
|
Toolbox.HostType.WINDOW);
|
||||||
|
|
||||||
|
let debuggerPanel = toolbox.getCurrentPanel();
|
||||||
|
let gDebugger = debuggerPanel.panelWin;
|
||||||
|
|
||||||
|
return {client, tab, tabClient, workerClient, toolbox, gDebugger};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -767,7 +767,9 @@ WorkerTarget.prototype = {
|
||||||
return this._workerClient.client;
|
return this._workerClient.client;
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function () {},
|
destroy: function () {
|
||||||
|
this._workerClient.detach();
|
||||||
|
},
|
||||||
|
|
||||||
hasActor: function (name) {
|
hasActor: function (name) {
|
||||||
// console is the only one actor implemented by WorkerActor
|
// console is the only one actor implemented by WorkerActor
|
||||||
|
|
|
@ -863,10 +863,25 @@ var DebuggerServer = {
|
||||||
transport.hooks = {
|
transport.hooks = {
|
||||||
onClosed: () => {
|
onClosed: () => {
|
||||||
if (!dbg.isClosed) {
|
if (!dbg.isClosed) {
|
||||||
|
// If the worker happens to be shutting down while we are trying
|
||||||
|
// to close the connection, there is a small interval during
|
||||||
|
// which no more runnables can be dispatched to the worker, but
|
||||||
|
// the worker debugger has not yet been closed. In that case,
|
||||||
|
// the call to postMessage below will fail. The onClosed hook on
|
||||||
|
// DebuggerTransport is not supposed to throw exceptions, so we
|
||||||
|
// need to make sure to catch these early.
|
||||||
|
try {
|
||||||
dbg.postMessage(JSON.stringify({
|
dbg.postMessage(JSON.stringify({
|
||||||
type: "disconnect",
|
type: "disconnect",
|
||||||
id,
|
id,
|
||||||
}));
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
// We can safely ignore these exceptions. The only time the
|
||||||
|
// call to postMessage can fail is if the worker is either
|
||||||
|
// shutting down, or has finished shutting down. In both
|
||||||
|
// cases, there is nothing to clean up, so we don't care
|
||||||
|
// whether this message arrives or not.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.cancelForwarding(id);
|
connection.cancelForwarding(id);
|
||||||
|
@ -1444,6 +1459,26 @@ DebuggerServerConnection.prototype = {
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
removeActorPool(actorPool, noCleanup) {
|
removeActorPool(actorPool, noCleanup) {
|
||||||
|
// When a connection is closed, it removes each of its actor pools. When an
|
||||||
|
// actor pool is removed, it calls the disconnect method on each of its
|
||||||
|
// actors. Some actors, such as ThreadActor, manage their own actor pools.
|
||||||
|
// When the disconnect method is called on these actors, they manually
|
||||||
|
// remove their actor pools. Consequently, this method is reentrant.
|
||||||
|
//
|
||||||
|
// In addition, some actors, such as ThreadActor, perform asynchronous work
|
||||||
|
// (in the case of ThreadActor, because they need to resume), before they
|
||||||
|
// remove each of their actor pools. Since we don't wait for this work to
|
||||||
|
// be completed, we can end up in this function recursively after the
|
||||||
|
// connection already set this._extraPools to null.
|
||||||
|
//
|
||||||
|
// This is a bug: if the disconnect method can perform asynchronous work,
|
||||||
|
// then we should wait for that work to be completed before setting this.
|
||||||
|
// _extraPools to null. As a temporary solution, it should be acceptable
|
||||||
|
// to just return early (if this._extraPools has been set to null, all
|
||||||
|
// actors pools for this connection should already have been removed).
|
||||||
|
if (this._extraPools === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let index = this._extraPools.lastIndexOf(actorPool);
|
let index = this._extraPools.lastIndexOf(actorPool);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
let pool = this._extraPools.splice(index, 1);
|
let pool = this._extraPools.splice(index, 1);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче