Bug 488080 - 'Workers: Don't compile script if the worker is already canceled'. r+sr=jst
--- a/dom/src/threads/nsDOMThreadService.cpp
+++ b/dom/src/threads/nsDOMThreadService.cpp
@@ -376,16 +376,21 @@ public:
NS_ERROR("nsDOMThreadService didn't give us a context! Are we out of memory?");
return NS_ERROR_FAILURE;
}
NS_ASSERTION(!JS_GetGlobalObject(cx), "Shouldn't have a global!");
JS_SetContextPrivate(cx, mWorker);
+ // Go ahead and trigger the operation callback for this context before we
+ // try to run any JS. That way we'll be sure to cancel or suspend as soon as
+ // possible if the compilation takes too long.
+ JS_TriggerOperationCallback(cx);
+
PRBool killWorkerWhenDone;
// Tell the worker which context it will be using
if (mWorker->SetGlobalForContext(cx)) {
RunQueue(cx, &killWorkerWhenDone);
// Code in XPConnect assumes that the context's global object won't be
// replaced outside of a request.
@@ -428,18 +433,16 @@ protected:
void ClearQueue() {
nsCOMPtr<nsIRunnable> runnable;
while ((runnable = dont_AddRef((nsIRunnable*)mRunnables.PopFront()))) {
// Loop until all the runnables are dead.
}
}
void RunQueue(JSContext* aCx, PRBool* aCloseRunnableSet) {
- PRBool operationCallbackTriggered = PR_FALSE;
-
while (1) {
nsCOMPtr<nsIRunnable> runnable;
{
nsAutoMonitor mon(gDOMThreadService->mMonitor);
runnable = dont_AddRef((nsIRunnable*)mRunnables.PopFront());
if (!runnable && mCloseRunnable) {
@@ -464,25 +467,16 @@ protected:
#endif
*aCloseRunnableSet = mKillWorkerWhenDone;
gDOMThreadService->WorkerComplete(this);
mon.NotifyAll();
return;
}
}
- if (!operationCallbackTriggered) {
- // Make sure that our operation callback is set to run before starting.
- // That way we are sure to suspend this worker if needed.
- JS_TriggerOperationCallback(aCx);
-
- // Only need to do this the first time.
- operationCallbackTriggered = PR_TRUE;
- }
-
// Clear out any old cruft hanging around in the regexp statics.
JS_ClearRegExpStatics(aCx);
runnable->Run();
}
NS_NOTREACHED("Shouldn't ever get here!");
}
@@ -501,16 +495,17 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorke
/*******************************************************************************
* JS environment function and callbacks
*/
JSBool
DOMWorkerOperationCallback(JSContext* aCx)
{
nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(aCx);
+ NS_ASSERTION(worker, "This must never be null!");
PRBool wasSuspended = PR_FALSE;
PRBool extraThreadAllowed = PR_FALSE;
jsrefcount suspendDepth = 0;
for (;;) {
// Kill execution if we're canceled.
if (worker->IsCanceled()) {
--- a/dom/src/threads/test/closeOnGC_worker.js
+++ b/dom/src/threads/test/closeOnGC_worker.js
@@ -1,5 +1,7 @@
onclose = function() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "closeOnGC_server.sjs", false);
xhr.send();
};
+
+postMessage("ready");
--- a/dom/src/threads/test/test_closeOnGC.html
+++ b/dom/src/threads/test/test_closeOnGC.html
@@ -15,21 +15,23 @@
function CC() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.garbageCollect();
}
var worker = new Worker("closeOnGC_worker.js");
- worker = null;
-
- CC();
+ worker.onmessage = function(event) {
+ is(event.data, "ready");
+ worker = null;
+ }
var interval = setInterval(function() {
+ dump("xxxben interval\n");
var xhr = new XMLHttpRequest();
xhr.open("GET", "closeOnGC_server.sjs", false);
xhr.send();
if (xhr.responseText != "closed") {
CC();
return;
}
clearInterval(interval);