Bug 1092102 - Implement WorkerDebugger.isFrozen;r=khuey

This commit is contained in:
Eddy Bruël 2015-04-01 20:32:20 +02:00
parent 0e15f05bda
commit d877851987
10 changed files with 264 additions and 3 deletions

View File

@ -4223,7 +4223,8 @@ WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
mCondVar(mMutex, "WorkerDebugger::mCondVar"),
mWorkerPrivate(aWorkerPrivate),
mIsEnabled(false),
mIsInitialized(false)
mIsInitialized(false),
mIsFrozen(false)
{
mWorkerPrivate->AssertIsOnParentThread();
}
@ -4277,6 +4278,21 @@ WorkerDebugger::GetIsChrome(bool* aResult)
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::GetIsFrozen(bool* aResult)
{
AssertIsOnMainThread();
MutexAutoLock lock(mMutex);
if (!mWorkerPrivate) {
return NS_ERROR_UNEXPECTED;
}
*aResult = mIsFrozen;
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::GetParent(nsIWorkerDebugger** aResult)
{
@ -4474,6 +4490,52 @@ WorkerDebugger::Disable()
NotifyIsEnabled(false);
}
void
WorkerDebugger::Freeze()
{
mWorkerPrivate->AssertIsOnWorkerThread();
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &WorkerDebugger::FreezeOnMainThread);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
}
void
WorkerDebugger::FreezeOnMainThread()
{
AssertIsOnMainThread();
mIsFrozen = true;
for (size_t index = 0; index < mListeners.Length(); ++index) {
mListeners[index]->OnFreeze();
}
}
void
WorkerDebugger::Thaw()
{
mWorkerPrivate->AssertIsOnWorkerThread();
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &WorkerDebugger::ThawOnMainThread);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
}
void
WorkerDebugger::ThawOnMainThread()
{
AssertIsOnMainThread();
mIsFrozen = false;
for (size_t index = 0; index < mListeners.Length(); ++index) {
mListeners[index]->OnThaw();
}
}
void
WorkerDebugger::PostMessageToDebugger(const nsAString& aMessage)
{
@ -5693,6 +5755,7 @@ WorkerPrivate::FreezeInternal(JSContext* aCx)
NS_ASSERTION(!mFrozen, "Already frozen!");
mFrozen = true;
mDebugger->Freeze();
return true;
}
@ -5704,6 +5767,7 @@ WorkerPrivate::ThawInternal(JSContext* aCx)
NS_ASSERTION(mFrozen, "Not yet frozen!");
mFrozen = false;
mDebugger->Thaw();
return true;
}

View File

@ -727,6 +727,7 @@ class WorkerDebugger : public nsIWorkerDebugger {
// Only touched on the main thread.
bool mIsInitialized;
bool mIsFrozen;
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> mListeners;
public:
@ -747,6 +748,12 @@ public:
void
Disable();
void
Freeze();
void
Thaw();
void
PostMessageToDebugger(const nsAString& aMessage);
@ -761,6 +768,12 @@ private:
void
NotifyIsEnabled(bool aIsEnabled);
void
FreezeOnMainThread();
void
ThawOnMainThread();
void
PostMessageToDebuggerOnMainThread(const nsAString& aMessage);

View File

@ -2,7 +2,7 @@
interface nsIDOMWindow;
[scriptable, uuid(55d54034-1573-4889-b1d9-93ba12fc33c7)]
[scriptable, uuid(530db841-1b2c-485a-beeb-f2b1acb9714e)]
interface nsIWorkerDebuggerListener : nsISupports
{
void onClose();
@ -10,10 +10,14 @@ interface nsIWorkerDebuggerListener : nsISupports
void onError(in DOMString filename, in unsigned long lineno,
in DOMString message);
void onFreeze();
void onMessage(in DOMString message);
void onThaw();
};
[scriptable, builtinclass, uuid(28e0a60c-ff10-446c-8c2a-5fbdc01394ea)]
[scriptable, builtinclass, uuid(d7c73e54-3c41-4393-9d13-fa2ed4Ba6764)]
interface nsIWorkerDebugger : nsISupports
{
const unsigned long TYPE_DEDICATED = 0;
@ -24,6 +28,8 @@ interface nsIWorkerDebugger : nsISupports
readonly attribute bool isChrome;
readonly attribute bool isFrozen;
readonly attribute nsIWorkerDebugger parent;
readonly attribute unsigned long type;

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script>
var worker = new Worker("WorkerDebugger.isFrozen_worker1.js");
worker.onmessage = function () {
parent.postMessage("ready", "*");
};
</script>
</head>
<body>
This is page 1.
</body>
<html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script>
var worker = new Worker("WorkerDebugger.isFrozen_worker2.js");
worker.onmessage = function () {
parent.postMessage("ready", "*");
};
</script>
</head>
<body>
This is page 2.
</body>
<html>

View File

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

View File

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

View File

@ -4,6 +4,10 @@ support-files =
WorkerDebugger.initialize_childWorker.js
WorkerDebugger.initialize_debugger.js
WorkerDebugger.initialize_worker.js
WorkerDebugger.isFrozen_iframe1.html
WorkerDebugger.isFrozen_iframe2.html
WorkerDebugger.isFrozen_worker1.js
WorkerDebugger.isFrozen_worker2.js
WorkerDebugger.postMessage_childWorker.js
WorkerDebugger.postMessage_debugger.js
WorkerDebugger.postMessage_worker.js
@ -47,6 +51,7 @@ support-files =
[test_WorkerDebugger.xul]
[test_WorkerDebugger.initialize.xul]
[test_WorkerDebugger.isFrozen.xul]
[test_WorkerDebugger.postMessage.xul]
[test_WorkerDebuggerGlobalScope.createSandbox.xul]
[test_WorkerDebuggerGlobalScope.enterEventLoop.xul]

View File

@ -130,6 +130,41 @@ function waitForDebuggerMessage(dbg, message) {
});
}
function waitForDebuggerFreeze(dbg) {
return new Promise(function (resolve) {
dbg.addListener({
onFreeze: function () {
dbg.removeListener(this);
resolve();
}
});
});
}
function waitForDebuggerThaw(dbg) {
return new Promise(function (resolve) {
dbg.addListener({
onThaw: function () {
dbg.removeListener(this);
resolve();
}
});
});
}
function waitForWindowMessage(window, message) {
return new Promise(function (resolve) {
let onmessage = function (event) {
if (event.data !== event.data) {
return;
}
window.removeEventListener("message", onmessage, false);
resolve();
};
window.addEventListener("message", onmessage, false);
});
}
function waitForWorkerMessage(worker, message) {
return new Promise(function (resolve) {
worker.addEventListener("message", function onmessage(event) {

View 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.isFrozen"
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 CACHE_SUBFRAMES = "browser.sessionhistory.cache_subframes";
const MAX_TOTAL_VIEWERS = "browser.sessionhistory.max_total_viewers";
const IFRAME1_URL = "WorkerDebugger.isFrozen_iframe1.html";
const IFRAME2_URL = "WorkerDebugger.isFrozen_iframe2.html";
const WORKER1_URL = "WorkerDebugger.isFrozen_worker1.js";
const WORKER2_URL = "WorkerDebugger.isFrozen_worker2.js";
function test() {
Task.spawn(function* () {
SimpleTest.waitForExplicitFinish();
var oldMaxTotalViewers = SpecialPowers.getIntPref(MAX_TOTAL_VIEWERS);
SpecialPowers.setBoolPref(CACHE_SUBFRAMES, true);
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, 10);
let iframe = $("iframe");
let promise = waitForMultiple([
waitForRegister(WORKER1_URL),
waitForWindowMessage(window, "ready"),
]);
iframe.src = IFRAME1_URL;
let [dbg1] = yield promise;
is(dbg1.isClosed, false,
"debugger for worker on page 1 should not be closed");
is(dbg1.isFrozen, false,
"debugger for worker on page 1 should not be frozen");
promise = waitForMultiple([
waitForDebuggerFreeze(dbg1),
waitForRegister(WORKER2_URL),
waitForWindowMessage(window, "ready"),
]);
iframe.src = IFRAME2_URL;
let [_, dbg2] = yield promise;
is(dbg1.isClosed, false,
"debugger for worker on page 1 should not be closed");
is(dbg1.isFrozen, true,
"debugger for worker on page 1 should be frozen");
is(dbg2.isClosed, false,
"debugger for worker on page 2 should not be closed");
is(dbg2.isFrozen, false,
"debugger for worker on page 2 should not be frozen");
promise = waitForMultiple([
waitForDebuggerFreeze(dbg2),
waitForDebuggerThaw(dbg1),
]);
iframe.contentWindow.history.back();
yield promise;
is(dbg1.isClosed, false,
"debugger for worker on page 1 should not be closed")
is(dbg1.isFrozen, false,
"debugger for worker on page 1 should not be frozen");
is(dbg2.isClosed, false,
"debugger for worker on page 2 should not be closed");
is(dbg2.isFrozen, true,
"debugger for worker on page 2 should be frozen");
SpecialPowers.clearUserPref(CACHE_SUBFRAMES);
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, oldMaxTotalViewers);
SimpleTest.finish();
});
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display:none;"></div>
<pre id="test"></pre>
<iframe id="iframe"></iframe>
</body>
<label id="test-result"/>
</window>