Bug 1164077 - Implement WorkerActor.attach;r=jlong

This commit is contained in:
Eddy Bruël 2015-05-22 17:58:46 +02:00
Родитель ec4d34ba60
Коммит 3479bf68cf
12 изменённых файлов: 368 добавлений и 7 удалений

Просмотреть файл

@ -43,6 +43,8 @@ support-files =
code_ugly-7.js
code_ugly-8
code_ugly-8^headers^
code_WorkerActor.attach-worker1.js
code_WorkerActor.attach-worker2.js
doc_auto-pretty-print-01.html
doc_auto-pretty-print-02.html
doc_binary_search.html
@ -103,6 +105,8 @@ support-files =
doc_watch-expressions.html
doc_watch-expression-button.html
doc_with-frame.html
doc_WorkerActor.attach-tab1.html
doc_WorkerActor.attach-tab2.html
head.js
sjs_random-javascript.sjs
testactors.js
@ -556,3 +560,5 @@ skip-if = e10s && debug
skip-if = e10s && debug
[browser_dbg_watch-expressions-02.js]
skip-if = e10s && debug
[browser_dbg_WorkerActor.attach.js]
skip-if = e10s && debug

Просмотреть файл

@ -0,0 +1,63 @@
let MAX_TOTAL_VIEWERS = "browser.sessionhistory.max_total_viewers";
let TAB1_URL = EXAMPLE_URL + "doc_WorkerActor.attach-tab1.html";
let TAB2_URL = EXAMPLE_URL + "doc_WorkerActor.attach-tab2.html";
let WORKER1_URL = "code_WorkerActor.attach-worker1.js";
let WORKER2_URL = "code_WorkerActor.attach-worker2.js";
function test() {
Task.spawn(function* () {
let oldMaxTotalViewers = SpecialPowers.getIntPref(MAX_TOTAL_VIEWERS);
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, 10);
DebuggerServer.init();
DebuggerServer.addBrowserActors();
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let tab = yield addTab(TAB1_URL);
let { tabs } = yield listTabs(client);
let [, tabClient] = yield attachTab(client, findTab(tabs, TAB1_URL));
yield listWorkers(tabClient);
// If a page still has pending network requests, it will not be moved into
// the bfcache. Consequently, we cannot use waitForWorkerListChanged here,
// because the worker is not guaranteed to have finished loading when it is
// registered. Instead, we have to wait for the promise returned by
// createWorker in the tab to be resolved.
yield createWorkerInTab(tab, WORKER1_URL);
let { workers } = yield listWorkers(tabClient);
let [, workerClient1] = yield attachWorker(tabClient,
findWorker(workers, WORKER1_URL));
is(workerClient1.isFrozen, false);
executeSoon(() => {
tab.linkedBrowser.loadURI(TAB2_URL);
});
yield waitForWorkerFreeze(workerClient1);
is(workerClient1.isFrozen, true, "worker should be frozen");
yield createWorkerInTab(tab, WORKER2_URL);
({ workers } = yield listWorkers(tabClient));
let [, workerClient2] = yield attachWorker(tabClient,
findWorker(workers, WORKER2_URL));
is(workerClient2.isFrozen, false);
executeSoon(() => {
tab.linkedBrowser.contentWindow.history.back();
});
yield Promise.all([
waitForWorkerFreeze(workerClient2),
waitForWorkerThaw(workerClient1)
]);
terminateWorkerInTab(tab, WORKER1_URL);
yield waitForWorkerClose(workerClient1);
yield close(client);
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, oldMaxTotalViewers);
finish();
});
}

Просмотреть файл

@ -0,0 +1,5 @@
"use strict";
self.onmessage = function () {};
postMessage("load");

Просмотреть файл

@ -0,0 +1,5 @@
"use strict";
self.onmessage = function () {};
postMessage("load");

Просмотреть файл

@ -13,8 +13,14 @@ addMessageListener("test:call", function (message) {
dump("Calling function with name " + message.data.name + ".\n");
let data = message.data;
XPCNativeWrapper.unwrap(content)[data.name].apply(undefined, data.args);
sendAsyncMessage("test:call");
let result = XPCNativeWrapper.unwrap(content)[data.name].apply(undefined, data.args);
if (result && result.then) {
result.then(() => {
sendAsyncMessage("test:call");
});
} else {
sendAsyncMessage("test:call");
}
});
addMessageListener("test:click", function (message) {
@ -28,6 +34,34 @@ addMessageListener("test:click", function (message) {
addMessageListener("test:eval", function (message) {
dump("Evalling string " + message.data.string + ".\n");
content.eval(message.data.string);
sendAsyncMessage("test:eval");
let result = content.eval(message.data.string);
if (result.then) {
result.then(() => {
sendAsyncMessage("test:eval");
});
} else {
sendAsyncMessage("test:eval");
}
});
let workers = {}
addMessageListener("test:createWorker", function (message) {
dump("Creating worker with url '" + message.data.url + "'.\n");
let url = message.data.url;
let worker = new content.Worker(message.data.url);
worker.addEventListener("message", function listener() {
worker.removeEventListener("message", listener);
sendAsyncMessage("test:createWorker");
});
workers[url] = worker;
});
addMessageListener("test:terminateWorker", function (message) {
dump("Terminating worker with url '" + message.data.url + "'.\n");
let url = message.data.url;
workers[url].terminate();
delete workers[url];
});

Просмотреть файл

@ -0,0 +1,5 @@
"use strict";
self.onmessage = function () {};
postMessage("load");

Просмотреть файл

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -984,7 +984,7 @@ function callInTab(tab, name) {
name: name,
args: Array.prototype.slice.call(arguments, 2)
});
waitForMessageFromTab(tab, "test:call");
return waitForMessageFromTab(tab, "test:call");
}
function evalInTab(tab, string) {
@ -993,7 +993,7 @@ function evalInTab(tab, string) {
sendMessageToTab(tab, "test:eval", {
string: string,
});
waitForMessageFromTab(tab, "test:eval");
return waitForMessageFromTab(tab, "test:eval");
}
function sendMouseClickToTab(tab, target) {
@ -1026,6 +1026,24 @@ function getSourceForm(aSources, aURL) {
return item.attachment.source;
}
function createWorkerInTab(tab, url) {
info("Creating worker with url '" + url + "' in tab.");
sendMessageToTab(tab, "test:createWorker", {
url: url
});
return waitForMessageFromTab(tab, "test:createWorker");
}
function terminateWorkerInTab(tab, url) {
info("Terminating worker with url '" + url + "' in tab.");
sendMessageToTab(tab, "test:terminateWorker", {
url: url
});
return waitForMessageFromTab(tab, "test:terminateWorker");
}
function connect(client) {
info("Connecting client.");
return new Promise(function (resolve) {
@ -1081,6 +1099,25 @@ function listWorkers(tabClient) {
});
}
function findWorker(workers, url) {
info("Finding worker with url '" + url + "'.");
for (let worker of workers) {
if (worker.url === url) {
return worker;
}
}
return null;
}
function attachWorker(tabClient, worker) {
info("Attaching to worker with url '" + worker.url + "'.");
return new Promise(function(resolve, reject) {
tabClient.attachWorker(worker.actor, function (response, workerClient) {
resolve([response, workerClient]);
});
});
}
function waitForWorkerListChanged(tabClient) {
info("Waiting for worker list to change.");
return new Promise(function (resolve) {
@ -1090,3 +1127,31 @@ function waitForWorkerListChanged(tabClient) {
});
});
}
function waitForWorkerClose(workerClient) {
info("Waiting for worker to close.");
return new Promise(function (resolve) {
workerClient.addOneTimeListener("close", function () {
info("Worker did close.");
resolve();
});
});
}
function waitForWorkerFreeze(workerClient) {
info("Waiting for worker to freeze.");
return new Promise(function (resolve) {
workerClient.addOneTimeListener("freeze", function () {
resolve();
});
});
}
function waitForWorkerThaw(workerClient) {
info("Waiting for worker to thaw.");
return new Promise(function (resolve) {
workerClient.addOneTimeListener("thaw", function () {
resolve();
});
});
}

Просмотреть файл

@ -5541,6 +5541,20 @@
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'detach' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_WORKERDETACH_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'detach' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_WORKERDETACH_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'detach' request to go round trip."
},
"DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_LOCAL_MS": {
"expires_in_version": "never",
"kind": "exponential",

Просмотреть файл

@ -51,6 +51,7 @@ Object.defineProperty(this, "WebConsoleClient", {
});
Components.utils.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
this.executeSoon = DevToolsUtils.executeSoon;
this.makeInfallible = DevToolsUtils.makeInfallible;
this.values = DevToolsUtils.values;
@ -505,6 +506,29 @@ DebuggerClient.prototype = {
});
},
attachWorker: function DC_attachWorker(aWorkerActor, aOnResponse = noop) {
let workerClient = this._clients.get(aWorkerActor);
if (workerClient !== undefined) {
executeSoon(() => aOnResponse({
from: workerClient.actor,
type: "attached",
isFrozen: workerClient.isFrozen
}, workerClient));
return;
}
this.request({ to: aWorkerActor, type: "attach" }, (aResponse) => {
if (aResponse.error) {
aOnResponse(aResponse, null);
return;
}
let workerClient = new WorkerClient(this, aResponse);
this.registerClient(workerClient);
aOnResponse(aResponse, workerClient);
});
},
/**
* Attach to an addon actor.
*
@ -1326,11 +1350,82 @@ TabClient.prototype = {
type: "listWorkers"
}, {
telemetry: "LISTWORKERS"
})
}),
attachWorker: function (aWorkerActor, aOnResponse) {
this.client.attachWorker(aWorkerActor, aOnResponse);
}
};
eventSource(TabClient.prototype);
function WorkerClient(aClient, aForm) {
this._client = aClient;
this._actor = aForm.from;
this._isClosed = false;
this._isFrozen = aForm.isFrozen;
this._onClose = this._onClose.bind(this);
this._onFreeze = this._onFreeze.bind(this);
this._onThaw = this._onThaw.bind(this);
this.addListener("close", this._onClose);
this.addListener("freeze", this._onFreeze);
this.addListener("thaw", this._onThaw);
}
WorkerClient.prototype = {
get _transport() {
return this._client._transport;
},
get request() {
return this._client.request;
},
get actor() {
return this._actor;
},
get isClosed() {
return this._isClosed;
},
get isFrozen() {
return this._isFrozen;
},
detach: DebuggerClient.requester({ type: "detach" }, {
after: function (aResponse) {
this._client.unregisterClient(this);
return aResponse;
},
telemetry: "WORKERDETACH"
}),
_onClose: function () {
this.removeListener("close", this._onClose);
this.removeListener("freeze", this._onFreeze);
this.removeListener("thaw", this._onThaw);
this._client.unregisterClient(this);
this._closed = true;
},
_onFreeze: function () {
this._isFrozen = true;
},
_onThaw: function () {
this._isFrozen = false;
},
events: ["close", "freeze", "thaw"]
};
eventSource(WorkerClient.prototype);
function AddonClient(aClient, aActor) {
this._client = aClient;
this._actor = aActor;

Просмотреть файл

@ -27,6 +27,7 @@ function matchWorkerDebugger(dbg, options) {
function WorkerActor(dbg) {
this._dbg = dbg;
this._isAttached = false;
}
WorkerActor.prototype = {
@ -37,9 +38,61 @@ WorkerActor.prototype = {
actor: this.actorID,
url: this._dbg.url
};
},
onAttach: function () {
if (this._dbg.isClosed) {
return { error: "closed" };
}
if (!this._isAttached) {
this._dbg.addListener(this);
this._isAttached = true;
}
return {
type: "attached",
isFrozen: this._dbg.isFrozen
};
},
onDetach: function () {
if (!this._isAttached) {
return { error: "wrongState" };
}
this._detach();
return { type: "detached" };
},
onClose: function () {
if (this._isAttached) {
this._detach();
}
this.conn.sendActorEvent(this.actorID, "close");
},
onFreeze: function () {
this.conn.sendActorEvent(this.actorID, "freeze");
},
onThaw: function () {
this.conn.sendActorEvent(this.actorID, "thaw");
},
_detach: function () {
this._dbg.removeListener(this);
this._isAttached = false;
}
};
WorkerActor.prototype.requestTypes = {
"attach": WorkerActor.prototype.onAttach,
"detach": WorkerActor.prototype.onDetach
};
exports.WorkerActor = WorkerActor;
function WorkerActorList(options) {