Bug 488080 - 'Workers: Don't compile script if the worker is already canceled'. r+sr=jst
authorBen Turner <bent.mozilla@gmail.com>
Fri, 13 Nov 2009 13:30:03 -0800
changeset 34840 f2a2bb94bf9a35b1ca4e6e6e4b4142e78e092879
parent 34839 b89fd003bdd92e7b81924b4d9f0ea6d11ce519e6
child 34841 2c771d7e771b92ab5f2ebf3cc761e64b87989ec1
push idunknown
push userunknown
push dateunknown
bugs488080
milestone1.9.3a1pre
Bug 488080 - 'Workers: Don't compile script if the worker is already canceled'. r+sr=jst
dom/src/threads/nsDOMThreadService.cpp
dom/src/threads/test/closeOnGC_worker.js
dom/src/threads/test/test_closeOnGC.html
--- 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);