зеркало из https://github.com/mozilla/gecko-dev.git
Bug 547399 - 'Workers: Don't let worker messages run if the worker is suspended'. r+sr=jst.
This commit is contained in:
Родитель
fe2a33cdae
Коммит
9554ef498f
|
@ -933,6 +933,17 @@ public:
|
|||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
// If the worker is suspended and we're running on the main thread then we
|
||||
// can't actually dispatch the event yet. Instead we queue it for whenever
|
||||
// we resume.
|
||||
if (mWorker->IsSuspended() && NS_IsMainThread()) {
|
||||
if (!mWorker->QueueSuspendedRunnable(this)) {
|
||||
NS_ERROR("Out of memory?!");
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target = mToInner ?
|
||||
static_cast<nsDOMWorkerMessageHandler*>(mWorker->GetInnerScope()) :
|
||||
static_cast<nsDOMWorkerMessageHandler*>(mWorker);
|
||||
|
@ -1044,6 +1055,7 @@ nsDOMWorker::~nsDOMWorker()
|
|||
}
|
||||
|
||||
NS_ASSERTION(!mFeatures.Length(), "Live features!");
|
||||
NS_ASSERTION(!mQueuedRunnables.Length(), "Events that never ran!");
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
NS_GetMainThread(getter_AddRefs(mainThread));
|
||||
|
@ -1349,6 +1361,9 @@ nsDOMWorker::Kill()
|
|||
features[index]->Cancel();
|
||||
}
|
||||
|
||||
// Make sure we kill any queued runnables that we never had a chance to run.
|
||||
mQueuedRunnables.Clear();
|
||||
|
||||
// We no longer need to keep our inner scope.
|
||||
mInnerScope = nsnull;
|
||||
mScopeWN = nsnull;
|
||||
|
@ -1400,6 +1415,13 @@ nsDOMWorker::Resume()
|
|||
if (shouldResumeFeatures) {
|
||||
ResumeFeatures();
|
||||
}
|
||||
|
||||
// Repost any events that were queued for the main thread while suspended.
|
||||
PRUint32 count = mQueuedRunnables.Length();
|
||||
for (PRUint32 index = 0; index < count; index++) {
|
||||
NS_DispatchToCurrentThread(mQueuedRunnables[index]);
|
||||
}
|
||||
mQueuedRunnables.Clear();
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -1934,6 +1956,13 @@ nsDOMWorker::GetExpirationTime()
|
|||
}
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
nsDOMWorker::QueueSuspendedRunnable(nsIRunnable* aRunnable)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
return mQueuedRunnables.AppendElement(aRunnable) ? PR_TRUE : PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWorker::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
|
|
|
@ -64,6 +64,7 @@ class nsDOMWorkerTimeout;
|
|||
class nsICancelable;
|
||||
class nsIDOMEventListener;
|
||||
class nsIEventTarget;
|
||||
class nsIRunnable;
|
||||
class nsIScriptGlobalObject;
|
||||
class nsIXPConnectWrappedNative;
|
||||
|
||||
|
@ -118,6 +119,7 @@ class nsDOMWorker : public nsDOMWorkerMessageHandler,
|
|||
friend class nsDOMWorkerXHR;
|
||||
friend class nsDOMWorkerXHRProxy;
|
||||
friend class nsReportErrorRunnable;
|
||||
friend class nsDOMFireEventRunnable;
|
||||
|
||||
friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
|
||||
friend void DOMWorkerErrorReporter(JSContext* aCx,
|
||||
|
@ -288,6 +290,8 @@ private:
|
|||
return mLocation;
|
||||
}
|
||||
|
||||
PRBool QueueSuspendedRunnable(nsIRunnable* aRunnable);
|
||||
|
||||
private:
|
||||
|
||||
// mParent will live as long as mParentWN but only mParentWN will keep the JS
|
||||
|
@ -327,6 +331,8 @@ private:
|
|||
|
||||
nsCOMPtr<nsIWorkerLocation> mLocation;
|
||||
|
||||
nsTArray<nsCOMPtr<nsIRunnable> > mQueuedRunnables;
|
||||
|
||||
PRPackedBool mSuspended;
|
||||
PRPackedBool mCompileAttempted;
|
||||
};
|
||||
|
|
|
@ -82,6 +82,9 @@ _TEST_FILES = \
|
|||
relativeLoad_import.js \
|
||||
test_scopeOnerror.html \
|
||||
scopeOnerror_worker.js \
|
||||
test_suspend.html \
|
||||
suspend_iframe.html \
|
||||
suspend_worker.js \
|
||||
test_simpleThread.html \
|
||||
simpleThread_worker.js \
|
||||
test_terminate.html \
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for DOM Worker Threads Suspending</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<div id="output"></div>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var output = document.getElementById("output");
|
||||
|
||||
var worker;
|
||||
|
||||
function terminateWorker() {
|
||||
if (worker) {
|
||||
worker.terminate();
|
||||
worker = null;
|
||||
}
|
||||
}
|
||||
|
||||
function startWorker(messageCallback, errorCallback) {
|
||||
worker = new Worker("suspend_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
output.textContent = output.textContent + event.data + "\n";
|
||||
messageCallback(event.data);
|
||||
};
|
||||
|
||||
worker.onerror = function(event) {
|
||||
this.terminate();
|
||||
errorCallback(event.message);
|
||||
};
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,5 @@
|
|||
var counter = 0;
|
||||
|
||||
setInterval(function() {
|
||||
postMessage(++counter);
|
||||
}, 100);
|
|
@ -0,0 +1,113 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for DOM Worker Threads</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<iframe id="workerFrame" src="suspend_iframe.html" onload="subframeLoaded();">
|
||||
</iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var iframe;
|
||||
var lastCount;
|
||||
|
||||
var suspended;
|
||||
var resumed;
|
||||
|
||||
var interval;
|
||||
var oldMessageCount;
|
||||
var waitCount = 0;
|
||||
|
||||
function setCachePref(enabled) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
if (enabled) {
|
||||
prefBranch.setBoolPref("browser.sessionhistory.cache_subframes", true);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
prefBranch.clearUserPref("browser.sessionhistory.cache_subframes");
|
||||
} catch (e) { /* Pref didn't exist, meh */ }
|
||||
}
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
setCachePref(false);
|
||||
iframe.terminateWorker();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function waitInterval() {
|
||||
is(iframe.location, "about:blank", "Wrong url!");
|
||||
is(suspended, true, "Not suspended?");
|
||||
is(lastCount, oldMessageCount, "Received a message while suspended!");
|
||||
if (++waitCount == 5) {
|
||||
clearInterval(interval);
|
||||
iframe.history.back();
|
||||
resumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
function badOnloadCallback() {
|
||||
ok(false, "iframe didn't go into fastback cache!");
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function suspendCallback() {
|
||||
is(iframe.location, "about:blank", "Wrong url!");
|
||||
is(suspended, true, "Not suspended?");
|
||||
iframe.onload = badOnloadCallback;
|
||||
oldMessageCount = lastCount;
|
||||
interval = setInterval(waitInterval, 1000);
|
||||
}
|
||||
|
||||
function messageCallback(data) {
|
||||
if (!suspended) {
|
||||
ok(lastCount === undefined || lastCount == data - 1,
|
||||
"Data is inconsistent");
|
||||
lastCount = data;
|
||||
if (lastCount == 50) {
|
||||
setCachePref(true);
|
||||
iframe.location = "about:blank";
|
||||
suspended = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var newLocation =
|
||||
window.location.toString().replace("test_suspend.html",
|
||||
"suspend_iframe.html");
|
||||
is(iframe.location, newLocation, "Wrong url!");
|
||||
ok(suspended && resumed, "Got message before resumed!");
|
||||
is(lastCount, data - 1, "Missed a message, suspend failed!");
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
|
||||
function errorCallback(data) {
|
||||
ok(false, "Iframe had an error: '" + data + "'");
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function subframeLoaded() {
|
||||
var iframeElement = document.getElementById("workerFrame");
|
||||
iframeElement.onload = suspendCallback;
|
||||
|
||||
iframe = iframeElement.contentWindow;
|
||||
ok(iframe, "No iframe?!");
|
||||
|
||||
iframe.startWorker(messageCallback, errorCallback);
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче