--- a/dom/public/idl/threads/nsIDOMThreads.idl
+++ b/dom/public/idl/threads/nsIDOMThreads.idl
@@ -117,25 +117,16 @@ interface nsIDOMWorkerPool : nsISupports
/**
* Create a new worker object by evaluating the given script.
*
* @param aSourceScript (in DOMString)
* The script to compile. See below for details on the scope in which
* the script will run.
*/
nsIDOMWorkerThread createWorker(in DOMString aSourceScript);
-
- /**
- * Create a new worker object by evaluating the given script.
- *
- * @param aSourceURL (in AString)
- * The script url to load and compile. See below for details on the
- * scope in which the script will run.
- */
- nsIDOMWorkerThread createWorkerFromURL(in AString aSourceURL);
};
[scriptable, uuid(0f2a52ea-afc9-49e6-86dd-2d0cb65b5dd5)]
interface nsIDOMThreadService : nsISupports
{
/**
* Creates a new DOM worker pool.
*/
--- a/dom/src/threads/Makefile.in
+++ b/dom/src/threads/Makefile.in
@@ -48,29 +48,27 @@ LIBRARY_NAME = domthreads_s
LIBXUL_LIBRARY = 1
FORCE_STATIC_LIB = 1
REQUIRES = \
caps \
content \
js \
layout \
- necko \
pref \
string \
widget \
xpcom \
xpconnect \
$(NULL)
CPPSRCS = \
nsDOMThreadService.cpp \
nsDOMWorkerBase.cpp \
nsDOMWorkerPool.cpp \
- nsDOMWorkerScriptLoader.cpp \
nsDOMWorkerSecurityManager.cpp \
nsDOMWorkerThread.cpp \
nsDOMWorkerTimeout.cpp \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/dom/src/base \
$(NULL)
deleted file mode 100644
--- a/dom/src/threads/nsAutoJSObjectHolder.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is worker threads.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Ben Turner <bent.mozilla@gmail.com> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __NSAUTOJSOBJECTHOLDER_H__
-#define __NSAUTOJSOBJECTHOLDER_H__
-
-#include "jsapi.h"
-
-/**
- * Simple class that looks and acts like a JSObject* except that it unroots
- * itself automatically if Root() is ever called. Designed to be rooted on the
- * context or runtime (but not both!). Also automatically nulls its JSObject*
- * on Unroot and asserts that Root has been called prior to assigning an object.
- */
-class nsAutoJSObjectHolder
-{
-public:
- /**
- * Default constructor, no holding.
- */
- nsAutoJSObjectHolder()
- : mRt(NULL), mObj(NULL), mHeld(PR_FALSE) { }
-
- /**
- * Hold by rooting on the context's runtime in the constructor, passing the
- * result out.
- */
- nsAutoJSObjectHolder(JSContext* aCx, JSBool* aRv = NULL,
- JSObject* aObj = NULL)
- : mRt(NULL), mObj(aObj), mHeld(JS_FALSE) {
- JSBool rv = Hold(aCx);
- if (aRv) {
- *aRv = rv;
- }
- }
-
- /**
- * Hold by rooting on the runtime in the constructor, passing the result out.
- */
- nsAutoJSObjectHolder(JSRuntime* aRt, JSBool* aRv = NULL,
- JSObject* aObj = NULL)
- : mRt(aRt), mObj(aObj), mHeld(JS_FALSE) {
- JSBool rv = Hold(aRt);
- if (aRv) {
- *aRv = rv;
- }
- }
-
- /**
- * Always release on destruction.
- */
- ~nsAutoJSObjectHolder() {
- Release();
- }
-
- /**
- * Hold by rooting on the context's runtime.
- */
- JSBool Hold(JSContext* aCx) {
- return Hold(JS_GetRuntime(aCx));
- }
-
- /**
- * Hold by rooting on the runtime.
- */
- JSBool Hold(JSRuntime* aRt) {
- if (!mHeld) {
- mHeld = JS_AddNamedRootRT(aRt, &mObj, "nsAutoRootedJSObject");
- if (mHeld) {
- mRt = aRt;
- }
- }
- return mHeld;
- }
-
- /**
- * Manually release.
- */
- void Release() {
- NS_ASSERTION(!mHeld || mRt, "Bad!");
- if (mHeld) {
- mHeld = !JS_RemoveRootRT(mRt, &mObj);
- if (!mHeld) {
- mRt = NULL;
- }
- mObj = NULL;
- }
- }
-
- /**
- * Determine if Hold has been called.
- */
- JSBool IsHeld() {
- return mHeld;
- }
-
- /**
- * Pretend to be a JSObject*.
- */
- JSObject* get() const {
- return mObj;
- }
-
- /**
- * Pretend to be a JSObject*.
- */
- operator JSObject*() const {
- return get();
- }
-
- /**
- * Pretend to be a JSObject*. Assert if not held.
- */
- JSObject* operator=(JSObject* aOther) {
- NS_ASSERTION(mHeld, "Not rooted!");
- return mObj = aOther;
- }
-
-private:
- JSRuntime* mRt;
- JSObject* mObj;
- JSBool mHeld;
-};
-
-#endif /* __NSAUTOJSOBJECTHOLDER_H__ */
--- a/dom/src/threads/nsDOMThreadService.cpp
+++ b/dom/src/threads/nsDOMThreadService.cpp
@@ -37,18 +37,16 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMThreadService.h"
// Interfaces
#include "nsIComponentManager.h"
#include "nsIConsoleService.h"
-#include "nsIDocument.h"
-#include "nsIDOMDocument.h"
#include "nsIEventTarget.h"
#include "nsIGenericFactory.h"
#include "nsIJSContextStack.h"
#include "nsIJSRuntimeService.h"
#include "nsIObserverService.h"
#include "nsIScriptError.h"
#include "nsIScriptGlobalObject.h"
#include "nsIServiceManager.h"
@@ -85,24 +83,16 @@ PRLogModuleInfo *gDOMThreadsLog = nsnull
PR_STATIC_ASSERT(THREADPOOL_MAX_THREADS >= 1);
// The maximum number of idle threads in the internal thread pool
#define THREADPOOL_IDLE_THREADS 3
PR_STATIC_ASSERT(THREADPOOL_MAX_THREADS >= THREADPOOL_IDLE_THREADS);
-// As we suspend threads for various reasons (navigating away from the page,
-// loading scripts, etc.) we open another slot in the thread pool for another
-// worker to use. We can't do this forever so we set an absolute cap on the
-// number of threads we'll allow to prevent DOS attacks.
-#define THREADPOOL_THREAD_CAP 20
-
-PR_STATIC_ASSERT(THREADPOOL_THREAD_CAP >= THREADPOOL_MAX_THREADS);
-
// The number of times our JS operation callback will be called before yielding
// the thread
#define CALLBACK_YIELD_THRESHOLD 100
// A "bad" value for the NSPR TLS functions.
#define BAD_TLS_INDEX (PRUintn)-1
// Don't know why nsISupports.idl defines this out...
@@ -391,42 +381,37 @@ DOMWorkerOperationCallback(JSContext* aC
{
nsDOMWorkerThread* worker = (nsDOMWorkerThread*)JS_GetContextPrivate(aCx);
// Want a strong ref here to make sure that the monitor we wait on won't go
// away.
nsRefPtr<nsDOMWorkerPool> pool;
PRBool wasSuspended = PR_FALSE;
- PRBool extraThreadAllowed = PR_FALSE;
jsrefcount suspendDepth = 0;
while (1) {
// Kill execution if we're canceled.
if (worker->IsCanceled()) {
LOG(("Forcefully killing JS for worker [0x%p]",
static_cast<void*>(worker)));
if (wasSuspended) {
- if (extraThreadAllowed) {
- gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
- }
+ gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
JS_ResumeRequest(aCx, suspendDepth);
}
// Kill exectuion of the currently running JS.
return PR_FALSE;
}
// Break out if we're not suspended.
if (!worker->IsSuspended()) {
if (wasSuspended) {
- if (extraThreadAllowed) {
- gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
- }
+ gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
JS_ResumeRequest(aCx, suspendDepth);
}
break;
}
if (!wasSuspended) {
// Make sure we can get the monitor we need to wait on. It's possible that
// the worker was canceled since we checked above.
@@ -437,20 +422,18 @@ DOMWorkerOperationCallback(JSContext* aC
pool = worker->Pool();
// Make sure to suspend our request while we block like this, otherwise we
// prevent GC for everyone.
suspendDepth = JS_SuspendRequest(aCx);
// Since we're going to block this thread we should open up a new thread
- // in the thread pool for other workers. Must check the return value to
- // make sure we don't decrement when we failed.
- extraThreadAllowed =
- NS_SUCCEEDED(gDOMThreadService->ChangeThreadPoolMaxThreads(1));
+ // in the thread pool for other workers.
+ gDOMThreadService->ChangeThreadPoolMaxThreads(1);
// Only do all this setup once.
wasSuspended = PR_TRUE;
}
nsAutoMonitor mon(pool->Monitor());
mon.Wait();
}
@@ -777,24 +760,16 @@ nsDOMThreadService::CreateJSContext()
JSAutoContextDestroyer cx(JS_NewContext(rt, 8192));
NS_ENSURE_TRUE(cx, nsnull);
JS_SetErrorReporter(cx, DOMWorkerErrorReporter);
JS_SetOperationCallback(cx, DOMWorkerOperationCallback,
100 * JS_OPERATION_WEIGHT_BASE);
- static JSSecurityCallbacks securityCallbacks = {
- nsDOMWorkerSecurityManager::JSCheckAccess,
- NULL,
- NULL
- };
-
- JS_SetContextSecurityCallbacks(cx, &securityCallbacks);
-
nsresult rv = nsContentUtils::XPConnect()->
SetSecurityManagerForJSContext(cx, gWorkerSecurityManager, 0);
NS_ENSURE_SUCCESS(rv, nsnull);
return cx.forget();
}
#define LOOP_OVER_POOLS(_func, _args) \
@@ -853,21 +828,16 @@ nsDOMThreadService::ChangeThreadPoolMaxT
PRUint32 currentThreadCount;
nsresult rv = mThreadPool->GetThreadLimit(¤tThreadCount);
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 newThreadCount = (PRInt32)currentThreadCount + (PRInt32)aDelta;
NS_ASSERTION(newThreadCount >= THREADPOOL_MAX_THREADS,
"Can't go below initial thread count!");
- if (newThreadCount > THREADPOOL_THREAD_CAP) {
- NS_WARNING("Thread pool cap reached!");
- return NS_ERROR_FAILURE;
- }
-
rv = mThreadPool->SetThreadLimit((PRUint32)newThreadCount);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsIJSRuntimeService*
nsDOMThreadService::JSRuntimeService()
@@ -1003,23 +973,17 @@ nsDOMThreadService::OnThreadShuttingDown
*/
NS_IMETHODIMP
nsDOMThreadService::CreatePool(nsIDOMWorkerPool** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_TRUE(mThreadPool, NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
- nsIDOMDocument* domDocument = nsContentUtils::GetDocumentFromCaller();
- NS_ENSURE_TRUE(domDocument, NS_ERROR_UNEXPECTED);
-
- nsCOMPtr<nsIDocument> callingDocument(do_QueryInterface(domDocument));
- NS_ENSURE_TRUE(callingDocument, NS_ERROR_NO_INTERFACE);
-
- nsRefPtr<nsDOMWorkerPool> pool(new nsDOMWorkerPool(callingDocument));
+ nsRefPtr<nsDOMWorkerPool> pool(new nsDOMWorkerPool());
NS_ENSURE_TRUE(pool, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = pool->Init();
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(!mPools.Contains(pool), "Um?!");
mPools.AppendElement(pool);
--- a/dom/src/threads/nsDOMWorkerPool.cpp
+++ b/dom/src/threads/nsDOMWorkerPool.cpp
@@ -64,22 +64,20 @@
#define LOOP_OVER_WORKERS(_func, _args) \
PR_BEGIN_MACRO \
PRUint32 workerCount = mWorkers.Length(); \
for (PRUint32 i = 0; i < workerCount; i++) { \
mWorkers[i]-> _func _args ; \
} \
PR_END_MACRO
-nsDOMWorkerPool::nsDOMWorkerPool(nsIDocument* aDocument)
-: mParentGlobal(nsnull),
- mParentDocument(aDocument)
+nsDOMWorkerPool::nsDOMWorkerPool()
+: mParentGlobal(nsnull)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
- NS_ASSERTION(aDocument, "Must have a document!");
}
nsDOMWorkerPool::~nsDOMWorkerPool()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
LOOP_OVER_WORKERS(Cancel, ());
@@ -231,24 +229,16 @@ nsDOMWorkerPool::ResumeWorkersForGlobal(
LOOP_OVER_WORKERS(Resume, ());
Resume();
nsAutoMonitor mon(mMonitor);
mon.NotifyAll();
}
}
-nsIDocument*
-nsDOMWorkerPool::GetParentDocument()
-{
- NS_ASSERTION(NS_IsMainThread(),
- "Don't touch the non-threadsafe document off the main thread!");
- return mParentDocument;
-}
-
NS_IMETHODIMP
nsDOMWorkerPool::PostMessage(const nsAString& aMessage)
{
nsresult rv = PostMessageInternal(aMessage);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@@ -281,52 +271,28 @@ NS_IMETHODIMP
nsDOMWorkerPool::GetErrorListener(nsIDOMWorkerErrorListener** aListener)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_IF_ADDREF(*aListener = mErrorListener);
return NS_OK;
}
NS_IMETHODIMP
-nsDOMWorkerPool::CreateWorker(const nsAString& aFullScript,
+nsDOMWorkerPool::CreateWorker(const nsAString& fullScript,
nsIDOMWorkerThread** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
- NS_ENSURE_ARG(!aFullScript.IsEmpty());
+ NS_ENSURE_ARG(!fullScript.IsEmpty());
NS_ENSURE_ARG_POINTER(_retval);
- nsRefPtr<nsDOMWorkerThread> worker =
- new nsDOMWorkerThread(this, aFullScript, PR_FALSE);
+ nsRefPtr<nsDOMWorkerThread> worker(new nsDOMWorkerThread(this, fullScript));
NS_ENSURE_TRUE(worker, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = worker->Init();
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(!mWorkers.Contains(worker), "Um?!");
mWorkers.AppendElement(worker);
NS_ADDREF(*_retval = worker);
return NS_OK;
}
-
-NS_IMETHODIMP
-nsDOMWorkerPool::CreateWorkerFromURL(const nsAString& aScriptURL,
- nsIDOMWorkerThread** _retval)
-{
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- NS_ENSURE_ARG(!aScriptURL.IsEmpty());
- NS_ENSURE_ARG_POINTER(_retval);
-
- nsRefPtr<nsDOMWorkerThread> worker =
- new nsDOMWorkerThread(this, aScriptURL, PR_TRUE);
- NS_ENSURE_TRUE(worker, NS_ERROR_OUT_OF_MEMORY);
-
- nsresult rv = worker->Init();
- NS_ENSURE_SUCCESS(rv, rv);
-
- NS_ASSERTION(!mWorkers.Contains(worker), "Um?!");
- mWorkers.AppendElement(worker);
-
- NS_ADDREF(*_retval = worker);
- return NS_OK;
-}
--- a/dom/src/threads/nsDOMWorkerPool.h
+++ b/dom/src/threads/nsDOMWorkerPool.h
@@ -47,42 +47,39 @@
// Other includes
#include "jsapi.h"
#include "nsStringGlue.h"
#include "nsTPtrArray.h"
#include "prmon.h"
class nsDOMWorkerThread;
-class nsIDocument;
class nsIScriptError;
class nsIScriptGlobalObject;
/**
* The pool is almost always touched only on the main thread.
*/
class nsDOMWorkerPool : public nsDOMWorkerBase,
public nsIDOMWorkerPool,
public nsIClassInfo
{
friend class nsDOMThreadService;
friend class nsDOMWorkerFunctions;
friend class nsDOMWorkerPoolWeakRef;
- friend class nsDOMWorkerScriptLoader;
- friend class nsDOMWorkerStreamObserver;
friend class nsDOMWorkerThread;
friend class nsReportErrorRunnable;
friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMWORKERPOOL
NS_DECL_NSICLASSINFO
- nsDOMWorkerPool(nsIDocument* aDocument);
+ nsDOMWorkerPool();
// For nsDOMWorkerBase
virtual nsDOMWorkerPool* Pool() {
return this;
}
private:
virtual ~nsDOMWorkerPool();
@@ -104,24 +101,19 @@ private:
void CancelWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
void SuspendWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
void ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
PRMonitor* Monitor() {
return mMonitor;
}
- nsIDocument* GetParentDocument();
-
// Weak reference to the window that created and owns this pool.
nsISupports* mParentGlobal;
- // Weak reference to the document that created this pool.
- nsIDocument* mParentDocument;
-
// Weak array of workers. The idea is that workers can be garbage collected
// independently of the owning pool and other workers.
nsTPtrArray<nsDOMWorkerThread> mWorkers;
// An error handler function, may be null.
nsCOMPtr<nsIDOMWorkerErrorListener> mErrorListener;
// Monitor for suspending and resuming workers.
deleted file mode 100644
--- a/dom/src/threads/nsDOMWorkerScriptLoader.cpp
+++ /dev/null
@@ -1,790 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is worker threads.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Ben Turner <bent.mozilla@gmail.com> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsDOMWorkerScriptLoader.h"
-
-// Interfaces
-#include "nsIContentPolicy.h"
-#include "nsIIOService.h"
-#include "nsIRequest.h"
-#include "nsIScriptSecurityManager.h"
-#include "nsIStreamLoader.h"
-
-// Other includes
-#include "nsAutoLock.h"
-#include "nsContentErrors.h"
-#include "nsContentPolicyUtils.h"
-#include "nsContentUtils.h"
-#include "nsISupportsPrimitives.h"
-#include "nsNetError.h"
-#include "nsNetUtil.h"
-#include "nsScriptLoader.h"
-#include "nsThreadUtils.h"
-#include "pratom.h"
-
-// DOMWorker includes
-#include "nsDOMWorkerPool.h"
-#include "nsDOMThreadService.h"
-#include "nsDOMWorkerTimeout.h"
-
-#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
-
-nsDOMWorkerScriptLoader::nsDOMWorkerScriptLoader()
-: mWorker(nsnull),
- mTarget(nsnull),
- mCx(NULL),
- mScriptCount(0),
- mCanceled(PR_FALSE),
- mTrackedByWorker(PR_FALSE)
-{
- // Created on worker thread.
- NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-}
-
-nsDOMWorkerScriptLoader::~nsDOMWorkerScriptLoader()
-{
- // Can't touch mWorker's lock
- if (!mCanceled) {
- // Destroyed on worker thread, unless canceled (and then who knows!).
- NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
- if (mTrackedByWorker) {
- jsrefcount suspendDepth;
- if (mCx) {
- suspendDepth = JS_SuspendRequest(mCx);
- }
-
- nsAutoLock lock(mWorker->Lock());
- #ifdef DEBUG
- PRBool removed =
- #endif
- mWorker->mScriptLoaders.RemoveElement(this);
- NS_ASSERTION(removed, "Something is wrong here!");
-
- if (mCx) {
- JS_ResumeRequest(mCx, suspendDepth);
- }
- }
- }
-}
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerScriptLoader, nsRunnable,
- nsIStreamLoaderObserver)
-
-nsresult
-nsDOMWorkerScriptLoader::LoadScripts(nsDOMWorkerThread* aWorker,
- JSContext* aCx,
- const nsTArray<nsString>& aURLs)
-{
- NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
- NS_ASSERTION(aWorker, "Null worker!");
- NS_ASSERTION(aCx, "Null context!");
-
- NS_ASSERTION(!mWorker, "Not designed to be used more than once!");
-
- mWorker = aWorker;
- mCx = aCx;
-
- mTarget = NS_GetCurrentThread();
- NS_ASSERTION(mTarget, "This should never be null!");
-
- {
- JSAutoSuspendRequest asr(aCx);
- nsAutoLock lock(mWorker->Lock());
- mTrackedByWorker = nsnull != mWorker->mScriptLoaders.AppendElement(this);
- NS_ASSERTION(mTrackedByWorker, "Failed to add loader to worker's array!");
- }
-
- if (mCanceled) {
- return NS_ERROR_ABORT;
- }
-
- mScriptCount = aURLs.Length();
- if (!mScriptCount) {
- return NS_ERROR_INVALID_ARG;
- }
-
- // Do all the memory work for these arrays now rather than checking for
- // failures all along the way.
- PRBool success = mLoadInfos.SetCapacity(mScriptCount);
- NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
-
- // Need one runnable per script and then an extra for the finished
- // notification.
- success = mPendingRunnables.SetCapacity(mScriptCount + 1);
- NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
-
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- ScriptLoadInfo* newInfo = mLoadInfos.AppendElement();
- NS_ASSERTION(newInfo, "Shouldn't fail if SetCapacity succeeded above!");
-
- newInfo->url.Assign(aURLs[index]);
- if (newInfo->url.IsEmpty()) {
- return NS_ERROR_INVALID_ARG;
- }
-
- success = newInfo->scriptObj.Hold(aCx);
- NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
- }
-
- // Don't want timeouts, etc., from queuing up while we're waiting on the
- // network or compiling.
- AutoSuspendWorkerEvents aswe(this);
-
- nsresult rv = DoRunLoop();
-
- {
- JSAutoSuspendRequest asr(aCx);
- nsAutoLock lock(mWorker->Lock());
-#ifdef DEBUG
- PRBool removed =
-#endif
- mWorker->mScriptLoaders.RemoveElement(this);
- NS_ASSERTION(removed, "Something is wrong here!");
- mTrackedByWorker = PR_FALSE;
- }
-
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Verify that all scripts downloaded and compiled.
- rv = VerifyScripts();
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- rv = ExecuteScripts();
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::LoadScript(nsDOMWorkerThread* aWorker,
- JSContext* aCx,
- const nsString& aURL)
-{
- nsAutoTArray<nsString, 1> url;
- url.AppendElement(aURL);
-
- return LoadScripts(aWorker, aCx, url);
-}
-
-nsresult
-nsDOMWorkerScriptLoader::DoRunLoop()
-{
- NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
- volatile PRBool done = PR_FALSE;
- mDoneRunnable = new ScriptLoaderDone(this, &done);
- NS_ENSURE_TRUE(mDoneRunnable, NS_ERROR_OUT_OF_MEMORY);
-
- nsresult rv = NS_DispatchToMainThread(this);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!(done || mCanceled)) {
- // Since we're going to lock up this thread we might as well allow the
- // thread service to schedule another worker on a new thread.
- nsDOMThreadService* threadService = nsDOMThreadService::get();
- PRBool changed = NS_SUCCEEDED(threadService->ChangeThreadPoolMaxThreads(1));
-
- while (!(done || mCanceled)) {
- JSAutoSuspendRequest asr(mCx);
- NS_ProcessNextEvent(mTarget);
- }
-
- if (changed) {
- threadService->ChangeThreadPoolMaxThreads(-1);
- }
- }
-
- return mCanceled ? NS_ERROR_ABORT : NS_OK;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::VerifyScripts()
-{
- nsresult rv = NS_OK;
-
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- ScriptLoadInfo& loadInfo = mLoadInfos[index];
- NS_ASSERTION(loadInfo.done, "Inconsistent state!");
-
- if (NS_SUCCEEDED(loadInfo.result) && loadInfo.scriptObj) {
- continue;
- }
-
- NS_ASSERTION(!loadInfo.scriptObj, "Inconsistent state!");
-
- // Flag failure before worrying about whether or not to report an error.
- rv = NS_FAILED(loadInfo.result) ? loadInfo.result : NS_ERROR_FAILURE;
-
- // If loadInfo.result is a success code then the compiler probably reported
- // an error already. Also we don't really care about NS_BINDING_ABORTED
- // since that's the code we set when some other script had a problem and the
- // rest were canceled.
- if (NS_SUCCEEDED(loadInfo.result) || loadInfo.result == NS_BINDING_ABORTED) {
- continue;
- }
-
- // Ok, this is the script that caused us to fail.
-
- // Only throw an error there is no other pending exception.
- if (!JS_IsExceptionPending(mCx)) {
- NS_ConvertUTF16toUTF8 url(loadInfo.url);
- JS_ReportError(mCx, "Failed to compile script: %s", url.get());
- }
- break;
- }
-
- return rv;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::ExecuteScripts()
-{
- // Now execute all the scripts.
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
- JSScript* script =
- static_cast<JSScript*>(JS_GetPrivate(mCx, loadInfo.scriptObj));
- NS_ASSERTION(script, "This shouldn't ever be null!");
-
- JSObject* global = mWorker->mGlobal ?
- mWorker->mGlobal :
- JS_GetGlobalObject(mCx);
- NS_ENSURE_STATE(global);
-
- // Because we may have nested calls to this function we don't want the
- // execution to automatically report errors. We let them propagate instead.
- uint32 oldOpts =
- JS_SetOptions(mCx, JS_GetOptions(mCx) | JSOPTION_DONT_REPORT_UNCAUGHT);
-
- jsval val;
- PRBool success = JS_ExecuteScript(mCx, global, script, &val);
-
- JS_SetOptions(mCx, oldOpts);
-
- if (!success) {
- return NS_ERROR_FAILURE;
- }
- }
- return NS_OK;
-}
-
-void
-nsDOMWorkerScriptLoader::Cancel()
-{
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- NS_ASSERTION(!mCanceled, "Cancel called more than once!");
- mCanceled = PR_TRUE;
-
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
- nsIRequest* request =
- static_cast<nsIRequest*>(loadInfo.channel.get());
- if (request) {
-#ifdef DEBUG
- nsresult rv =
-#endif
- request->Cancel(NS_BINDING_ABORTED);
- NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to cancel channel!");
- }
- }
-
- nsAutoTArray<ScriptLoaderRunnable*, 10> runnables;
- {
- nsAutoLock lock(mWorker->Lock());
- runnables.AppendElements(mPendingRunnables);
- mPendingRunnables.Clear();
- }
-
- PRUint32 runnableCount = runnables.Length();
- for (PRUint32 index = 0; index < runnableCount; index++) {
- runnables[index]->Revoke();
- }
-
- // We're about to post a revoked event to the worker thread, which seems
- // silly, but we have to do this because the worker thread may be sleeping
- // waiting on its event queue.
- NotifyDone();
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::Run()
-{
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- // We may have been canceled already.
- if (mCanceled) {
- return NS_BINDING_ABORTED;
- }
-
- nsresult rv = RunInternal();
- if (NS_SUCCEEDED(rv)) {
- return rv;
- }
-
- // Ok, something failed beyond a normal cancel.
-
- // If necko is holding a ref to us then we'll end up notifying in the
- // OnStreamComplete method, not here.
- PRBool needsNotify = PR_TRUE;
-
- // Cancel any async channels that were already opened.
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
- nsIRequest* request = static_cast<nsIRequest*>(loadInfo.channel.get());
- if (request) {
-#ifdef DEBUG
- nsresult rvInner =
-#endif
- request->Cancel(NS_BINDING_ABORTED);
- NS_WARN_IF_FALSE(NS_SUCCEEDED(rvInner), "Failed to cancel channel!");
-
- // Necko is holding a ref to us so make sure that the OnStreamComplete
- // code sends the done event.
- needsNotify = PR_FALSE;
- }
- else {
- // Make sure to set this so that the OnStreamComplete code will dispatch
- // the done event.
- loadInfo.done = PR_TRUE;
- }
- }
-
- if (needsNotify) {
- NotifyDone();
- }
-
- return rv;
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
- nsISupports* aContext,
- nsresult aStatus,
- PRUint32 aStringLen,
- const PRUint8* aString)
-{
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- // We may have been canceled already.
- if (mCanceled) {
- return NS_BINDING_ABORTED;
- }
-
- nsresult rv = OnStreamCompleteInternal(aLoader, aContext, aStatus, aStringLen,
- aString);
-
- // Dispatch the done event if we've received all the data.
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- if (!mLoadInfos[index].done) {
- // Some async load is still outstanding, don't notify yet.
- break;
- }
-
- if (index == mScriptCount - 1) {
- // All loads complete, signal the thread.
- NotifyDone();
- }
- }
-
- return rv;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::RunInternal()
-{
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- // Things we need to make all this work...
- nsIDocument* parentDoc = mWorker->Pool()->GetParentDocument();
- NS_ASSERTION(parentDoc, "Null parent document?!");
-
- // All of these can potentially be null, but that should be ok. We'll either
- // succeed without them or fail below.
- nsIURI* parentBaseURI = parentDoc->GetBaseURI();
- nsCOMPtr<nsILoadGroup> loadGroup(parentDoc->GetDocumentLoadGroup());
- nsCOMPtr<nsIIOService> ios(do_GetIOService());
-
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- ScriptLoadInfo& loadInfo = mLoadInfos[index];
- nsresult& rv = loadInfo.result;
-
- nsCOMPtr<nsIURI>& uri = loadInfo.finalURI;
- rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
- loadInfo.url, parentDoc,
- parentBaseURI);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
- NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
-
- rv =
- secMan->CheckLoadURIWithPrincipal(parentDoc->NodePrincipal(), uri,
- nsIScriptSecurityManager::ALLOW_CHROME);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
- rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT,
- uri,
- parentDoc->NodePrincipal(),
- parentDoc,
- NS_LITERAL_CSTRING("text/javascript"),
- nsnull,
- &shouldLoad,
- nsContentUtils::GetContentPolicy(),
- secMan);
- if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
- if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
- return NS_ERROR_CONTENT_BLOCKED;
- }
- return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
- }
-
- // We need to know which index we're on in OnStreamComplete so we know where
- // to put the result.
- nsCOMPtr<nsISupportsPRUint32> indexSupports =
- do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = indexSupports->SetData(index);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // We don't care about progress so just use the simple stream loader for
- // OnStreamComplete notification only.
- nsCOMPtr<nsIStreamLoader> loader;
- rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = NS_NewChannel(getter_AddRefs(loadInfo.channel), uri, ios, loadGroup);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = loadInfo.channel->AsyncOpen(loader, indexSupports);
- if (NS_FAILED(rv)) {
- // Null this out so we don't try to cancel it later.
- loadInfo.channel = nsnull;
- return rv;
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::OnStreamCompleteInternal(nsIStreamLoader* aLoader,
- nsISupports* aContext,
- nsresult aStatus,
- PRUint32 aStringLen,
- const PRUint8* aString)
-{
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
- NS_ENSURE_TRUE(indexSupports, NS_ERROR_NO_INTERFACE);
-
- PRUint32 index = PR_UINT32_MAX;
- indexSupports->GetData(&index);
-
- if (index >= mScriptCount) {
- NS_NOTREACHED("This really can't fail or we'll hang!");
- return NS_ERROR_FAILURE;
- }
-
- ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
- NS_ASSERTION(!loadInfo.done, "Got complete on the same load twice!");
- loadInfo.done = PR_TRUE;
-
-#ifdef DEBUG
- // Make sure we're seeing the channel that we expect.
- nsCOMPtr<nsIRequest> request;
- nsresult rvDebug = aLoader->GetRequest(getter_AddRefs(request));
-
- // When we cancel sometimes we get null here. That should be ok, but only if
- // we're canceled.
- NS_ASSERTION(NS_SUCCEEDED(rvDebug) || mCanceled, "GetRequest failed!");
-
- if (NS_SUCCEEDED(rvDebug)) {
- nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
- NS_ASSERTION(channel, "QI failed!");
-
- nsCOMPtr<nsISupports> thisChannel(do_QueryInterface(channel));
- NS_ASSERTION(thisChannel, "QI failed!");
-
- nsCOMPtr<nsISupports> ourChannel(do_QueryInterface(loadInfo.channel));
- NS_ASSERTION(ourChannel, "QI failed!");
-
- NS_ASSERTION(thisChannel == ourChannel, "Wrong channel!");
- }
-#endif
-
- // Use an alias to keep rv and loadInfo.result in sync.
- nsresult& rv = loadInfo.result = aStatus;
-
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- if (!(aStringLen && aString)) {
- return rv = NS_ERROR_UNEXPECTED;
- }
-
- nsIDocument* parentDoc = mWorker->Pool()->GetParentDocument();
- NS_ASSERTION(parentDoc, "Null parent document?!");
-
- // Use the regular nsScriptLoader for this grunt work! Should be just fine
- // because we're running on the main thread.
- rv = nsScriptLoader::ConvertToUTF16(loadInfo.channel, aString, aStringLen,
- EmptyString(), parentDoc,
- loadInfo.scriptText);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- if (loadInfo.scriptText.IsEmpty()) {
- return rv = NS_ERROR_FAILURE;
- }
-
- nsCString filename;
- loadInfo.finalURI->GetSpec(filename);
-
- if (filename.IsEmpty()) {
- filename.Assign(NS_LossyConvertUTF16toASCII(loadInfo.url));
- }
- else {
- // This will help callers figure out what their script url resolved to in
- // case of errors.
- loadInfo.url.Assign(NS_ConvertUTF8toUTF16(filename));
- }
-
- nsRefPtr<ScriptCompiler> compiler =
- new ScriptCompiler(this, mCx, loadInfo.scriptText, filename,
- loadInfo.scriptObj);
- NS_ASSERTION(compiler, "Out of memory!");
- if (!compiler) {
- return rv = NS_ERROR_OUT_OF_MEMORY;
- }
-
- rv = mTarget->Dispatch(compiler, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return rv;
-}
-
-void
-nsDOMWorkerScriptLoader::NotifyDone()
-{
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- if (!mDoneRunnable) {
- // We've already completed, no need to cancel anything.
- return;
- }
-
- for (PRUint32 index = 0; index < mScriptCount; index++) {
- ScriptLoadInfo& loadInfo = mLoadInfos[index];
- // Null both of these out because they aren't threadsafe and must be
- // destroyed on this thread.
- loadInfo.channel = nsnull;
- loadInfo.finalURI = nsnull;
-
- if (mCanceled) {
- // Simulate a complete, yet failed, load.
- loadInfo.done = PR_TRUE;
- loadInfo.result = NS_BINDING_ABORTED;
- }
- }
-
-#ifdef DEBUG
- nsresult rv =
-#endif
- mTarget->Dispatch(mDoneRunnable, NS_DISPATCH_NORMAL);
- NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Couldn't dispatch done event!");
-
- mDoneRunnable = nsnull;
-}
-
-void
-nsDOMWorkerScriptLoader::SuspendWorkerEvents()
-{
- NS_ASSERTION(mWorker, "No worker yet!");
- mWorker->SuspendTimeouts();
-}
-
-void
-nsDOMWorkerScriptLoader::ResumeWorkerEvents()
-{
- NS_ASSERTION(mWorker, "No worker yet!");
- mWorker->ResumeTimeouts();
-}
-
-nsDOMWorkerScriptLoader::
-ScriptLoaderRunnable::ScriptLoaderRunnable(nsDOMWorkerScriptLoader* aLoader)
-: mRevoked(PR_FALSE),
- mLoader(aLoader)
-{
- nsAutoLock lock(aLoader->Lock());
-#ifdef DEBUG
- nsDOMWorkerScriptLoader::ScriptLoaderRunnable** added =
-#endif
- aLoader->mPendingRunnables.AppendElement(this);
- NS_ASSERTION(added, "This shouldn't fail because we SetCapacity earlier!");
-}
-
-nsDOMWorkerScriptLoader::
-ScriptLoaderRunnable::~ScriptLoaderRunnable()
-{
- if (!mRevoked) {
- nsAutoLock lock(mLoader->Lock());
-#ifdef DEBUG
- PRBool removed =
-#endif
- mLoader->mPendingRunnables.RemoveElement(this);
- NS_ASSERTION(removed, "Someone has changed the array!");
- }
-}
-
-void
-nsDOMWorkerScriptLoader::ScriptLoaderRunnable::Revoke()
-{
- mRevoked = PR_TRUE;
-}
-
-nsDOMWorkerScriptLoader::
-ScriptCompiler::ScriptCompiler(nsDOMWorkerScriptLoader* aLoader,
- JSContext* aCx,
- const nsString& aScriptText,
- const nsCString& aFilename,
- nsAutoJSObjectHolder& aScriptObj)
-: ScriptLoaderRunnable(aLoader),
- mCx(aCx),
- mScriptText(aScriptText),
- mFilename(aFilename),
- mScriptObj(aScriptObj)
-{
- NS_ASSERTION(aCx, "Null context!");
- NS_ASSERTION(!aScriptText.IsEmpty(), "No script to compile!");
- NS_ASSERTION(aScriptObj.IsHeld(), "Should be held!");
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::ScriptCompiler::Run()
-{
- NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
- if (mRevoked) {
- return NS_OK;
- }
-
- NS_ASSERTION(!mScriptObj, "Already have a script object?!");
- NS_ASSERTION(mScriptObj.IsHeld(), "Not held?!");
- NS_ASSERTION(!mScriptText.IsEmpty(), "Shouldn't have empty source here!");
-
- JSAutoRequest ar(mCx);
-
- JSObject* global = JS_GetGlobalObject(mCx);
- NS_ENSURE_STATE(global);
-
- // Because we may have nested calls to this function we don't want the
- // execution to automatically report errors. We let them propagate instead.
- uint32 oldOpts =
- JS_SetOptions(mCx, JS_GetOptions(mCx) | JSOPTION_DONT_REPORT_UNCAUGHT);
-
- JSScript* script = JS_CompileUCScript(mCx, global, mScriptText.BeginReading(),
- mScriptText.Length(), mFilename.get(),
- 1);
- JS_SetOptions(mCx, oldOpts);
-
- if (!script) {
- return NS_ERROR_FAILURE;
- }
-
- mScriptObj = JS_NewScriptObject(mCx, script);
- NS_ENSURE_STATE(mScriptObj);
-
- return NS_OK;
-}
-
-nsDOMWorkerScriptLoader::
-ScriptLoaderDone::ScriptLoaderDone(nsDOMWorkerScriptLoader* aLoader,
- volatile PRBool* aDoneFlag)
-: ScriptLoaderRunnable(aLoader),
- mDoneFlag(aDoneFlag)
-{
- NS_ASSERTION(aDoneFlag && !*aDoneFlag, "Bad setup!");
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::ScriptLoaderDone::Run()
-{
- NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
- if (mRevoked) {
- return NS_OK;
- }
-
- *mDoneFlag = PR_TRUE;
- return NS_OK;
-}
-
-nsDOMWorkerScriptLoader::
-AutoSuspendWorkerEvents::AutoSuspendWorkerEvents(nsDOMWorkerScriptLoader* aLoader)
-: mLoader(aLoader)
-{
- NS_ASSERTION(aLoader, "Don't hand me null!");
- aLoader->SuspendWorkerEvents();
-}
-
-nsDOMWorkerScriptLoader::
-AutoSuspendWorkerEvents::~AutoSuspendWorkerEvents()
-{
- mLoader->ResumeWorkerEvents();
-}
deleted file mode 100644
--- a/dom/src/threads/nsDOMWorkerScriptLoader.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is worker threads.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Ben Turner <bent.mozilla@gmail.com> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __NSDOMWORKERSCRIPTLOADER_H__
-#define __NSDOMWORKERSCRIPTLOADER_H__
-
-// Bases
-#include "nsThreadUtils.h"
-#include "nsIStreamLoader.h"
-
-// Interfaces
-#include "nsIChannel.h"
-#include "nsIURI.h"
-
-// Other includes
-#include "jsapi.h"
-#include "nsAutoPtr.h"
-#include "nsAutoJSObjectHolder.h"
-#include "nsCOMPtr.h"
-#include "nsStringGlue.h"
-#include "nsTArray.h"
-#include "prlock.h"
-
-// DOMWorker includes
-#include "nsDOMWorkerThread.h"
-
-/**
- * This class takes a list of script URLs, downloads the scripts, compiles the
- * scripts, and then finally executes them. Due to platform limitations all
- * network operations must happen on the main thread so this object sends events
- * back and forth from the worker thread to the main thread. The flow goes like
- * this:
- *
- * 1. (Worker thread) nsDOMWorkerScriptLoader created.
- * 2. (Worker thread) LoadScript(s) called. Some simple argument validation is
- * performed (currently limited to ensuring that all
- * arguments are strings). nsDOMWorkerScriptLoader is then
- * dispatched to the main thread.
- * 3. (Main thread) Arguments validated as URIs, security checks performed,
- * content policy consulted. Network loads begin.
- * 4. (Necko thread) Necko stuff!
- * 5. (Main thread) Completed downloads are packaged in a ScriptCompiler
- * runnable and sent to the worker thread.
- * 6. (Worker thread) ScriptCompiler runnables are processed (i.e. their
- * scripts are compiled) in the order in which the necko
- * downloads completed.
- * 7. (Worker thread) After all loads complete and all compilation succeeds
- * the scripts are executed in the order that the URLs were
- * given to LoadScript(s).
- *
- * Currently if *anything* after 2 fails then we cancel any pending loads and
- * bail out entirely.
- */
-class nsDOMWorkerScriptLoader : public nsRunnable,
- public nsIStreamLoaderObserver
-{
- friend class AutoSuspendWorkerEvents;
- friend class nsDOMWorkerFunctions;
- friend class nsDOMWorkerThread;
- friend class ScriptLoaderRunnable;
-
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSIRUNNABLE
- NS_DECL_NSISTREAMLOADEROBSERVER
-
- nsDOMWorkerScriptLoader();
-
- nsresult LoadScripts(nsDOMWorkerThread* aWorker,
- JSContext* aCx,
- const nsTArray<nsString>& aURLs);
-
- nsresult LoadScript(nsDOMWorkerThread* aWorker,
- JSContext* aCx,
- const nsString& aURL);
-
- void Cancel();
-
-private:
- ~nsDOMWorkerScriptLoader();
-
- nsresult DoRunLoop();
- nsresult VerifyScripts();
- nsresult ExecuteScripts();
-
- nsresult RunInternal();
-
- nsresult OnStreamCompleteInternal(nsIStreamLoader* aLoader,
- nsISupports* aContext,
- nsresult aStatus,
- PRUint32 aStringLen,
- const PRUint8* aString);
-
- void NotifyDone();
-
- void SuspendWorkerEvents();
- void ResumeWorkerEvents();
-
- PRLock* Lock() {
- return mWorker->Lock();
- }
-
- class ScriptLoaderRunnable : public nsRunnable
- {
- protected:
- // Meant to be inherited.
- ScriptLoaderRunnable(nsDOMWorkerScriptLoader* aLoader);
- virtual ~ScriptLoaderRunnable();
-
- public:
- void Revoke();
-
- protected:
- PRBool mRevoked;
-
- private:
- nsDOMWorkerScriptLoader* mLoader;
- };
-
- class ScriptCompiler : public ScriptLoaderRunnable
- {
- public:
- NS_DECL_NSIRUNNABLE
-
- ScriptCompiler(nsDOMWorkerScriptLoader* aLoader,
- JSContext* aCx,
- const nsString& aScriptText,
- const nsCString& aFilename,
- nsAutoJSObjectHolder& aScriptObj);
-
- private:
- JSContext* mCx;
- nsString mScriptText;
- nsCString mFilename;
- nsAutoJSObjectHolder& mScriptObj;
- };
-
- class ScriptLoaderDone : public ScriptLoaderRunnable
- {
- public:
- NS_DECL_NSIRUNNABLE
-
- ScriptLoaderDone(nsDOMWorkerScriptLoader* aLoader,
- volatile PRBool* aDoneFlag);
-
- private:
- volatile PRBool* mDoneFlag;
- };
-
- class AutoSuspendWorkerEvents
- {
- public:
- AutoSuspendWorkerEvents(nsDOMWorkerScriptLoader* aLoader);
- ~AutoSuspendWorkerEvents();
-
- private:
- nsDOMWorkerScriptLoader* mLoader;
- };
-
- struct ScriptLoadInfo
- {
- ScriptLoadInfo() : done(PR_FALSE), result(NS_ERROR_NOT_INITIALIZED) { }
-
- nsString url;
- nsString scriptText;
- PRBool done;
- nsresult result;
- nsCOMPtr<nsIURI> finalURI;
- nsCOMPtr<nsIChannel> channel;
- nsAutoJSObjectHolder scriptObj;
- };
-
- nsDOMWorkerThread* mWorker;
- nsIThread* mTarget;
- JSContext* mCx;
-
- nsRefPtr<ScriptLoaderDone> mDoneRunnable;
-
- PRUint32 mScriptCount;
- nsTArray<ScriptLoadInfo> mLoadInfos;
-
- PRPackedBool mCanceled;
- PRPackedBool mTrackedByWorker;
-
- // Protected by mWorker's lock!
- nsTArray<ScriptLoaderRunnable*> mPendingRunnables;
-};
-
-#endif /* __NSDOMWORKERSCRIPTLOADER_H__ */
--- a/dom/src/threads/nsDOMWorkerSecurityManager.cpp
+++ b/dom/src/threads/nsDOMWorkerSecurityManager.cpp
@@ -83,18 +83,8 @@ nsDOMWorkerSecurityManager::CanAccess(PR
JSObject* aJSObject,
nsISupports* aObj,
nsIClassInfo* aClassInfo,
jsval aName,
void** aPolicy)
{
return NS_OK;
}
-
-JSBool
-nsDOMWorkerSecurityManager::JSCheckAccess(JSContext *cx,
- JSObject *obj,
- jsval id,
- JSAccessMode mode,
- jsval *vp)
-{
- return JS_TRUE;
-}
--- a/dom/src/threads/nsDOMWorkerSecurityManager.h
+++ b/dom/src/threads/nsDOMWorkerSecurityManager.h
@@ -35,22 +35,17 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERSECURITYMANAGER_H__
#define __NSDOMWORKERSECURITYMANAGER_H__
#include "nsIXPCSecurityManager.h"
-#include "jsapi.h"
class nsDOMWorkerSecurityManager : public nsIXPCSecurityManager
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIXPCSECURITYMANAGER
-
- static JSBool JSCheckAccess(JSContext *cx, JSObject *obj, jsval id,
- JSAccessMode mode, jsval *vp);
-
};
#endif /* __NSDOMWORKERSECURITYMANAGER_H__ */
--- a/dom/src/threads/nsDOMWorkerThread.cpp
+++ b/dom/src/threads/nsDOMWorkerThread.cpp
@@ -49,21 +49,19 @@
// Other includes
#ifdef MOZ_SHARK
#include "jsdbgapi.h"
#endif
#include "nsAutoLock.h"
#include "nsContentUtils.h"
#include "nsJSUtils.h"
#include "nsJSEnvironment.h"
-#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMWorkerPool.h"
-#include "nsDOMWorkerScriptLoader.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerTimeout.h"
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
// XXX Could make these functions of nsDOMWorkerThread instead.
class nsDOMWorkerFunctions
{
@@ -91,19 +89,16 @@ public:
jsval* aArgv, jsval* aRval) {
return MakeTimeout(aCx, aObj, aArgc, aArgv, aRval, PR_TRUE);
}
// Used for both clearTimeout() and clearInterval().
static JSBool KillTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
jsval* aArgv, jsval* aRval);
- static JSBool LoadScripts(JSContext* aCx, JSObject* aObj, uintN aArgc,
- jsval* aArgv, jsval* aRval);
-
private:
// Internal helper for SetTimeout and SetInterval.
static JSBool MakeTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
jsval* aArgv, jsval* aRval, PRBool aIsInterval);
};
JSBool
nsDOMWorkerFunctions::Dump(JSContext* aCx,
@@ -159,21 +154,17 @@ nsDOMWorkerFunctions::PostMessage(JSCont
JSString* str;
if (aArgc && (str = JS_ValueToString(aCx, aArgv[0])) && str) {
rv = pool->PostMessageInternal(nsDependentJSString(str), worker);
}
else {
rv = pool->PostMessageInternal(EmptyString(), worker);
}
-
- if (NS_FAILED(rv)) {
- JS_ReportError(aCx, "Failed to post message!");
- return JS_FALSE;
- }
+ NS_ENSURE_SUCCESS(rv, JS_FALSE);
return JS_TRUE;
}
JSBool
nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx,
JSObject* /* aObj */,
uintN aArgc,
@@ -188,26 +179,20 @@ nsDOMWorkerFunctions::MakeTimeout(JSCont
if (worker->IsCanceled()) {
return JS_FALSE;
}
PRUint32 id = ++worker->mNextTimeoutId;
nsAutoPtr<nsDOMWorkerTimeout>
timeout(new nsDOMWorkerTimeout(worker, id));
- if (!timeout) {
- JS_ReportOutOfMemory(aCx);
- return JS_FALSE;
- }
+ NS_ENSURE_TRUE(timeout, JS_FALSE);
nsresult rv = timeout->Init(aCx, aArgc, aArgv, aIsInterval);
- if (NS_FAILED(rv)) {
- JS_ReportError(aCx, "Failed to initialize timeout!");
- return JS_FALSE;
- }
+ NS_ENSURE_SUCCESS(rv, JS_FALSE);
timeout.forget();
*aRval = INT_TO_JSVAL(id);
return JS_TRUE;
}
JSBool
@@ -236,86 +221,24 @@ nsDOMWorkerFunctions::KillTimeout(JSCont
JS_ReportError(aCx, "First argument must be a timeout id");
return JS_FALSE;
}
worker->CancelTimeout(PRUint32(id));
return JS_TRUE;
}
-JSBool JS_DLL_CALLBACK
-nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
- JSObject* /* aObj */,
- uintN aArgc,
- jsval* aArgv,
- jsval* /* aRval */)
-{
- nsDOMWorkerThread* worker =
- static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
- NS_ASSERTION(worker, "This should be set by the DOM thread service!");
-
- if (worker->IsCanceled()) {
- return JS_FALSE;
- }
-
- if (!aArgc) {
- JS_ReportError(aCx, "Function must have at least one argument!");
- return JS_FALSE;
- }
-
- nsAutoTArray<nsString, 5> urls;
-
- if (!urls.SetCapacity((PRUint32)aArgc)) {
- JS_ReportOutOfMemory(aCx);
- return JS_FALSE;
- }
-
- for (uintN index = 0; index < aArgc; index++) {
- jsval val = aArgv[index];
-
- if (!JSVAL_IS_STRING(val)) {
- JS_ReportError(aCx, "Argument %d must be a string", index);
- return JS_FALSE;
- }
-
- JSString* str = JS_ValueToString(aCx, val);
- if (!str) {
- JS_ReportError(aCx, "Couldn't convert argument %d to a string", index);
- return JS_FALSE;
- }
-
- nsString* newURL = urls.AppendElement();
- NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!");
-
- newURL->Assign(nsDependentJSString(str));
- }
-
- nsRefPtr<nsDOMWorkerScriptLoader> loader = new nsDOMWorkerScriptLoader();
- if (!loader) {
- JS_ReportOutOfMemory(aCx);
- return JS_FALSE;
- }
-
- nsresult rv = loader->LoadScripts(worker, aCx, urls);
- if (NS_FAILED(rv)) {
- return JS_FALSE;
- }
-
- return JS_TRUE;
-}
-
JSFunctionSpec gDOMWorkerFunctions[] = {
{ "dump", nsDOMWorkerFunctions::Dump, 1, 0, 0 },
{ "debug", nsDOMWorkerFunctions::DebugDump, 1, 0, 0 },
{ "postMessageToPool", nsDOMWorkerFunctions::PostMessage, 1, 0, 0 },
{ "setTimeout", nsDOMWorkerFunctions::SetTimeout, 1, 0, 0 },
{ "clearTimeout", nsDOMWorkerFunctions::KillTimeout, 1, 0, 0 },
{ "setInterval", nsDOMWorkerFunctions::SetInterval, 1, 0, 0 },
{ "clearInterval", nsDOMWorkerFunctions::KillTimeout, 1, 0, 0 },
- { "loadScripts", nsDOMWorkerFunctions::LoadScripts, 1, 0, 0 },
#ifdef MOZ_SHARK
{ "startShark", js_StartShark, 0, 0, 0 },
{ "stopShark", js_StopShark, 0, 0, 0 },
{ "connectShark", js_ConnectShark, 0, 0, 0 },
{ "disconnectShark", js_DisconnectShark, 0, 0, 0 },
#endif
{ nsnull, nsnull, 0, 0, 0 }
};
@@ -378,49 +301,53 @@ nsDOMWorkerThreadContext::GetThisThread(
NS_ENSURE_TRUE(mWeakRef, NS_ERROR_OUT_OF_MEMORY);
}
NS_ADDREF(*aThisThread = mWeakRef);
return NS_OK;
}
nsDOMWorkerThread::nsDOMWorkerThread(nsDOMWorkerPool* aPool,
- const nsAString& aSource,
- PRBool aSourceIsURL)
+ const nsAString& aSource)
: mPool(aPool),
+ mSource(aSource),
+ mGlobal(nsnull),
mCompiled(PR_FALSE),
mCallbackCount(0),
mNextTimeoutId(0),
mLock(nsnull)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- if (aSourceIsURL) {
- mSourceURL.Assign(aSource);
- NS_ASSERTION(!mSourceURL.IsEmpty(), "Empty source url!");
- }
- else {
- mSource.Assign(aSource);
- NS_ASSERTION(!mSource.IsEmpty(), "Empty source string!");
- }
+ NS_ASSERTION(!aSource.IsEmpty(), "Empty source string!");
PR_INIT_CLIST(&mTimeouts);
}
nsDOMWorkerThread::~nsDOMWorkerThread()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!IsCanceled()) {
nsRefPtr<nsDOMWorkerPool> pool = Pool();
pool->NoteDyingWorker(this);
}
ClearTimeouts();
+ // Only clean up if we created a global object
+ if (mGlobal) {
+ JSRuntime* rt;
+ if (NS_SUCCEEDED(nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt))) {
+ JS_RemoveRootRT(rt, &mGlobal);
+ }
+ else {
+ NS_ERROR("This shouldn't fail!");
+ }
+ }
+
if (mLock) {
nsAutoLock::DestroyLock(mLock);
}
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerThread, nsIDOMWorkerThread,
nsIClassInfo)
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerThread, nsIDOMWorkerThread)
@@ -430,30 +357,23 @@ NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerThr
nsresult
nsDOMWorkerThread::Init()
{
mLock = nsAutoLock::NewLock("nsDOMWorkerThread::mLock");
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
NS_ASSERTION(!mGlobal, "Already got a global?!");
- JSRuntime* rt;
- nsresult rv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
- NS_ENSURE_SUCCESS(rv, rv);
-
- PRBool success = mGlobal.Hold(rt);
- NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
-
// This is pretty cool - all we have to do to get our script executed is to
// pass a no-op runnable to the thread service and it will make sure we have
// a context and global object.
nsCOMPtr<nsIRunnable> runnable(new nsRunnable());
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
- rv = nsDOMThreadService::get()->Dispatch(this, runnable);
+ nsresult rv = nsDOMThreadService::get()->Dispatch(this, runnable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// From nsDOMWorkerBase
nsresult
nsDOMWorkerThread::HandleMessage(const nsAString& aMessage,
@@ -520,21 +440,25 @@ nsDOMWorkerThread::HandleMessage(const n
JSObject* listener;
rv = wrappedListener->GetJSObject(&listener);
NS_ENSURE_SUCCESS(rv, rv);
// And call it.
jsval rval;
PRBool success = JS_CallFunctionValue(cx, mGlobal, OBJECT_TO_JSVAL(listener),
2, argv, &rval);
- if (!success && JS_IsExceptionPending(cx)) {
+ if (!success) {
// Make sure any pending exceptions are converted to errors for the pool.
JS_ReportPendingException(cx);
}
+ // We shouldn't leave any pending exceptions - our error reporter should
+ // clear any exception it reports.
+ NS_ASSERTION(!JS_IsExceptionPending(cx), "Huh?!");
+
return NS_OK;
}
// From nsDOMWorkerBase
nsresult
nsDOMWorkerThread::DispatchMessage(nsIRunnable* aRunnable)
{
nsresult rv = nsDOMThreadService::get()->Dispatch(this, aRunnable);
@@ -543,19 +467,16 @@ nsDOMWorkerThread::DispatchMessage(nsIRu
return NS_OK;
}
void
nsDOMWorkerThread::Cancel()
{
nsDOMWorkerBase::Cancel();
- // Do this before waiting on the thread service below!
- CancelScriptLoaders();
-
// If we're suspended there's a good chance that we're already paused waiting
// on the pool's monitor. Waiting on the thread service's lock will deadlock.
if (!IsSuspended()) {
nsDOMThreadService::get()->WaitForCanceledWorker(this);
}
ClearTimeouts();
}
@@ -573,19 +494,17 @@ nsDOMWorkerThread::Resume()
nsDOMWorkerBase::Resume();
ResumeTimeouts();
}
PRBool
nsDOMWorkerThread::SetGlobalForContext(JSContext* aCx)
{
PRBool success = CompileGlobalObject(aCx);
- if (!success) {
- return PR_FALSE;
- }
+ NS_ENSURE_TRUE(success, PR_FALSE);
JS_SetGlobalObject(aCx, mGlobal);
return PR_TRUE;
}
PRBool
nsDOMWorkerThread::CompileGlobalObject(JSContext* aCx)
{
@@ -639,48 +558,42 @@ nsDOMWorkerThread::CompileGlobalObject(J
NS_ENSURE_SUCCESS(rv, PR_FALSE);
// Set up a name for our worker object
success = JS_DefineProperty(aCx, global, "threadContext",
OBJECT_TO_JSVAL(contextObj), nsnull, nsnull,
JSPROP_ENUMERATE);
NS_ENSURE_TRUE(success, PR_FALSE);
- jsval val;
-
- // From here on out we have to remember to null mGlobal if something fails!
- mGlobal = global;
+ JSScript* script = JS_CompileUCScript(aCx, global,
+ reinterpret_cast<const jschar*>
+ (mSource.BeginReading()),
+ mSource.Length(), nsnull, 1);
+ NS_ENSURE_TRUE(script, PR_FALSE);
- if (mSource.IsEmpty()) {
- NS_ASSERTION(!mSourceURL.IsEmpty(), "Must have a url here!");
-
- nsRefPtr<nsDOMWorkerScriptLoader> loader = new nsDOMWorkerScriptLoader();
- NS_ASSERTION(loader, "Out of memory!");
- if (!loader) {
- mGlobal = NULL;
- return PR_FALSE;
- }
+ JSRuntime* rt;
+ rv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
+ NS_ENSURE_SUCCESS(rv, PR_FALSE);
- rv = loader->LoadScript(this, aCx, mSourceURL);
- JS_ReportPendingException(aCx);
- if (NS_FAILED(rv)) {
- mGlobal = NULL;
- return PR_FALSE;
- }
+ mGlobal = global;
+ success = JS_AddNamedRootRT(rt, &mGlobal, "nsDOMWorkerThread Global Object");
+ if (!success) {
+ NS_WARNING("Failed to root global object for worker thread!");
+ mGlobal = nsnull;
+ return PR_FALSE;
}
- else {
- NS_ASSERTION(!mSource.IsEmpty(), "No source text!");
- // Evaluate and execute the script
- success = JS_EvaluateUCScript(aCx, global, mSource.get(), mSource.Length(),
- "DOMWorker inline script", 1, &val);
- if (!success) {
- mGlobal = NULL;
- return PR_FALSE;
- }
+ // Execute the script
+ jsval val;
+ success = JS_ExecuteScript(aCx, global, script, &val);
+ if (!success) {
+ NS_WARNING("Failed to evaluate script for worker thread!");
+ JS_RemoveRootRT(rt, &mGlobal);
+ mGlobal = nsnull;
+ return PR_FALSE;
}
// See if the message listener function was defined.
nsCOMPtr<nsIDOMWorkerMessageListener> listener;
if (JS_LookupProperty(aCx, global, "messageListener", &val) &&
JSVAL_IS_OBJECT(val) &&
NS_SUCCEEDED(xpc->WrapJS(aCx, JSVAL_TO_OBJECT(val),
NS_GET_IID(nsIDOMWorkerMessageListener),
@@ -827,35 +740,15 @@ nsDOMWorkerThread::ResumeTimeouts()
PRTime now = PR_Now();
PRUint32 count = timeouts.Length();
for (PRUint32 i = 0; i < count; i++) {
timeouts[i]->Resume(now);
}
}
-void
-nsDOMWorkerThread::CancelScriptLoaders()
-{
- nsAutoTArray<nsDOMWorkerScriptLoader*, 20> loaders;
-
- // Must call cancel on the loaders outside the lock!
- {
- nsAutoLock lock(mLock);
- loaders.AppendElements(mScriptLoaders);
-
- // Don't clear mScriptLoaders, they'll remove themselves as they get
- // destroyed.
- }
-
- PRUint32 loaderCount = loaders.Length();
- for (PRUint32 index = 0; index < loaderCount; index++) {
- loaders[index]->Cancel();
- }
-}
-
NS_IMETHODIMP
nsDOMWorkerThread::PostMessage(const nsAString& aMessage)
{
nsresult rv = PostMessageInternal(aMessage);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
--- a/dom/src/threads/nsDOMWorkerThread.h
+++ b/dom/src/threads/nsDOMWorkerThread.h
@@ -42,20 +42,18 @@
// Bases
#include "nsDOMWorkerBase.h"
#include "nsIClassInfo.h"
#include "nsIDOMThreads.h"
// Other includes
#include "jsapi.h"
-#include "nsAutoJSObjectHolder.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
-#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "prclist.h"
#include "prlock.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
// Macro to generate nsIClassInfo methods for these threadsafe DOM classes
@@ -110,40 +108,37 @@ NS_IMETHODIMP
\
NS_IMETHODIMP \
_class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
{ \
return NS_ERROR_NOT_AVAILABLE; \
}
class nsDOMWorkerPool;
-class nsDOMWorkerScriptLoader;
class nsDOMWorkerTimeout;
class nsDOMWorkerThread : public nsDOMWorkerBase,
public nsIDOMWorkerThread,
public nsIClassInfo
{
friend class nsDOMCreateJSContextRunnable;
friend class nsDOMWorkerFunctions;
friend class nsDOMWorkerPool;
friend class nsDOMWorkerRunnable;
- friend class nsDOMWorkerScriptLoader;
friend class nsDOMWorkerTimeout;
friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMWORKERTHREAD
NS_DECL_NSICLASSINFO
nsDOMWorkerThread(nsDOMWorkerPool* aPool,
- const nsAString& aSource,
- PRBool aSourceIsURL);
+ const nsAString& aSource);
virtual nsDOMWorkerPool* Pool() {
NS_ASSERTION(!IsCanceled(), "Don't touch Pool after we've been canceled!");
return mPool;
}
private:
virtual ~nsDOMWorkerThread();
@@ -169,32 +164,23 @@ private:
void AddTimeout(nsDOMWorkerTimeout* aTimeout);
void RemoveTimeout(nsDOMWorkerTimeout* aTimeout);
void ClearTimeouts();
void CancelTimeout(PRUint32 aId);
void SuspendTimeouts();
void ResumeTimeouts();
- void CancelScriptLoaders();
-
- PRLock* Lock() {
- return mLock;
- }
-
nsDOMWorkerPool* mPool;
nsString mSource;
- nsString mSourceURL;
- nsAutoJSObjectHolder mGlobal;
+ JSObject* mGlobal;
PRBool mCompiled;
PRUint32 mCallbackCount;
PRUint32 mNextTimeoutId;
PRLock* mLock;
PRCList mTimeouts;
-
- nsTArray<nsDOMWorkerScriptLoader*> mScriptLoaders;
};
#endif /* __NSDOMWORKERTHREAD_H__ */
--- a/dom/src/threads/test/Makefile.in
+++ b/dom/src/threads/test/Makefile.in
@@ -42,22 +42,16 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/src/threads/tests
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
- importScripts_worker.js \
- importScripts_worker_imported1.js \
- importScripts_worker_imported2.js \
- importScripts_worker_imported3.js \
- importScripts_worker_imported4.js \
- test_importScripts.html \
test_simpleThread.html \
test_threadErrors.html \
test_threadTimeouts.html \
test_longThread.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker.js
+++ /dev/null
@@ -1,54 +0,0 @@
-function messageListener(message, source) {
- switch (message) {
- case 'start':
- loadScripts("importScripts_worker_imported2.js");
- importedScriptFunction2();
- tryBadScripts();
- source.postMessage('started');
- break;
- case 'stop':
- tryBadScripts();
- postMessageToPool('stopped');
- break;
- default:
- throw new Error("Bad message: " + message);
- break;
- }
-}
-
-// This caused security exceptions in the past, make sure it doesn't!
-var constructor = {}.constructor;
-
-loadScripts("importScripts_worker_imported1.js");
-
-// Try to call a function defined in the imported script.
-importedScriptFunction();
-
-function tryBadScripts() {
- var badScripts = [
- // Has a syntax error
- "importScripts_worker_imported3.js",
- // Throws an exception
- "importScripts_worker_imported4.js",
- // Shouldn't exist!
- "http://flippety.com/floppety/foo.js",
- // Not a valid url
- "http://flippety::foo_js ftw"
- ];
-
- for (var i = 0; i < badScripts.length; i++) {
- var caughtException = false;
- var url = badScripts[i];
- try {
- loadScripts(url);
- }
- catch (e) {
- caughtException = true;
- }
- if (!caughtException) {
- throw "Bad script didn't throw exception: " + url;
- }
- }
-}
-
-tryBadScripts();
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported1.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// This caused security exceptions in the past, make sure it doesn't!
-var myConstructor = {}.constructor;
-
-// Try to call a function defined in the imported script.
-function importedScriptFunction() {
- dump("running importedScriptFunction\n");
-}
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported2.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// This caused security exceptions in the past, make sure it doesn't!
-var myConstructor2 = {}.constructor;
-
-// Try to call a function defined in the imported script.
-function importedScriptFunction2() {
- dump("running importedScriptFunction2\n");
-}
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported3.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// Deliberate syntax error, should generate a worker exception!
-for (var index = 0; index < 100) {}
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported4.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// Deliberate throw, should generate a worker exception!
-throw new Error("Bah!");
deleted file mode 100644
--- a/dom/src/threads/test/test_importScripts.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-Tests of DOM Worker Threads (Bug 437152)
--->
-<head>
- <title>Test for DOM Worker Threads (Bug 437152)</title>
- <script type="text/javascript" src="/MochiKit/MochiKit.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>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=437152">DOM Worker Threads Bug 437152</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
- var pool = navigator.newWorkerPool();
- pool.messageListener = function(message, source) {
- switch (message) {
- case "started":
- source.postMessage("stop");
- break;
- case "stopped":
- SimpleTest.finish();
- break;
- default:
- ok(false, "Unexpected message:" + message);
- SimpleTest.finish();
- }
- };
-
- pool.errorListener = function(error, source) {
- ok(false, "Worker had an error:" + error);
- SimpleTest.finish();
- }
-
- var worker = pool.createWorkerFromURL("importScripts_worker.js");
- worker.postMessage("start");
-
- SimpleTest.waitForExplicitFinish();
-</script>
-</pre>
-</body>
-</html>
-