mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Bug 757133 - Implement a WorkerDebugger;r=khuey
This commit is contained in:
parent
0c3516c497
commit
8eb04071b0
@ -2181,8 +2181,6 @@ WorkerPrivateParent<Derived>::DisableDebugger()
|
||||
if (NS_FAILED(UnregisterWorkerDebugger(self->mDebugger))) {
|
||||
NS_WARNING("Failed to unregister worker debugger!");
|
||||
}
|
||||
|
||||
self->mDebugger = nullptr;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
@ -3504,6 +3502,22 @@ WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
|
||||
WorkerDebugger::~WorkerDebugger()
|
||||
{
|
||||
MOZ_ASSERT(!mWorkerPrivate);
|
||||
MOZ_ASSERT(!mIsEnabled);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
if (NS_FAILED(NS_GetMainThread(getter_AddRefs(mainThread)))) {
|
||||
NS_WARNING("Failed to proxy release of listeners, leaking instead!");
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < mListeners.Length(); ++index) {
|
||||
nsIWorkerDebuggerListener* listener = nullptr;
|
||||
mListeners[index].forget(&listener);
|
||||
if (NS_FAILED(NS_ProxyRelease(mainThread, listener))) {
|
||||
NS_WARNING("Failed to proxy release of listener, leaking instead!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerDebugger, nsIWorkerDebugger)
|
||||
@ -3519,6 +3533,60 @@ WorkerDebugger::GetIsClosed(bool* aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::GetIsChrome(bool* aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mWorkerPrivate) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
*aResult = mWorkerPrivate->IsChromeWorker();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::GetParent(nsIWorkerDebugger** aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mWorkerPrivate) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
WorkerPrivate* parent = mWorkerPrivate->GetParent();
|
||||
if (!parent) {
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWorkerPrivate->IsDedicatedWorker());
|
||||
|
||||
nsCOMPtr<nsIWorkerDebugger> debugger = parent->Debugger();
|
||||
debugger.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::GetType(uint32_t* aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mWorkerPrivate) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
*aResult = mWorkerPrivate->Type();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::GetUrl(nsAString& aResult)
|
||||
{
|
||||
@ -3534,6 +3602,53 @@ WorkerDebugger::GetUrl(nsAString& aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::GetWindow(nsIDOMWindow** aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mWorkerPrivate) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mWorkerPrivate->GetParent() || !mWorkerPrivate->IsDedicatedWorker()) {
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = mWorkerPrivate->GetWindow();
|
||||
window.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::AddListener(nsIWorkerDebuggerListener* aListener)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (mListeners.Contains(aListener)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mListeners.AppendElement(aListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::RemoveListener(nsIWorkerDebuggerListener* aListener)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!mListeners.Contains(aListener)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mListeners.RemoveElement(aListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebugger::WaitIsEnabled(bool aIsEnabled)
|
||||
{
|
||||
@ -3576,6 +3691,15 @@ WorkerDebugger::Disable()
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate = nullptr;
|
||||
|
||||
{
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners(mListeners);
|
||||
for (size_t index = 0; index < listeners.Length(); ++index) {
|
||||
listeners[index]->OnClose();
|
||||
}
|
||||
}
|
||||
|
||||
NotifyIsEnabled(false);
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,8 @@ class WorkerPrivate;
|
||||
class WorkerRunnable;
|
||||
class WorkerDebugger;
|
||||
|
||||
// If you change this, the corresponding list in nsIWorkerDebugger.idl needs to
|
||||
// be updated too.
|
||||
enum WorkerType
|
||||
{
|
||||
WorkerTypeDedicated,
|
||||
@ -663,6 +665,12 @@ public:
|
||||
return mIsChromeWorker;
|
||||
}
|
||||
|
||||
WorkerType
|
||||
Type() const
|
||||
{
|
||||
return mWorkerType;
|
||||
}
|
||||
|
||||
bool
|
||||
IsDedicatedWorker() const
|
||||
{
|
||||
@ -737,6 +745,9 @@ class WorkerDebugger : public nsIWorkerDebugger {
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
bool mIsEnabled;
|
||||
|
||||
// Only touched on the main thread.
|
||||
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> mListeners;
|
||||
|
||||
public:
|
||||
explicit WorkerDebugger(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
@ -868,6 +879,14 @@ public:
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
LoadInfo* aLoadInfo);
|
||||
|
||||
WorkerDebugger*
|
||||
Debugger() const
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mDebugger);
|
||||
return mDebugger;
|
||||
}
|
||||
|
||||
void
|
||||
DoRunLoop(JSContext* aCx);
|
||||
|
||||
|
@ -1,9 +1,33 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(54fd2dd3-c01b-4f71-888f-462f37a54f57)]
|
||||
interface nsIWorkerDebuggerListener : nsISupports
|
||||
{
|
||||
void onClose();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(0833b363-bffe-4cdb-ad50-1c4563e0C8ff)]
|
||||
interface nsIWorkerDebugger : nsISupports
|
||||
{
|
||||
const unsigned long TYPE_DEDICATED = 0;
|
||||
const unsigned long TYPE_SHARED = 1;
|
||||
const unsigned long TYPE_SERVICE = 2;
|
||||
|
||||
readonly attribute bool isClosed;
|
||||
|
||||
readonly attribute bool isChrome;
|
||||
|
||||
readonly attribute nsIWorkerDebugger parent;
|
||||
|
||||
readonly attribute unsigned long type;
|
||||
|
||||
readonly attribute DOMString url;
|
||||
|
||||
readonly attribute nsIDOMWindow window;
|
||||
|
||||
void addListener(in nsIWorkerDebuggerListener listener);
|
||||
|
||||
void removeListener(in nsIWorkerDebuggerListener listener);
|
||||
};
|
||||
|
3
dom/workers/test/WorkerDebugger_childWorker.js
Normal file
3
dom/workers/test/WorkerDebugger_childWorker.js
Normal file
@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
onmessage = function () {};
|
3
dom/workers/test/WorkerDebugger_parentWorker.js
Normal file
3
dom/workers/test/WorkerDebugger_parentWorker.js
Normal file
@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger_childWorker.js");
|
11
dom/workers/test/WorkerDebugger_sharedWorker.js
Normal file
11
dom/workers/test/WorkerDebugger_sharedWorker.js
Normal file
@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
onconnect = function (event) {
|
||||
event.ports[0].onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "close":
|
||||
close();
|
||||
break;
|
||||
}
|
||||
};
|
||||
};
|
@ -2,6 +2,9 @@
|
||||
support-files =
|
||||
WorkerDebuggerManager_childWorker.js
|
||||
WorkerDebuggerManager_parentWorker.js
|
||||
WorkerDebugger_childWorker.js
|
||||
WorkerDebugger_parentWorker.js
|
||||
WorkerDebugger_sharedWorker.js
|
||||
WorkerTest.jsm
|
||||
WorkerTest_subworker.js
|
||||
WorkerTest_worker.js
|
||||
@ -24,6 +27,7 @@ support-files =
|
||||
file_url.jsm
|
||||
bug1062920_worker.js
|
||||
|
||||
[test_WorkerDebugger.xul]
|
||||
[test_WorkerDebuggerManager.xul]
|
||||
[test_bug883784.jsm]
|
||||
[test_bug883784.xul]
|
||||
|
@ -84,6 +84,20 @@ function waitForUnregister(predicate = () => true) {
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDebuggerClose(dbg, predicate = () => true) {
|
||||
return new Promise(function (resolve) {
|
||||
dbg.addListener({
|
||||
onClose: function () {
|
||||
if (!predicate()) {
|
||||
return;
|
||||
}
|
||||
dbg.removeListener(this);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForMultiple(promises) {
|
||||
return new Promise(function (resolve) {
|
||||
let results = [];
|
||||
|
98
dom/workers/test/test_WorkerDebugger.xul
Normal file
98
dom/workers/test/test_WorkerDebugger.xul
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebugger"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const PARENT_WORKER_URL = "WorkerDebugger_parentWorker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebugger_childWorker.js";
|
||||
const SHARED_WORKER_URL = "WorkerDebugger_sharedWorker.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
]);
|
||||
worker = new ChromeWorker(PARENT_WORKER_URL);
|
||||
let dbgs = yield promise;
|
||||
is(dbgs[0].isChrome, true, "debugger should be for chrome worker");
|
||||
is(dbgs[0].parent, null,
|
||||
"debugger for a top-level worker should not have parent");
|
||||
is(dbgs[0].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
|
||||
"debugger should be for dedicated worker");
|
||||
is(dbgs[0].window, window,
|
||||
"debugger for top-level dedicated worker should have window");
|
||||
is(dbgs[1].isChrome, false, "debugger should be for content worker");
|
||||
is(dbgs[1].parent, dbgs[0],
|
||||
"debugger for child worker should have parent");
|
||||
is(dbgs[1].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED);
|
||||
is(dbgs[1].window, null,
|
||||
"debugger for non-top-level worker should not have window");
|
||||
|
||||
promise = waitForMultiple([
|
||||
waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForDebuggerClose(dbgs[1]),
|
||||
waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForDebuggerClose(dbgs[0]),
|
||||
]);
|
||||
worker.terminate();
|
||||
yield promise;
|
||||
|
||||
promise = waitForRegister();
|
||||
worker = new SharedWorker(SHARED_WORKER_URL);
|
||||
let dbg = yield promise;
|
||||
is(dbg.isChrome, false, "debugger should be for content worker");
|
||||
is(dbg.parent, null,
|
||||
"debugger for top-level worker should not have parent");
|
||||
is(dbg.type, Ci.nsIWorkerDebugger.TYPE_SHARED,
|
||||
"debugger should be for shared worker");
|
||||
is(dbg.window, null,
|
||||
"debugger for non-dedicated worker should not have window");
|
||||
|
||||
let listener = {
|
||||
onRegistered: function () {
|
||||
ok(false,
|
||||
"debugger for shared worker should not be registered twice");
|
||||
},
|
||||
};
|
||||
wdm.addListener(listener);
|
||||
worker = new SharedWorker(SHARED_WORKER_URL);
|
||||
|
||||
dbg.addListener({
|
||||
onClose: function () {
|
||||
is(dbg.isClosed, true, "debugger should be closed");
|
||||
wdm.removeListener(listener);
|
||||
dbg.removeListener(this);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
worker.port.start();
|
||||
worker.port.postMessage("close");
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
Loading…
Reference in New Issue
Block a user