Bug 606752 - 'DOM Worker can destroy JSContext while Cycle Collector is running'. r=jst, a=blocking.
authorBen Turner <bent.mozilla@gmail.com>
Thu, 13 Jan 2011 13:14:38 -0800
changeset 60459 19565050334a4029df04a493e3736abd4810d38d
parent 60458 dfdf3e5dc7494adbe51cc251ff3baef4f7f19d10
child 60460 183d1071f07e5720aa5d25a8b51cbcb255806b2f
push id18002
push userbturner@mozilla.com
push dateThu, 13 Jan 2011 21:15:31 +0000
treeherdermozilla-central@19565050334a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst, blocking
bugs606752
milestone2.0b10pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 606752 - 'DOM Worker can destroy JSContext while Cycle Collector is running'. r=jst, a=blocking.
dom/src/threads/nsDOMThreadService.cpp
--- a/dom/src/threads/nsDOMThreadService.cpp
+++ b/dom/src/threads/nsDOMThreadService.cpp
@@ -151,16 +151,57 @@ public:
     mCx = nsnull;
     return cx;
   }
 
 private:
   JSContext* mCx;
 };
 
+class nsDestroyJSContextRunnable : public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  nsDestroyJSContextRunnable(JSContext* aCx)
+  : mCx(aCx)
+  {
+    NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+    NS_ASSERTION(aCx, "Null pointer!");
+    NS_ASSERTION(!JS_GetGlobalObject(aCx), "Should not have a global!");
+
+    // We're removing this context from this thread. Let the JS engine know.
+    JS_ClearContextThread(aCx);
+  }
+
+  NS_IMETHOD Run()
+  {
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+    // We're about to use this context on this thread. Let the JS engine know.
+    if (!!JS_SetContextThread(mCx)) {
+      NS_WARNING("JS_SetContextThread failed!");
+    }
+
+    if (nsContentUtils::XPConnect()) {
+      nsContentUtils::XPConnect()->ReleaseJSContext(mCx, PR_TRUE);
+    }
+    else {
+      NS_WARNING("Failed to release JSContext!");
+    }
+
+    return NS_OK;
+  }
+
+private:
+  JSContext* mCx;
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsDestroyJSContextRunnable, nsIRunnable)
+
 /**
  * This class is used as to post an error to the worker's outer handler.
  */
 class nsReportErrorRunnable : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
 
@@ -1391,17 +1432,24 @@ nsDOMThreadService::OnThreadShuttingDown
     }
 
     JSContext* pushedCx;
     gThreadJSContextStack->Pop(&pushedCx);
     NS_ASSERTION(pushedCx == cx, "Popped the wrong context!");
 
     gThreadJSContextStack->SetSafeJSContext(nsnull);
 
-    nsContentUtils::XPConnect()->ReleaseJSContext(cx, PR_TRUE);
+    // The cycle collector may be running on the main thread. If so we cannot
+    // simply destroy this context. Instead we proxy the context destruction to
+    // the main thread. If that fails somehow then we simply leak the context.
+    nsCOMPtr<nsIRunnable> runnable = new nsDestroyJSContextRunnable(cx);
+
+    if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
+      NS_WARNING("Failed to dispatch release runnable!");
+    }
   }
 
   return NS_OK;
 }
 
 nsresult
 nsDOMThreadService::RegisterWorker(nsDOMWorker* aWorker,
                                    nsIScriptGlobalObject* aGlobalObject)