☠☠ backed out by 70ac1a0bc4ab ☠ ☠ | |
author | Ben Turner <bent.mozilla@gmail.com> |
Sun, 17 Jul 2011 15:09:13 -0400 | |
changeset 73715 | fdddabd345b9358618cc7380d2c15314f1575214 |
parent 73714 | 756c914075a35cb1fe88fbea7dd0f041d7ccbb97 |
child 73716 | 3857a4309fc3eb823ce7c167b253b7ed52252f93 |
push id | 235 |
push user | bzbarsky@mozilla.com |
push date | Tue, 27 Sep 2011 17:13:04 +0000 |
treeherder | mozilla-beta@2d1e082d176a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | sicking |
bugs | 649537 |
milestone | 8.0a1 |
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
|
--- a/dom/Makefile.in +++ b/dom/Makefile.in @@ -57,17 +57,16 @@ DIRS = \ interfaces/xbl \ interfaces/xpath \ interfaces/load-save \ interfaces/xul \ interfaces/storage \ interfaces/json \ interfaces/offline \ interfaces/geolocation \ - interfaces/threads \ interfaces/notification \ interfaces/svg \ $(NULL) ifdef MOZ_SMIL DIRS += interfaces/smil endif @@ -76,16 +75,17 @@ DIRS += \ base \ src \ locales \ plugins/base \ plugins/ipc \ indexedDB \ system \ ipc \ + workers \ $(NULL) ifdef ENABLE_TESTS DIRS += tests # These subdirs rely on GTK libraries and header files, it is not # buildable on other non-GTK unix builds
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -455,17 +455,17 @@ // Geolocation #include "nsIDOMGeoGeolocation.h" #include "nsIDOMGeoPosition.h" #include "nsIDOMGeoPositionCoords.h" #include "nsIDOMGeoPositionError.h" // Workers -#include "nsDOMWorker.h" +#include "mozilla/dom/workers/Workers.h" #include "nsDOMFile.h" #include "nsDOMFileReader.h" #include "nsIDOMFileException.h" #include "nsIDOMFileError.h" #include "nsIDOMFormData.h" #include "nsIDOMDOMStringMap.h" @@ -594,19 +594,16 @@ static const char kDOMStringBundleURL[] DOMCI_DATA(Crypto, void) DOMCI_DATA(CRMFObject, void) DOMCI_DATA(SmartCardEvent, void) DOMCI_DATA(ContentFrameMessageManager, void) DOMCI_DATA(DOMPrototype, void) DOMCI_DATA(DOMConstructor, void) -DOMCI_DATA(Worker, void) -DOMCI_DATA(ChromeWorker, void) - #define NS_DEFINE_CLASSINFO_DATA_WITH_NAME(_class, _name, _helper, \ _flags) \ { #_name, \ nsnull, \ { _helper::doCreate }, \ nsnull, \ nsnull, \ nsnull, \ @@ -1426,21 +1423,16 @@ static nsDOMClassInfoData sClassInfoData NS_DEFINE_CLASSINFO_DATA(SimpleGestureEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(MozTouchEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA_WITH_NAME(MathMLElement, Element, nsElementSH, ELEMENT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(Worker, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeWorker, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(WebGLRenderingContext, nsWebGLViewportHandlerSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(WebGLBuffer, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(WebGLTexture, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(WebGLProgram, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -1567,18 +1559,16 @@ struct nsConstructorFuncMapData nsDOMConstructorFunc mConstructorFunc; }; #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func) \ { eDOMClassInfo_##_class##_id, _func }, static const nsConstructorFuncMapData kConstructorFuncMap[] = { - NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Worker, nsDOMWorker::NewWorker) - NS_DEFINE_CONSTRUCTOR_FUNC_DATA(ChromeWorker, nsDOMWorker::NewChromeWorker) NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile) NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder) }; nsIXPConnect *nsDOMClassInfo::sXPConnect = nsnull; nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nsnull; PRBool nsDOMClassInfo::sIsInitialized = PR_FALSE; PRBool nsDOMClassInfo::sDisableDocumentAllSupport = PR_FALSE; @@ -4139,28 +4129,16 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(MathMLElement, nsIDOMElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(Worker, nsIWorker) - DOM_CLASSINFO_MAP_ENTRY(nsIWorker) - DOM_CLASSINFO_MAP_ENTRY(nsIAbstractWorker) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) - DOM_CLASSINFO_MAP_END - - DOM_CLASSINFO_MAP_BEGIN(ChromeWorker, nsIWorker) - DOM_CLASSINFO_MAP_ENTRY(nsIWorker) - DOM_CLASSINFO_MAP_ENTRY(nsIAbstractWorker) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) - DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(WebGLRenderingContext, nsIDOMWebGLRenderingContext) DOM_CLASSINFO_MAP_ENTRY(nsIDOMWebGLRenderingContext) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(WebGLBuffer, nsIWebGLBuffer) DOM_CLASSINFO_MAP_ENTRY(nsIWebGLBuffer) DOM_CLASSINFO_MAP_END @@ -6061,18 +6039,40 @@ nsDOMConstructor::HasInstance(nsIXPConne JSClass *dom_class = JS_GET_CLASS(cx, dom_obj); if (!dom_class) { NS_ERROR("nsDOMConstructor::HasInstance can't get class."); return NS_ERROR_UNEXPECTED; } const nsGlobalNameStruct *name_struct; rv = GetNameStruct(NS_ConvertASCIItoUTF16(dom_class->name), &name_struct); + if (NS_FAILED(rv)) { + return rv; + } + if (!name_struct) { - return rv; + // This isn't a normal DOM object, see if this constructor lives on its + // prototype chain. + jsval val; + if (!JS_GetProperty(cx, obj, "prototype", &val)) { + return NS_ERROR_UNEXPECTED; + } + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(val)); + JSObject *dot_prototype = JSVAL_TO_OBJECT(val); + + JSObject *proto = JS_GetPrototype(cx, dom_obj); + for ( ; proto; proto = JS_GetPrototype(cx, proto)) { + if (proto == dot_prototype) { + *bp = PR_TRUE; + break; + } + } + + return NS_OK; } if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor && name_struct->mType != nsGlobalNameStruct::eTypeExternalClassInfo && name_struct->mType != nsGlobalNameStruct::eTypeExternalConstructorAlias) { // Doesn't have DOM interfaces. return NS_OK; } @@ -6697,16 +6697,20 @@ ContentWindowGetter(JSContext *cx, uintN { JSObject *obj = JS_THIS_OBJECT(cx, vp); if (!obj) return JS_FALSE; return ::JS_GetProperty(cx, obj, "content", vp); } +static JSNewResolveOp sOtherResolveFuncs[] = { + mozilla::dom::workers::ResolveWorkerClasses +}; + NS_IMETHODIMP nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper); if (!JSID_IS_STRING(id)) { @@ -6923,16 +6927,26 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp } // It is not worth calling GlobalResolve() if we are resolving // for assignment, since only read-write properties get dealt // with there. if (!(flags & JSRESOLVE_ASSIGNING)) { JSAutoRequest ar(cx); + // Resolve special classes. + for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sOtherResolveFuncs); i++) { + if (!sOtherResolveFuncs[i](cx, obj, id, flags, objp)) { + return NS_ERROR_FAILURE; + } + if (*objp) { + return NS_OK; + } + } + // Call GlobalResolve() after we call FindChildWithName() so // that named child frames will override external properties // which have been registered with the script namespace manager. JSBool did_resolve = JS_FALSE; rv = GlobalResolve(win, cx, obj, id, &did_resolve); NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -457,19 +457,16 @@ DOMCI_CLASS(NotifyPaintEvent) DOMCI_CLASS(NotifyAudioAvailableEvent) DOMCI_CLASS(SimpleGestureEvent) DOMCI_CLASS(MozTouchEvent) DOMCI_CLASS(MathMLElement) -DOMCI_CLASS(Worker) -DOMCI_CLASS(ChromeWorker) - // WebGL DOMCI_CLASS(WebGLRenderingContext) DOMCI_CLASS(WebGLBuffer) DOMCI_CLASS(WebGLTexture) DOMCI_CLASS(WebGLProgram) DOMCI_CLASS(WebGLShader) DOMCI_CLASS(WebGLFramebuffer) DOMCI_CLASS(WebGLRenderbuffer)
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -86,19 +86,19 @@ #include "nsPluginHost.h" #include "nsIPluginInstanceOwner.h" #include "nsGeolocation.h" #include "nsDesktopNotification.h" #include "nsContentCID.h" #include "nsLayoutStatics.h" #include "nsCycleCollector.h" #include "nsCCUncollectableMarker.h" -#include "nsDOMThreadService.h" #include "nsAutoJSValHolder.h" #include "nsDOMMediaQueryList.h" +#include "mozilla/dom/workers/Workers.h" // Interfaces Needed #include "nsIFrame.h" #include "nsCanvasFrame.h" #include "nsIWidget.h" #include "nsIBaseWindow.h" #include "nsDeviceMotion.h" #include "nsIContent.h" @@ -1239,28 +1239,21 @@ nsGlobalWindow::ClearScopeWhenAllScripts } void nsGlobalWindow::FreeInnerObjects(PRBool aClearScope) { NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window"); // Kill all of the workers for this window. - nsDOMThreadService* dts = nsDOMThreadService::get(); - if (dts) { - nsIScriptContext *scx = GetContextInternal(); - - JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull; - - // Have to suspend this request here because CancelWorkersForGlobal will - // lock until the worker has died and that could cause a deadlock. - JSAutoSuspendRequest asr(cx); - - dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this)); - } + nsIScriptContext *scx = GetContextInternal(); + JSContext *cx = scx ? + static_cast<JSContext*>(scx->GetNativeContext()) : + nsnull; + mozilla::dom::workers::CancelWorkersForWindow(cx, this); // Close all IndexedDB databases for this window. indexedDB::IndexedDatabaseManager* idbManager = indexedDB::IndexedDatabaseManager::Get(); if (idbManager) { idbManager->AbortCloseDatabasesForWindow(this); } @@ -9923,21 +9916,23 @@ nsGlobalWindow::SuspendTimeouts(PRUint32 FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren)); PRBool suspended = (mTimeoutsSuspendDepth != 0); mTimeoutsSuspendDepth += aIncrease; if (!suspended) { DisableDeviceMotionUpdates(); - nsDOMThreadService* dts = nsDOMThreadService::get(); - if (dts) { - dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this)); - } - + // Suspend all of the workers for this window. + nsIScriptContext *scx = GetContextInternal(); + JSContext *cx = scx ? + static_cast<JSContext*>(scx->GetNativeContext()) : + nsnull; + mozilla::dom::workers::SuspendWorkersForWindow(cx, this); + TimeStamp now = TimeStamp::Now(); for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) { // Set mTimeRemaining to be the time remaining for this timer. if (t->mWhen > now) t->mTimeRemaining = t->mWhen - now; else t->mTimeRemaining = TimeDuration(0); @@ -9999,20 +9994,22 @@ nsGlobalWindow::ResumeTimeouts(PRBool aT NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!"); --mTimeoutsSuspendDepth; PRBool shouldResume = (mTimeoutsSuspendDepth == 0); nsresult rv; if (shouldResume) { EnableDeviceMotionUpdates(); - nsDOMThreadService* dts = nsDOMThreadService::get(); - if (dts) { - dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this)); - } + // Resume all of the workers for this window. + nsIScriptContext *scx = GetContextInternal(); + JSContext *cx = scx ? + static_cast<JSContext*>(scx->GetNativeContext()) : + nsnull; + mozilla::dom::workers::ResumeWorkersForWindow(cx, this); // Restore all of the timeouts, using the stored time remaining // (stored in timeout->mTimeRemaining). TimeStamp now = TimeStamp::Now(); #ifdef DEBUG PRBool _seenDummyTimeout = PR_FALSE;
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -3685,42 +3685,42 @@ ObjectPrincipalFinder(JSContext *cx, JSO // JS principals, but the caller of this function expects a weak // reference. So we need to release here. JSPRINCIPALS_DROP(cx, jsPrincipals); return jsPrincipals; } -static JSObject* -DOMReadStructuredClone(JSContext* cx, - JSStructuredCloneReader* reader, - uint32 tag, - uint32 data, - void* closure) +JSObject* +NS_DOMReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, + uint32 tag, + uint32 data, + void* closure) { // We don't currently support any extensions to structured cloning. nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR); return nsnull; } -static JSBool -DOMWriteStructuredClone(JSContext* cx, - JSStructuredCloneWriter* writer, - JSObject* obj, - void *closure) +JSBool +NS_DOMWriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JSObject* obj, + void *closure) { // We don't currently support any extensions to structured cloning. nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR); return JS_FALSE; } -static void -DOMStructuredCloneError(JSContext* cx, - uint32 errorid) +void +NS_DOMStructuredCloneError(JSContext* cx, + uint32 errorid) { // We don't currently support any extensions to structured cloning. nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR); } //static nsresult nsJSRuntime::Init() @@ -3754,19 +3754,19 @@ nsJSRuntime::Init() JSSecurityCallbacks *callbacks = JS_GetRuntimeSecurityCallbacks(sRuntime); NS_ASSERTION(callbacks, "SecMan should have set security callbacks!"); callbacks->findObjectPrincipals = ObjectPrincipalFinder; // Set up the structured clone callbacks. static JSStructuredCloneCallbacks cloneCallbacks = { - DOMReadStructuredClone, - DOMWriteStructuredClone, - DOMStructuredCloneError + NS_DOMReadStructuredClone, + NS_DOMWriteStructuredClone, + NS_DOMStructuredCloneError }; JS_SetStructuredCloneCallbacks(sRuntime, &cloneCallbacks); // Set these global xpconnect options... Preferences::RegisterCallback(MaxScriptRunTimePrefChangedCallback, "dom.max_script_run_time"); MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nsnull);
--- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -358,9 +358,19 @@ public: NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID) /* factory functions */ nsresult NS_CreateJSRuntime(nsIScriptRuntime **aRuntime); /* prototypes */ void NS_ScriptErrorReporter(JSContext *cx, const char *message, JSErrorReport *report); +JSObject* NS_DOMReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, uint32 tag, + uint32 data, void* closure); + +JSBool NS_DOMWriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JSObject* obj, void *closure); + +void NS_DOMStructuredCloneError(JSContext* cx, uint32 errorid); + #endif /* nsJSEnvironment_h___ */
--- a/dom/dom-config.mk +++ b/dom/dom-config.mk @@ -2,17 +2,17 @@ MODULE = dom DOM_SRCDIRS = \ dom/base \ dom/src/events \ dom/src/storage \ dom/src/offline \ dom/src/geolocation \ dom/src/notification \ - dom/src/threads \ + dom/workers \ content/xbl/src \ content/xul/document/src \ content/events/src \ content/base/src \ content/html/content/src \ content/html/document/src \ content/svg/content/src \ layout/generic \
deleted file mode 100644 --- a/dom/interfaces/threads/Makefile.in +++ /dev/null @@ -1,52 +0,0 @@ -# -# ***** 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 mozilla.org code. -# -# The Initial Developer of the Original Code is Mozilla Foundation. -# Portions created by the Initial Developer are Copyright (C) 2007 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Vladimir Vukicevic <vladimir@pobox.com> (Original Author) -# Ben Turner <bent.mozilla@gmail.com> -# -# Alternatively, the contents of this file may be used under the terms of -# either of 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 ***** - -DEPTH = ../../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -MODULE = dom -XPIDL_MODULE = dom_threads -GRE_MODULE = 1 - -XPIDLSRCS = nsIDOMWorkers.idl - -include $(topsrcdir)/config/rules.mk
deleted file mode 100644 --- a/dom/interfaces/threads/nsIDOMWorkers.idl +++ /dev/null @@ -1,156 +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 Web Workers. - * - * 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 ***** */ - -/** - * From http://www.whatwg.org/specs/web-workers/current-work - */ - -#include "nsIDOMEvent.idl" -#include "nsIDOMEventTarget.idl" - -interface nsIDOMEventListener; - -[scriptable, uuid(ab3725b8-3fca-40cc-a42c-92fb154ef01d)] -interface nsIWorkerMessagePort : nsISupports -{ - void postMessage(/* in JSObject aMessage */); -}; - -[scriptable, uuid(508f2d49-e9a0-4fe8-bd33-321820173b4a)] -interface nsIWorkerMessageEvent : nsIDOMEvent -{ - readonly attribute DOMString data; - readonly attribute DOMString origin; - - readonly attribute nsISupports source; - - void initMessageEvent(in DOMString aTypeArg, - in boolean aCanBubbleArg, - in boolean aCancelableArg, - in DOMString aDataArg, - in DOMString aOriginArg, - in nsISupports aSourceArg); -}; - -[scriptable, uuid(73d82c1d-05de-49c9-a23b-7121ff09a67a)] -interface nsIWorkerErrorEvent : nsIDOMEvent -{ - readonly attribute DOMString message; - readonly attribute DOMString filename; - - readonly attribute unsigned long lineno; - - void initErrorEvent(in DOMString aTypeArg, - in boolean aCanBubbleArg, - in boolean aCancelableArg, - in DOMString aMessageArg, - in DOMString aFilenameArg, - in unsigned long aLinenoArg); -}; - -[scriptable, uuid(17a005c3-4f2f-4bb6-b169-c181fa6873de)] -interface nsIWorkerLocation : nsISupports -{ - readonly attribute AUTF8String href; - readonly attribute AUTF8String protocol; - readonly attribute AUTF8String host; - readonly attribute AUTF8String hostname; - readonly attribute AUTF8String port; - readonly attribute AUTF8String pathname; - readonly attribute AUTF8String search; - readonly attribute AUTF8String hash; - - AUTF8String toString(); -}; - -[scriptable, uuid(74fb665a-e477-4ce2-b3c6-c58b1b28b6c3)] -interface nsIWorkerNavigator : nsISupports -{ - readonly attribute DOMString appName; - readonly attribute DOMString appVersion; - readonly attribute DOMString platform; - readonly attribute DOMString userAgent; -}; - -[scriptable, uuid(c111e7d3-8044-4458-aa7b-637696ffb841)] -interface nsIWorkerGlobalScope : nsISupports -{ - readonly attribute nsIWorkerGlobalScope self; - readonly attribute nsIWorkerNavigator navigator; - readonly attribute nsIWorkerLocation location; - - attribute nsIDOMEventListener onerror; -}; - -[scriptable, uuid(5c55ea4b-e4ac-4ceb-bfeb-46bd5e521b8a)] -interface nsIWorkerScope : nsIWorkerGlobalScope -{ - void postMessage(/* in JSObject aMessage */); - - void close(); - - attribute nsIDOMEventListener onmessage; - attribute nsIDOMEventListener onclose; -}; - -[scriptable, builtinclass, uuid(b90b7561-b5e2-4545-84b0-280dbaaa94ea)] -interface nsIAbstractWorker : nsIDOMEventTarget -{ - attribute nsIDOMEventListener onerror; -}; - -[scriptable, builtinclass, uuid(daf945c3-8d29-4724-8939-dd383f7d27a7)] -interface nsIWorker : nsIAbstractWorker -{ - void postMessage(/* in JSObject aMessage */); - - attribute nsIDOMEventListener onmessage; - - void terminate(); -}; - -[scriptable, uuid(cfc4bb32-ca83-4d58-9b6f-66f8054a333a)] -interface nsIWorkerFactory : nsISupports -{ - nsIWorker newChromeWorker(/* in DOMString aScriptURL */); -}; - -%{ C++ -#define NS_WORKERFACTORY_CONTRACTID \ -"@mozilla.org/threads/workerfactory;1" -%}
--- a/dom/src/Makefile.in +++ b/dom/src/Makefile.in @@ -37,11 +37,11 @@ DEPTH = ../.. topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = jsurl events storage offline json geolocation threads notification +DIRS = jsurl events storage offline json geolocation notification foo include $(topsrcdir)/config/rules.mk
new file mode 100644 --- /dev/null +++ b/dom/src/foo/Makefile.in @@ -0,0 +1,55 @@ +# ***** 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): +# Vladimir Vukicevic <vladimir@pobox.com> (Original Author) +# Ben Turner <bent.mozilla@gmail.com> +# +# 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +relativesrcdir = dom/src/foo + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/rules.mk + +_TEST_FILES = \ + test_foo.html \ + $(NULL) + +libs:: $(_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/dom/src/foo/test_foo.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<!-- +Tests of DOM Worker Threads XHR(Bug 450452 ) +--> +<head> + <title>Test for DOM Worker Threads XHR (Bug 450452 )</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> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450452">DOM Worker Threads XHR (Bug 450452)</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + + ok(true, "passed"); + +</script> +</pre> +</body> +</html> +
deleted file mode 100644 --- a/dom/src/threads/nsDOMThreadService.cpp +++ /dev/null @@ -1,1608 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; 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): - * Vladimir Vukicevic <vladimir@pobox.com> (Original Author) - * Ben Turner <bent.mozilla@gmail.com> - * - * 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 "jscntxt.h" - -#include "nsDOMThreadService.h" - -// Interfaces -#include "nsIComponentManager.h" -#include "nsIConsoleService.h" -#include "nsIDocument.h" -#include "nsIDOMDocument.h" -#include "nsIEventTarget.h" -#include "nsIJSContextStack.h" -#include "nsIJSRuntimeService.h" -#include "nsIObserverService.h" -#include "nsIScriptError.h" -#include "nsIScriptGlobalObject.h" -#include "nsIServiceManager.h" -#include "nsISupportsPriority.h" -#include "nsIThreadPool.h" -#include "nsIXPConnect.h" -#include "nsPIDOMWindow.h" - -// Other includes -#include "nsAutoPtr.h" -#include "nsContentUtils.h" -#include "nsDeque.h" -#include "nsGlobalWindow.h" -#include "nsIClassInfoImpl.h" -#include "nsStringBuffer.h" -#include "nsThreadUtils.h" -#include "nsXPCOM.h" -#include "nsXPCOMCID.h" -#include "nsXPCOMCIDInternal.h" -#include "pratom.h" -#include "prthread.h" -#include "mozilla/Preferences.h" - -// DOMWorker includes -#include "nsDOMWorker.h" -#include "nsDOMWorkerEvents.h" -#include "nsDOMWorkerMacros.h" -#include "nsDOMWorkerMessageHandler.h" -#include "nsDOMWorkerPool.h" -#include "nsDOMWorkerSecurityManager.h" -#include "nsDOMWorkerTimeout.h" - -using namespace mozilla; - -#ifdef PR_LOGGING -PRLogModuleInfo *gDOMThreadsLog = nsnull; -#endif -#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args) - -// The maximum number of threads in the internal thread pool -#define THREADPOOL_MAX_THREADS 3 - -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); - -// A "bad" value for the NSPR TLS functions. -#define BAD_TLS_INDEX (PRUintn)-1 - -// Easy access for static functions. No reference here. -static nsDOMThreadService* gDOMThreadService = nsnull; - -// These pointers actually carry references and must be released. -static nsIObserverService* gObserverService = nsnull; -static nsIJSRuntimeService* gJSRuntimeService = nsnull; -static nsIThreadJSContextStack* gThreadJSContextStack = nsnull; -static nsIXPCSecurityManager* gWorkerSecurityManager = nsnull; - -PRUintn gJSContextIndex = BAD_TLS_INDEX; - -static const char* sPrefsToWatch[] = { - "dom.max_script_run_time" -}; - -// The length of time the close handler is allowed to run in milliseconds. -static PRUint32 gWorkerCloseHandlerTimeoutMS = 10000; - -/** - * Simple class to automatically destroy a JSContext to make error handling - * easier. - */ -class JSAutoContextDestroyer -{ -public: - JSAutoContextDestroyer(JSContext* aCx) - : mCx(aCx) { } - - ~JSAutoContextDestroyer() { - if (mCx) { - nsContentUtils::XPConnect()->ReleaseJSContext(mCx, PR_TRUE); - } - } - - operator JSContext*() { - return mCx; - } - - JSContext* forget() { - JSContext* cx = mCx; - 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 - - nsReportErrorRunnable(nsDOMWorker* aWorker, - nsIScriptError* aScriptError) - : mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()), - mScriptError(aScriptError) { - NS_ASSERTION(aScriptError, "Null pointer!"); - } - - NS_IMETHOD Run() { - if (mWorker->IsCanceled()) { - return NS_OK; - } - -#ifdef DEBUG - { - nsRefPtr<nsDOMWorker> parent = mWorker->GetParent(); - if (NS_IsMainThread()) { - NS_ASSERTION(!parent, "Shouldn't have a parent on the main thread!"); - } - else { - NS_ASSERTION(parent, "Should have a parent!"); - - JSContext* cx = nsDOMThreadService::get()->GetCurrentContext(); - NS_ASSERTION(cx, "No context!"); - - nsDOMWorker* currentWorker = (nsDOMWorker*)JS_GetContextPrivate(cx); - NS_ASSERTION(currentWorker == parent, "Wrong worker!"); - } - } -#endif - - NS_NAMED_LITERAL_STRING(errorStr, "error"); - - nsresult rv; - - if (mWorker->HasListeners(errorStr)) { - // Construct the error event. - nsString message; - rv = mScriptError->GetErrorMessage(message); - NS_ENSURE_SUCCESS(rv, rv); - - nsString filename; - rv = mScriptError->GetSourceName(filename); - NS_ENSURE_SUCCESS(rv, rv); - - PRUint32 lineno; - rv = mScriptError->GetLineNumber(&lineno); - NS_ENSURE_SUCCESS(rv, rv); - - nsRefPtr<nsDOMWorkerErrorEvent> event(new nsDOMWorkerErrorEvent()); - NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); - - rv = event->InitErrorEvent(errorStr, PR_FALSE, PR_TRUE, message, - filename, lineno); - NS_ENSURE_SUCCESS(rv, rv); - - event->SetTarget(static_cast<nsDOMWorkerMessageHandler*>(mWorker)); - - PRBool stopPropagation = PR_FALSE; - rv = mWorker->DispatchEvent(static_cast<nsDOMWorkerEvent*>(event), - &stopPropagation); - if (NS_SUCCEEDED(rv) && stopPropagation) { - return NS_OK; - } - } - - nsRefPtr<nsDOMWorker> parent = mWorker->GetParent(); - if (!parent) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - nsCOMPtr<nsIConsoleService> consoleService = - do_GetService(NS_CONSOLESERVICE_CONTRACTID); - if (consoleService) { - rv = consoleService->LogMessage(mScriptError); - NS_ENSURE_SUCCESS(rv, rv); - } - return NS_OK; - } - - nsRefPtr<nsReportErrorRunnable> runnable = - new nsReportErrorRunnable(parent, mScriptError); - if (runnable) { - nsRefPtr<nsDOMWorker> grandparent = parent->GetParent(); - rv = grandparent ? - nsDOMThreadService::get()->Dispatch(grandparent, runnable) : - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; - } - -private: - nsRefPtr<nsDOMWorker> mWorker; - nsCOMPtr<nsIXPConnectWrappedNative> mWorkerWN; - nsCOMPtr<nsIScriptError> mScriptError; -}; - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsReportErrorRunnable, nsIRunnable) - -/** - * Used to post an expired timeout to the correct worker. - */ -class nsDOMWorkerTimeoutRunnable : public nsIRunnable -{ -public: - NS_DECL_ISUPPORTS - - nsDOMWorkerTimeoutRunnable(nsDOMWorkerTimeout* aTimeout) - : mTimeout(aTimeout) { } - - NS_IMETHOD Run() { - return mTimeout->Run(); - } -protected: - nsRefPtr<nsDOMWorkerTimeout> mTimeout; -}; - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorkerTimeoutRunnable, nsIRunnable) - -class nsDOMWorkerKillRunnable : public nsIRunnable -{ -public: - NS_DECL_ISUPPORTS - - nsDOMWorkerKillRunnable(nsDOMWorker* aWorker) - : mWorker(aWorker) { } - - NS_IMETHOD Run() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - mWorker->Kill(); - return NS_OK; - } - -private: - nsRefPtr<nsDOMWorker> mWorker; -}; - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorkerKillRunnable, nsIRunnable) - -/** - * This class exists to solve a particular problem: Calling Dispatch on a - * thread pool will always create a new thread to service the runnable as long - * as the thread limit has not been reached. Since our DOM workers can only be - * accessed by one thread at a time we could end up spawning a new thread that - * does nothing but wait initially. There is no way to control this behavior - * currently so we cheat by using a runnable that emulates a thread. The - * nsDOMThreadService's monitor protects the queue of events. - */ -class nsDOMWorkerRunnable : public nsIRunnable -{ - friend class nsDOMThreadService; - -public: - NS_DECL_ISUPPORTS - - nsDOMWorkerRunnable(nsDOMWorker* aWorker) - : mWorker(aWorker), mCloseTimeoutInterval(0), mKillWorkerWhenDone(PR_FALSE) { - } - - virtual ~nsDOMWorkerRunnable() { - ClearQueue(); - } - - void PutRunnable(nsIRunnable* aRunnable, - PRIntervalTime aTimeoutInterval, - PRBool aClearQueue) { - NS_ASSERTION(aRunnable, "Null pointer!"); - - gDOMThreadService->mReentrantMonitor.AssertCurrentThreadIn(); - - if (NS_LIKELY(!aTimeoutInterval)) { - NS_ADDREF(aRunnable); - mRunnables.Push(aRunnable); - } - else { - NS_ASSERTION(!mCloseRunnable, "More than one close runnable?!"); - if (aClearQueue) { - ClearQueue(); - } - mCloseRunnable = aRunnable; - mCloseTimeoutInterval = aTimeoutInterval; - mKillWorkerWhenDone = PR_TRUE; - } - } - - void SetCloseRunnableTimeout(PRIntervalTime aTimeoutInterval) { - NS_ASSERTION(aTimeoutInterval, "No timeout specified!"); - NS_ASSERTION(aTimeoutInterval!= PR_INTERVAL_NO_TIMEOUT, "Bad timeout!"); - - // No need to enter the monitor because we should already be in it. - - NS_ASSERTION(mWorker->GetExpirationTime() == PR_INTERVAL_NO_TIMEOUT, - "Asked to set timeout on a runnable with no close handler!"); - - // This may actually overflow but we don't care - the worst that could - // happen is that the close handler could run for a slightly different - // amount of time and the spec leaves the time up to us anyway. - mWorker->SetExpirationTime(PR_IntervalNow() + aTimeoutInterval); - } - - NS_IMETHOD Run() { - NS_ASSERTION(!NS_IsMainThread(), - "This should *never* run on the main thread!"); - - // This must have been set up by the thread service - NS_ASSERTION(gJSContextIndex != BAD_TLS_INDEX, "No context index!"); - - // Make sure we have a JSContext to run everything on. - JSContext* cx = (JSContext*)PR_GetThreadPrivate(gJSContextIndex); - if (!cx) { - 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!"); - - if (mWorker->IsPrivileged()) { - JS_SetVersion(cx, JSVERSION_LATEST); - } - else { - JS_SetVersion(cx, JSVERSION_DEFAULT); - } - - 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; - { - nsLazyAutoRequest ar; - JSAutoEnterCompartment ac; - - // Tell the worker which context it will be using - if (mWorker->SetGlobalForContext(cx, &ar, &ac)) { - NS_ASSERTION(ar.entered(), "SetGlobalForContext must enter request on success"); - NS_ASSERTION(ac.entered(), "SetGlobalForContext must enter compartment on success"); - - RunQueue(cx, &killWorkerWhenDone); - - // Remove the global object from the context so that it might be garbage - // collected. - JS_SetGlobalObject(cx, NULL); - JS_SetContextPrivate(cx, NULL); - } - else { - NS_ASSERTION(!ar.entered(), "SetGlobalForContext must not enter request on failure"); - NS_ASSERTION(!ac.entered(), "SetGlobalForContext must not enter compartment on failure"); - - { - // Code in XPConnect assumes that the context's global object won't be - // replaced outside of a request. - JSAutoRequest ar2(cx); - - // This is usually due to a parse error in the worker script... - JS_SetGlobalObject(cx, NULL); - JS_SetContextPrivate(cx, NULL); - } - - ReentrantMonitorAutoEnter mon(gDOMThreadService->mReentrantMonitor); - killWorkerWhenDone = mKillWorkerWhenDone; - gDOMThreadService->WorkerComplete(this); - mon.NotifyAll(); - } - } - - if (killWorkerWhenDone) { - nsCOMPtr<nsIRunnable> runnable = new nsDOMWorkerKillRunnable(mWorker); - NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY); - - nsresult rv = NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; - } - -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) { - while (1) { - nsCOMPtr<nsIRunnable> runnable; - { - ReentrantMonitorAutoEnter mon(gDOMThreadService->mReentrantMonitor); - - runnable = dont_AddRef((nsIRunnable*)mRunnables.PopFront()); - - if (!runnable && mCloseRunnable) { - PRIntervalTime expirationTime; - if (mCloseTimeoutInterval == PR_INTERVAL_NO_TIMEOUT) { - expirationTime = mCloseTimeoutInterval; - } - else { - expirationTime = PR_IntervalNow() + mCloseTimeoutInterval; - } - mWorker->SetExpirationTime(expirationTime); - - runnable.swap(mCloseRunnable); - } - - if (!runnable || mWorker->IsCanceled()) { -#ifdef PR_LOGGING - if (mWorker->IsCanceled()) { - LOG(("Bailing out of run loop for canceled worker[0x%p]", - static_cast<void*>(mWorker.get()))); - } -#endif - *aCloseRunnableSet = mKillWorkerWhenDone; - gDOMThreadService->WorkerComplete(this); - mon.NotifyAll(); - return; - } - } - - // Clear out any old cruft hanging around in the regexp statics. - if (JSObject *global = JS_GetGlobalObject(aCx)) - JS_ClearRegExpStatics(aCx, global); - - runnable->Run(); - } - NS_NOTREACHED("Shouldn't ever get here!"); - } - - // Set at construction - nsRefPtr<nsDOMWorker> mWorker; - - // Protected by mReentrantMonitor - nsDeque mRunnables; - nsCOMPtr<nsIRunnable> mCloseRunnable; - PRIntervalTime mCloseTimeoutInterval; - PRBool mKillWorkerWhenDone; -}; - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorkerRunnable, nsIRunnable) - -/******************************************************************************* - * JS environment function and callbacks - */ - -JSBool -DOMWorkerOperationCallback(JSContext* aCx) -{ - nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(aCx); - NS_ASSERTION(worker, "This must never be null!"); - - PRBool canceled = worker->IsCanceled(); - if (!canceled && worker->IsSuspended()) { - JSAutoSuspendRequest suspended(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. - PRBool extraThreadAllowed = - NS_SUCCEEDED(gDOMThreadService->ChangeThreadPoolMaxThreads(1)); - - // Flush JIT caches now before suspending to avoid holding memory that we - // are not going to use. - JS_FlushCaches(aCx); - - for (;;) { - ReentrantMonitorAutoEnter mon(worker->Pool()->GetReentrantMonitor()); - - // There's a small chance that the worker was canceled after our check - // above in which case we shouldn't wait here. We're guaranteed not to - // race here because the pool reenters its monitor after canceling each - // worker in order to notify its condition variable. - canceled = worker->IsCanceled(); - if (!canceled && worker->IsSuspended()) { - mon.Wait(); - } - else { - break; - } - } - - if (extraThreadAllowed) { - gDOMThreadService->ChangeThreadPoolMaxThreads(-1); - } - } - - if (canceled) { - LOG(("Forcefully killing JS for worker [0x%p]", - static_cast<void*>(worker))); - // Kill execution of the currently running JS. - JS_ClearPendingException(aCx); - return JS_FALSE; - } - return JS_TRUE; -} - -void -DOMWorkerErrorReporter(JSContext* aCx, - const char* aMessage, - JSErrorReport* aReport) -{ - NS_ASSERTION(!NS_IsMainThread(), "Huh?!"); - - nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(aCx); - - if (worker->IsCanceled()) { - // We don't want to report errors from canceled workers. It's very likely - // that we only returned an error in the first place because the worker was - // already canceled. - return; - } - - if (worker->mErrorHandlerRecursionCount == 2) { - // We've somehow ended up in a recursive onerror loop. Bail out. - return; - } - - nsresult rv; - nsCOMPtr<nsIScriptError> scriptError; - - { - // CreateInstance will lock, make sure we suspend our request! - JSAutoSuspendRequest ar(aCx); - - scriptError = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv); - } - - if (NS_FAILED(rv)) { - return; - } - - nsCOMPtr<nsIScriptError2> scriptError2(do_QueryInterface(scriptError)); - - nsAutoString message, filename, line; - PRUint32 lineNumber, columnNumber, flags, errorNumber; - - if (aReport) { - if (aReport->ucmessage) { - message.Assign(reinterpret_cast<const PRUnichar*>(aReport->ucmessage)); - } - filename.AssignWithConversion(aReport->filename); - line.Assign(reinterpret_cast<const PRUnichar*>(aReport->uclinebuf)); - lineNumber = aReport->lineno; - columnNumber = aReport->uctokenptr - aReport->uclinebuf; - flags = aReport->flags; - errorNumber = aReport->errorNumber; - } - else { - lineNumber = columnNumber = errorNumber = 0; - flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag; - } - - if (message.IsEmpty()) { - message.AssignWithConversion(aMessage); - } - - rv = scriptError2->InitWithWindowID(message.get(), filename.get(), line.get(), - lineNumber, columnNumber, flags, - "DOM Worker javascript", - worker->Pool()->WindowID()); - - if (NS_FAILED(rv)) { - return; - } - - // Don't call the error handler if we're out of stack space. - if (errorNumber != JSMSG_OVER_RECURSED) { - // Try the onerror handler for the worker's scope. - nsRefPtr<nsDOMWorkerScope> scope = worker->GetInnerScope(); - NS_ASSERTION(scope, "Null scope!"); - - PRBool hasListeners = scope->HasListeners(NS_LITERAL_STRING("error")); - if (hasListeners) { - nsRefPtr<nsDOMWorkerErrorEvent> event(new nsDOMWorkerErrorEvent()); - if (event) { - rv = event->InitErrorEvent(NS_LITERAL_STRING("error"), PR_FALSE, - PR_TRUE, nsDependentString(message), - filename, lineNumber); - if (NS_SUCCEEDED(rv)) { - event->SetTarget(scope); - - NS_ASSERTION(worker->mErrorHandlerRecursionCount >= 0, - "Bad recursion count logic!"); - worker->mErrorHandlerRecursionCount++; - - PRBool preventDefaultCalled = PR_FALSE; - scope->DispatchEvent(static_cast<nsDOMWorkerEvent*>(event), - &preventDefaultCalled); - - worker->mErrorHandlerRecursionCount--; - - if (preventDefaultCalled) { - return; - } - } - } - } - } - - // Still unhandled, fire at the onerror handler on the worker. - nsCOMPtr<nsIRunnable> runnable = - new nsReportErrorRunnable(worker, scriptError); - NS_ENSURE_TRUE(runnable,); - - nsRefPtr<nsDOMWorker> parent = worker->GetParent(); - - // If this worker has a parent then we need to send the message through the - // thread service to be run on the parent's thread. Otherwise it is a - // top-level worker and we send the message to the main thread. - rv = parent ? nsDOMThreadService::get()->Dispatch(parent, runnable) - : NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - return; - } -} - -/******************************************************************************* - * nsDOMThreadService - */ - -nsDOMThreadService::nsDOMThreadService() -: mReentrantMonitor("nsDOMThreadServer.mReentrantMonitor"), - mNavigatorStringsLoaded(PR_FALSE) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); -#ifdef PR_LOGGING - if (!gDOMThreadsLog) { - gDOMThreadsLog = PR_NewLogModule("nsDOMThreads"); - } -#endif - LOG(("Initializing DOM Thread service")); -} - -nsDOMThreadService::~nsDOMThreadService() -{ - LOG(("DOM Thread service destroyed")); - - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - Cleanup(); -} - -NS_IMPL_THREADSAFE_ISUPPORTS3(nsDOMThreadService, nsIEventTarget, - nsIObserver, - nsIThreadPoolListener) - -nsresult -nsDOMThreadService::Init() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(!gDOMThreadService, "Only one instance should ever be created!"); - - nsresult rv; - nsCOMPtr<nsIObserverService> obs = - do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); - - obs.forget(&gObserverService); - - RegisterPrefCallbacks(); - - mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mThreadPool->SetListener(this); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mThreadPool->SetThreadLimit(THREADPOOL_MAX_THREADS); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mThreadPool->SetIdleThreadLimit(THREADPOOL_IDLE_THREADS); - NS_ENSURE_SUCCESS(rv, rv); - - PRBool success = mWorkersInProgress.Init(); - NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); - - success = mPools.Init(); - NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); - - success = mThreadsafeContractIDs.Init(); - NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); - - success = mJSContexts.SetCapacity(THREADPOOL_THREAD_CAP); - NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); - - nsCOMPtr<nsIJSRuntimeService> - runtimeSvc(do_GetService("@mozilla.org/js/xpc/RuntimeService;1")); - NS_ENSURE_TRUE(runtimeSvc, NS_ERROR_FAILURE); - runtimeSvc.forget(&gJSRuntimeService); - - nsCOMPtr<nsIThreadJSContextStack> - contextStack(do_GetService("@mozilla.org/js/xpc/ContextStack;1")); - NS_ENSURE_TRUE(contextStack, NS_ERROR_FAILURE); - contextStack.forget(&gThreadJSContextStack); - - nsCOMPtr<nsIXPCSecurityManager> secMan(new nsDOMWorkerSecurityManager()); - NS_ENSURE_TRUE(secMan, NS_ERROR_OUT_OF_MEMORY); - secMan.forget(&gWorkerSecurityManager); - - if (gJSContextIndex == BAD_TLS_INDEX && - PR_NewThreadPrivateIndex(&gJSContextIndex, NULL) != PR_SUCCESS) { - NS_ERROR("PR_NewThreadPrivateIndex failed!"); - gJSContextIndex = BAD_TLS_INDEX; - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -/* static */ -already_AddRefed<nsDOMThreadService> -nsDOMThreadService::GetOrInitService() -{ - if (!gDOMThreadService) { - nsRefPtr<nsDOMThreadService> service = new nsDOMThreadService(); - NS_ENSURE_TRUE(service, nsnull); - - nsresult rv = service->Init(); - NS_ENSURE_SUCCESS(rv, nsnull); - - service.swap(gDOMThreadService); - } - - nsRefPtr<nsDOMThreadService> service(gDOMThreadService); - return service.forget(); -} - -/* static */ -nsDOMThreadService* -nsDOMThreadService::get() -{ - return gDOMThreadService; -} - -/* static */ -JSContext* -nsDOMThreadService::GetCurrentContext() -{ - JSContext* cx; - - if (NS_IsMainThread()) { - nsresult rv = ThreadJSContextStack()->GetSafeJSContext(&cx); - NS_ENSURE_SUCCESS(rv, nsnull); - } - else { - NS_ENSURE_TRUE(gJSContextIndex, nsnull); - cx = static_cast<JSContext*>(PR_GetThreadPrivate(gJSContextIndex)); - } - - return cx; -} - -/* static */ -void -nsDOMThreadService::Shutdown() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_IF_RELEASE(gDOMThreadService); -} - -void -nsDOMThreadService::Cleanup() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - // This will either be called at 'xpcom-shutdown' or earlier if the call to - // Init fails somehow. We can therefore assume that all services will still - // be available here. - - // Cancel all workers that weren't tied to a window. - CancelWorkersForGlobal(nsnull); - - { - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - NS_ASSERTION(!mPools.Count(), "Live workers left!"); - mPools.Clear(); - - NS_ASSERTION(!mSuspendedWorkers.Length(), "Suspended workers left!"); - mSuspendedWorkers.Clear(); - } - - if (gObserverService) { - gObserverService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - NS_RELEASE(gObserverService); - - UnregisterPrefCallbacks(); - } - - // The thread pool holds a circular reference to this service through its - // listener. We must shut down the thread pool manually to break this cycle. - if (mThreadPool) { - mThreadPool->Shutdown(); - mThreadPool = nsnull; - } - - // Need to force a GC so that all of our workers get cleaned up. - if (gThreadJSContextStack) { - JSContext* safeContext; - if (NS_SUCCEEDED(gThreadJSContextStack->GetSafeJSContext(&safeContext))) { - JS_GC(safeContext); - } - NS_RELEASE(gThreadJSContextStack); - } - - // These must be released after the thread pool is shut down. - NS_IF_RELEASE(gJSRuntimeService); - NS_IF_RELEASE(gWorkerSecurityManager); -} - -nsresult -nsDOMThreadService::Dispatch(nsDOMWorker* aWorker, - nsIRunnable* aRunnable, - PRIntervalTime aTimeoutInterval, - PRBool aClearQueue) -{ - NS_ASSERTION(aWorker, "Null pointer!"); - NS_ASSERTION(aRunnable, "Null pointer!"); - - if (!mThreadPool) { - // This can happen from a nsDOMWorker::Finalize call after the thread pool - // has been shutdown. It should never be possible off the main thread. - NS_ASSERTION(NS_IsMainThread(), - "This should be impossible on a non-main thread!"); - return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; - } - - // Don't accept the runnable if the worker's close handler has been triggered - // (unless, of course, this is the close runnable as indicated by the non-0 - // timeout value). - if (aWorker->IsClosing() && !aTimeoutInterval) { - LOG(("Will not dispatch runnable [0x%p] for closing worker [0x%p]", - static_cast<void*>(aRunnable), static_cast<void*>(aWorker))); - return NS_ERROR_NOT_AVAILABLE; - } - - nsRefPtr<nsDOMWorkerRunnable> workerRunnable; - { - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - if (mWorkersInProgress.Get(aWorker, getter_AddRefs(workerRunnable))) { - workerRunnable->PutRunnable(aRunnable, aTimeoutInterval, aClearQueue); - return NS_OK; - } - - workerRunnable = new nsDOMWorkerRunnable(aWorker); - NS_ENSURE_TRUE(workerRunnable, NS_ERROR_OUT_OF_MEMORY); - - workerRunnable->PutRunnable(aRunnable, aTimeoutInterval, PR_FALSE); - - PRBool success = mWorkersInProgress.Put(aWorker, workerRunnable); - NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); - } - - nsresult rv = mThreadPool->Dispatch(workerRunnable, NS_DISPATCH_NORMAL); - - // XXX This is a mess and it could probably be removed once we have an - // infallible malloc implementation. - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch runnable to thread pool!"); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - // We exited the monitor after inserting the runnable into the table so make - // sure we're removing the right one! - nsRefPtr<nsDOMWorkerRunnable> tableRunnable; - if (mWorkersInProgress.Get(aWorker, getter_AddRefs(tableRunnable)) && - workerRunnable == tableRunnable) { - mWorkersInProgress.Remove(aWorker); - - // And don't forget to tell anyone who's waiting. - mon.NotifyAll(); - } - - return rv; - } - - return NS_OK; -} - -void -nsDOMThreadService::SetWorkerTimeout(nsDOMWorker* aWorker, - PRIntervalTime aTimeoutInterval) -{ - NS_ASSERTION(aWorker, "Null pointer!"); - NS_ASSERTION(aTimeoutInterval, "No timeout specified!"); - - NS_ASSERTION(mThreadPool, "Dispatch called after 'xpcom-shutdown'!"); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - nsRefPtr<nsDOMWorkerRunnable> workerRunnable; - if (mWorkersInProgress.Get(aWorker, getter_AddRefs(workerRunnable))) { - workerRunnable->SetCloseRunnableTimeout(aTimeoutInterval); - } -} - -void -nsDOMThreadService::WorkerComplete(nsDOMWorkerRunnable* aRunnable) -{ - mReentrantMonitor.AssertCurrentThreadIn(); - -#ifdef DEBUG - nsRefPtr<nsDOMWorker>& debugWorker = aRunnable->mWorker; - - nsRefPtr<nsDOMWorkerRunnable> runnable; - NS_ASSERTION(mWorkersInProgress.Get(debugWorker, getter_AddRefs(runnable)) && - runnable == aRunnable, - "Removing a worker that isn't in our hashtable?!"); -#endif - - mWorkersInProgress.Remove(aRunnable->mWorker); -} - -PRBool -nsDOMThreadService::QueueSuspendedWorker(nsDOMWorkerRunnable* aRunnable) -{ - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - -#ifdef DEBUG - { - // Make sure that the runnable is in mWorkersInProgress. - nsRefPtr<nsDOMWorkerRunnable> current; - mWorkersInProgress.Get(aRunnable->mWorker, getter_AddRefs(current)); - NS_ASSERTION(current == aRunnable, "Something crazy wrong here!"); - } -#endif - - return mSuspendedWorkers.AppendElement(aRunnable) ? PR_TRUE : PR_FALSE; -} - -/* static */ -JSContext* -nsDOMThreadService::CreateJSContext() -{ - JSRuntime* rt; - gJSRuntimeService->GetRuntime(&rt); - NS_ENSURE_TRUE(rt, nsnull); - - JSAutoContextDestroyer cx(JS_NewContext(rt, 8192)); - NS_ENSURE_TRUE(cx, nsnull); - - JS_SetErrorReporter(cx, DOMWorkerErrorReporter); - - JS_SetOperationCallback(cx, DOMWorkerOperationCallback); - - static JSSecurityCallbacks securityCallbacks = { - nsDOMWorkerSecurityManager::JSCheckAccess, - nsDOMWorkerSecurityManager::JSTranscodePrincipals, - nsDOMWorkerSecurityManager::JSFindPrincipal - }; - JS_SetContextSecurityCallbacks(cx, &securityCallbacks); - - JS_ClearContextDebugHooks(cx); - - nsresult rv = nsContentUtils::XPConnect()-> - SetSecurityManagerForJSContext(cx, gWorkerSecurityManager, 0); - NS_ENSURE_SUCCESS(rv, nsnull); - - JS_SetNativeStackQuota(cx, 256*1024); - - JS_SetOptions(cx, - JS_GetOptions(cx) | JSOPTION_METHODJIT | JSOPTION_JIT | JSOPTION_PROFILING); - JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 1 * 1024 * 1024); - - return cx.forget(); -} - -already_AddRefed<nsDOMWorkerPool> -nsDOMThreadService::GetPoolForGlobal(nsIScriptGlobalObject* aGlobalObject, - PRBool aRemove) -{ - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - nsRefPtr<nsDOMWorkerPool> pool; - mPools.Get(aGlobalObject, getter_AddRefs(pool)); - - if (aRemove) { - mPools.Remove(aGlobalObject); - } - - return pool.forget(); -} - -void -nsDOMThreadService::TriggerOperationCallbackForPool(nsDOMWorkerPool* aPool) -{ - mReentrantMonitor.AssertCurrentThreadIn(); - - // See if we need to trigger the operation callback on any currently running - // contexts. - PRUint32 contextCount = mJSContexts.Length(); - for (PRUint32 index = 0; index < contextCount; index++) { - JSContext*& cx = mJSContexts[index]; - nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(cx); - if (worker && worker->Pool() == aPool) { - JS_TriggerOperationCallback(cx); - } - } -} - -void -nsDOMThreadService::RescheduleSuspendedWorkerForPool(nsDOMWorkerPool* aPool) -{ - mReentrantMonitor.AssertCurrentThreadIn(); - - PRUint32 count = mSuspendedWorkers.Length(); - if (!count) { - // Nothing to do here. - return; - } - - nsTArray<nsDOMWorkerRunnable*> others(count); - - for (PRUint32 index = 0; index < count; index++) { - nsDOMWorkerRunnable* runnable = mSuspendedWorkers[index]; - -#ifdef DEBUG - { - // Make sure that the runnable never left mWorkersInProgress. - nsRefPtr<nsDOMWorkerRunnable> current; - mWorkersInProgress.Get(runnable->mWorker, getter_AddRefs(current)); - NS_ASSERTION(current == runnable, "Something crazy wrong here!"); - } -#endif - - if (runnable->mWorker->Pool() == aPool) { -#ifdef DEBUG - nsresult rv = -#endif - mThreadPool->Dispatch(runnable, NS_DISPATCH_NORMAL); - NS_ASSERTION(NS_SUCCEEDED(rv), "This shouldn't ever fail!"); - } - else { - others.AppendElement(runnable); - } - } - - mSuspendedWorkers.SwapElements(others); -} - -void -nsDOMThreadService::CancelWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject) -{ - nsRefPtr<nsDOMWorkerPool> pool = GetPoolForGlobal(aGlobalObject, PR_TRUE); - if (pool) { - pool->Cancel(); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - TriggerOperationCallbackForPool(pool); - RescheduleSuspendedWorkerForPool(pool); - } -} - -void -nsDOMThreadService::SuspendWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject) -{ - NS_ASSERTION(aGlobalObject, "Null pointer!"); - - nsRefPtr<nsDOMWorkerPool> pool = GetPoolForGlobal(aGlobalObject, PR_FALSE); - if (pool) { - pool->Suspend(); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - TriggerOperationCallbackForPool(pool); - } -} - -void -nsDOMThreadService::ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject) -{ - NS_ASSERTION(aGlobalObject, "Null pointer!"); - - nsRefPtr<nsDOMWorkerPool> pool = GetPoolForGlobal(aGlobalObject, PR_FALSE); - if (pool) { - pool->Resume(); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - TriggerOperationCallbackForPool(pool); - RescheduleSuspendedWorkerForPool(pool); - } -} - -void -nsDOMThreadService::NoteEmptyPool(nsDOMWorkerPool* aPool) -{ - NS_ASSERTION(aPool, "Null pointer!"); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mPools.Remove(aPool->ScriptGlobalObject()); -} - -void -nsDOMThreadService::TimeoutReady(nsDOMWorkerTimeout* aTimeout) -{ - nsRefPtr<nsDOMWorkerTimeoutRunnable> runnable = - new nsDOMWorkerTimeoutRunnable(aTimeout); - NS_ENSURE_TRUE(runnable,); - - Dispatch(aTimeout->GetWorker(), runnable); -} - -nsresult -nsDOMThreadService::ChangeThreadPoolMaxThreads(PRInt16 aDelta) -{ - NS_ENSURE_ARG(aDelta == 1 || aDelta == -1); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - 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); - - // If we're allowing an extra thread then post a dummy event to the thread - // pool so that any pending workers can get started. The thread pool doesn't - // do this on its own like it probably should... - if (aDelta == 1) { - nsCOMPtr<nsIRunnable> dummy(new nsRunnable()); - if (dummy) { - rv = mThreadPool->Dispatch(dummy, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); - } - } - - return NS_OK; -} - -void -nsDOMThreadService::NoteThreadsafeContractId(const nsACString& aContractId, - PRBool aIsThreadsafe) -{ - NS_ASSERTION(!aContractId.IsEmpty(), "Empty contract id!"); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - -#ifdef DEBUG - { - PRBool isThreadsafe; - if (mThreadsafeContractIDs.Get(aContractId, &isThreadsafe)) { - NS_ASSERTION(aIsThreadsafe == isThreadsafe, "Inconsistent threadsafety!"); - } - } -#endif - - if (!mThreadsafeContractIDs.Put(aContractId, aIsThreadsafe)) { - NS_WARNING("Out of memory!"); - } -} - -ThreadsafeStatus -nsDOMThreadService::GetContractIdThreadsafeStatus(const nsACString& aContractId) -{ - NS_ASSERTION(!aContractId.IsEmpty(), "Empty contract id!"); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - PRBool isThreadsafe; - if (mThreadsafeContractIDs.Get(aContractId, &isThreadsafe)) { - return isThreadsafe ? Threadsafe : NotThreadsafe; - } - - return Unknown; -} - -// static -nsIJSRuntimeService* -nsDOMThreadService::JSRuntimeService() -{ - return gJSRuntimeService; -} - -// static -nsIThreadJSContextStack* -nsDOMThreadService::ThreadJSContextStack() -{ - return gThreadJSContextStack; -} - -// static -nsIXPCSecurityManager* -nsDOMThreadService::WorkerSecurityManager() -{ - return gWorkerSecurityManager; -} - -/** - * See nsIEventTarget - */ -NS_IMETHODIMP -nsDOMThreadService::Dispatch(nsIRunnable* aEvent, - PRUint32 aFlags) -{ - NS_ENSURE_ARG_POINTER(aEvent); - NS_ENSURE_FALSE(aFlags & NS_DISPATCH_SYNC, NS_ERROR_NOT_IMPLEMENTED); - - // This should only ever be called by the timer code! We run the event right - // now, but all that does is queue the real event for the proper worker. - aEvent->Run(); - - return NS_OK; -} - -/** - * See nsIEventTarget - */ -NS_IMETHODIMP -nsDOMThreadService::IsOnCurrentThread(PRBool* _retval) -{ - NS_NOTREACHED("No one should call this!"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -/** - * See nsIObserver - */ -NS_IMETHODIMP -nsDOMThreadService::Observe(nsISupports* aSubject, - const char* aTopic, - const PRUnichar* aData) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - Cleanup(); - return NS_OK; - } - - NS_NOTREACHED("Unknown observer topic!"); - return NS_OK; -} - -/** - * See nsIThreadPoolListener - */ -NS_IMETHODIMP -nsDOMThreadService::OnThreadCreated() -{ - LOG(("Thread created")); - - nsIThread* current = NS_GetCurrentThread(); - - // We want our worker threads to always have a lower priority than the main - // thread. NSPR docs say that this isn't incredibly reliable across all - // platforms but we hope for the best. - nsCOMPtr<nsISupportsPriority> priority(do_QueryInterface(current)); - NS_ENSURE_TRUE(priority, NS_ERROR_FAILURE); - - nsresult rv = priority->SetPriority(nsISupportsPriority::PRIORITY_LOWEST); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(gJSContextIndex != BAD_TLS_INDEX, "No context index!"); - - // Set the context up for the worker. - JSContext* cx = (JSContext*)PR_GetThreadPrivate(gJSContextIndex); - if (!cx) { - cx = nsDOMThreadService::CreateJSContext(); - NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE); - - PRStatus status = PR_SetThreadPrivate(gJSContextIndex, cx); - if (status != PR_SUCCESS) { - NS_WARNING("Failed to set context on thread!"); - nsContentUtils::XPConnect()->ReleaseJSContext(cx, PR_TRUE); - return NS_ERROR_FAILURE; - } - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - -#ifdef DEBUG - JSContext** newContext = -#endif - mJSContexts.AppendElement(cx); - - // We ensure the capacity of this array in Init. - NS_ASSERTION(newContext, "Should never fail!"); - } - - // Make sure that XPConnect knows about this context. - gThreadJSContextStack->Push(cx); - gThreadJSContextStack->SetSafeJSContext(cx); - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMThreadService::OnThreadShuttingDown() -{ - LOG(("Thread shutting down")); - - NS_ASSERTION(gJSContextIndex != BAD_TLS_INDEX, "No context index!"); - - JSContext* cx = (JSContext*)PR_GetThreadPrivate(gJSContextIndex); - NS_WARN_IF_FALSE(cx, "Thread died with no context?"); - if (cx) { - { - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mJSContexts.RemoveElement(cx); - } - - JSContext* pushedCx; - gThreadJSContextStack->Pop(&pushedCx); - NS_ASSERTION(pushedCx == cx, "Popped the wrong context!"); - - gThreadJSContextStack->SetSafeJSContext(nsnull); - - // 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) -{ - NS_ASSERTION(aWorker, "Null pointer!"); - - if (aGlobalObject && NS_IsMainThread()) { - nsCOMPtr<nsPIDOMWindow> domWindow(do_QueryInterface(aGlobalObject)); - NS_ENSURE_TRUE(domWindow, NS_ERROR_NO_INTERFACE); - - nsPIDOMWindow* innerWindow = domWindow->IsOuterWindow() ? - domWindow->GetCurrentInnerWindow() : - domWindow.get(); - NS_ENSURE_STATE(innerWindow); - - nsCOMPtr<nsIScriptGlobalObject> newGlobal(do_QueryInterface(innerWindow)); - NS_ENSURE_TRUE(newGlobal, NS_ERROR_NO_INTERFACE); - - aGlobalObject = newGlobal; - } - - nsRefPtr<nsDOMWorkerPool> pool; - { - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - if (!mThreadPool) { - // Shutting down! - return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; - } - - mPools.Get(aGlobalObject, getter_AddRefs(pool)); - } - - nsresult rv; - - if (!pool) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - if (!mNavigatorStringsLoaded) { - rv = NS_GetNavigatorAppName(mAppName); - NS_ENSURE_SUCCESS(rv, rv); - - rv = NS_GetNavigatorAppVersion(mAppVersion); - NS_ENSURE_SUCCESS(rv, rv); - - rv = NS_GetNavigatorPlatform(mPlatform); - NS_ENSURE_SUCCESS(rv, rv); - - rv = NS_GetNavigatorUserAgent(mUserAgent); - NS_ENSURE_SUCCESS(rv, rv); - - mNavigatorStringsLoaded = PR_TRUE; - } - - nsCOMPtr<nsIDocument> document; - if (aGlobalObject) { - nsCOMPtr<nsPIDOMWindow> domWindow(do_QueryInterface(aGlobalObject)); - NS_ENSURE_TRUE(domWindow, NS_ERROR_NO_INTERFACE); - - nsIDOMDocument* domDocument = domWindow->GetExtantDocument(); - NS_ENSURE_STATE(domDocument); - - document = do_QueryInterface(domDocument); - NS_ENSURE_STATE(document); - } - - pool = new nsDOMWorkerPool(aGlobalObject, document); - NS_ENSURE_TRUE(pool, NS_ERROR_OUT_OF_MEMORY); - - rv = pool->Init(); - NS_ENSURE_SUCCESS(rv, rv); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - PRBool success = mPools.Put(aGlobalObject, pool); - NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); - } - - rv = pool->NoteWorker(aWorker); - NS_ENSURE_SUCCESS(rv, rv); - - aWorker->SetPool(pool); - return NS_OK; -} - -void -nsDOMThreadService::GetAppName(nsAString& aAppName) -{ - NS_ASSERTION(mNavigatorStringsLoaded, - "Shouldn't call this before we have loaded strings!"); - aAppName.Assign(mAppName); -} - -void -nsDOMThreadService::GetAppVersion(nsAString& aAppVersion) -{ - NS_ASSERTION(mNavigatorStringsLoaded, - "Shouldn't call this before we have loaded strings!"); - aAppVersion.Assign(mAppVersion); -} - -void -nsDOMThreadService::GetPlatform(nsAString& aPlatform) -{ - NS_ASSERTION(mNavigatorStringsLoaded, - "Shouldn't call this before we have loaded strings!"); - aPlatform.Assign(mPlatform); -} - -void -nsDOMThreadService::GetUserAgent(nsAString& aUserAgent) -{ - NS_ASSERTION(mNavigatorStringsLoaded, - "Shouldn't call this before we have loaded strings!"); - aUserAgent.Assign(mUserAgent); -} - -void -nsDOMThreadService::RegisterPrefCallbacks() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(sPrefsToWatch); index++) { - Preferences::RegisterCallback(PrefCallback, sPrefsToWatch[index]); - PrefCallback(sPrefsToWatch[index], nsnull); - } -} - -void -nsDOMThreadService::UnregisterPrefCallbacks() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(sPrefsToWatch); index++) { - Preferences::UnregisterCallback(PrefCallback, sPrefsToWatch[index]); - } -} - -// static -int -nsDOMThreadService::PrefCallback(const char* aPrefName, - void* aClosure) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - if(!strcmp(aPrefName, "dom.max_script_run_time")) { - // We assume atomic 32bit reads/writes. If this assumption doesn't hold on - // some wacky platform then the worst that could happen is that the close - // handler will run for a slightly different amount of time. - PRUint32 timeoutMS = - Preferences::GetUint(aPrefName, gWorkerCloseHandlerTimeoutMS); - - // We must have a timeout value, 0 is not ok. If the pref is set to 0 then - // fall back to our default. - if (timeoutMS) { - gWorkerCloseHandlerTimeoutMS = timeoutMS; - } - } - return 0; -} - -// static -PRUint32 -nsDOMThreadService::GetWorkerCloseHandlerTimeoutMS() -{ - return gWorkerCloseHandlerTimeoutMS; -}
deleted file mode 100644 --- a/dom/src/threads/nsDOMThreadService.h +++ /dev/null @@ -1,212 +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): - * Vladimir Vukicevic <vladimir@pobox.com> (Original Author) - * Ben Turner <bent.mozilla@gmail.com> - * - * 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 __NSDOMTHREADSERVICE_H__ -#define __NSDOMTHREADSERVICE_H__ - -// Interfaces -#include "nsIEventTarget.h" -#include "nsIObserver.h" -#include "nsIThreadPool.h" - -// Other includes -#include "jsapi.h" -#include "mozilla/ReentrantMonitor.h" -#include "nsAutoPtr.h" -#include "nsCOMPtr.h" -#include "nsDataHashtable.h" -#include "nsRefPtrHashtable.h" -#include "nsStringGlue.h" -#include "nsTPtrArray.h" - -#include "prlog.h" -#ifdef PR_LOGGING -extern PRLogModuleInfo* gDOMThreadsLog; -#endif - -class nsDOMWorker; -class nsDOMWorkerPool; -class nsDOMWorkerRunnable; -class nsDOMWorkerTimeout; -class nsIJSRuntimeService; -class nsIScriptGlobalObject; -class nsIThreadJSContextStack; -class nsIXPConnect; -class nsIXPCSecurityManager; - -enum ThreadsafeStatus -{ - Threadsafe, - NotThreadsafe, - Unknown -}; - -class nsDOMThreadService : public nsIEventTarget, - public nsIObserver, - public nsIThreadPoolListener -{ - friend class nsDOMWorker; - friend class nsDOMWorkerNavigator; - friend class nsDOMWorkerPool; - friend class nsDOMWorkerRunnable; - friend class nsDOMWorkerThread; - friend class nsDOMWorkerTimeout; - friend class nsDOMWorkerXHR; - friend class nsDOMWorkerXHRProxy; - friend class nsLayoutStatics; - friend class nsReportErrorRunnable; - - friend void DOMWorkerErrorReporter(JSContext* aCx, - const char* aMessage, - JSErrorReport* aReport); - -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIEVENTTARGET - NS_DECL_NSIOBSERVER - NS_DECL_NSITHREADPOOLLISTENER - - // Any DOM consumers that need access to this service should use this method. - static already_AddRefed<nsDOMThreadService> GetOrInitService(); - - // Simple getter for this service. This does not create the service if it - // hasn't been created already, and it never AddRef's! - static nsDOMThreadService* get(); - - static JSContext* GetCurrentContext(); - - // Easy access to the services we care about. - static nsIJSRuntimeService* JSRuntimeService(); - static nsIThreadJSContextStack* ThreadJSContextStack(); - static nsIXPCSecurityManager* WorkerSecurityManager(); - - void CancelWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject); - void SuspendWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject); - void ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject); - - nsresult ChangeThreadPoolMaxThreads(PRInt16 aDelta); - - void NoteThreadsafeContractId(const nsACString& aContractId, - PRBool aIsThreadsafe); - - ThreadsafeStatus GetContractIdThreadsafeStatus(const nsACString& aContractId); - -private: - nsDOMThreadService(); - ~nsDOMThreadService(); - - nsresult Init(); - void Cleanup(); - - static void Shutdown(); - - nsresult Dispatch(nsDOMWorker* aWorker, - nsIRunnable* aRunnable, - PRIntervalTime aTimeoutInterval = 0, - PRBool aClearQueue = PR_FALSE); - - void SetWorkerTimeout(nsDOMWorker* aWorker, - PRIntervalTime aTimeoutInterval); - - void WorkerComplete(nsDOMWorkerRunnable* aRunnable); - - static JSContext* CreateJSContext(); - - already_AddRefed<nsDOMWorkerPool> - GetPoolForGlobal(nsIScriptGlobalObject* aGlobalObject, - PRBool aRemove); - - void TriggerOperationCallbackForPool(nsDOMWorkerPool* aPool); - void RescheduleSuspendedWorkerForPool(nsDOMWorkerPool* aPool); - - void NoteEmptyPool(nsDOMWorkerPool* aPool); - - void TimeoutReady(nsDOMWorkerTimeout* aTimeout); - - nsresult RegisterWorker(nsDOMWorker* aWorker, - nsIScriptGlobalObject* aGlobalObject); - - void GetAppName(nsAString& aAppName); - void GetAppVersion(nsAString& aAppVersion); - void GetPlatform(nsAString& aPlatform); - void GetUserAgent(nsAString& aUserAgent); - - void RegisterPrefCallbacks(); - void UnregisterPrefCallbacks(); - - static int PrefCallback(const char* aPrefName, - void* aClosure); - - static PRUint32 GetWorkerCloseHandlerTimeoutMS(); - - PRBool QueueSuspendedWorker(nsDOMWorkerRunnable* aRunnable); - - // Our internal thread pool. - nsCOMPtr<nsIThreadPool> mThreadPool; - - // Maps nsIScriptGlobalObject* to nsDOMWorkerPool. - nsRefPtrHashtable<nsVoidPtrHashKey, nsDOMWorkerPool> mPools; - - // mReentrantMonitor protects all access to mWorkersInProgress and - // mCreationsInProgress. - mozilla::ReentrantMonitor mReentrantMonitor; - - // A map from nsDOMWorkerThread to nsDOMWorkerRunnable. - nsRefPtrHashtable<nsVoidPtrHashKey, nsDOMWorkerRunnable> mWorkersInProgress; - - // A list of active JSContexts that we've created. Always protected with - // mReentrantMonitor. - nsTArray<JSContext*> mJSContexts; - - // A list of worker runnables that were never started because the worker was - // suspended. Always protected with mReentrantMonitor. - nsTArray<nsDOMWorkerRunnable*> mSuspendedWorkers; - - // Always protected with mReentrantMonitor. - nsDataHashtable<nsCStringHashKey, PRBool> mThreadsafeContractIDs; - - nsString mAppName; - nsString mAppVersion; - nsString mPlatform; - nsString mUserAgent; - - PRBool mNavigatorStringsLoaded; -}; - -#endif /* __NSDOMTHREADSERVICE_H__ */
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorker.cpp +++ /dev/null @@ -1,2752 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; 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 Web Workers. - * - * 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 "nsDOMWorker.h" - -#include "nsIDOMEvent.h" -#include "nsIEventTarget.h" -#include "nsIJSRuntimeService.h" -#include "nsIXPConnect.h" - -#include "jscntxt.h" -#ifdef MOZ_SHARK -#include "jsdbgapi.h" -#endif -#include "nsAtomicRefcnt.h" -#include "nsAXPCNativeCallContext.h" -#include "nsContentUtils.h" -#include "nsDOMClassInfo.h" -#include "nsDOMClassInfoID.h" -#include "nsGlobalWindow.h" -#include "nsJSON.h" -#include "nsJSUtils.h" -#include "nsProxyRelease.h" -#include "nsThreadUtils.h" -#include "nsNativeCharsetUtils.h" -#include "xpcprivate.h" - -#include "nsDOMThreadService.h" -#include "nsDOMWorkerEvents.h" -#include "nsDOMWorkerLocation.h" -#include "nsDOMWorkerNavigator.h" -#include "nsDOMWorkerPool.h" -#include "nsDOMWorkerScriptLoader.h" -#include "nsDOMWorkerTimeout.h" -#include "nsDOMWorkerXHR.h" - -using namespace mozilla; - -class TestComponentThreadsafetyRunnable : public nsIRunnable -{ -public: - NS_DECL_ISUPPORTS - - TestComponentThreadsafetyRunnable(const nsACString& aContractId, - PRBool aService) - : mContractId(aContractId), - mService(aService), - mIsThreadsafe(PR_FALSE) - { } - - NS_IMETHOD Run() - { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - nsresult rv; - nsCOMPtr<nsISupports> instance; - if (mService) { - instance = do_GetService(mContractId.get(), &rv); - } - else { - instance = do_CreateInstance(mContractId.get(), &rv); - } - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(instance, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - PRUint32 flags; - rv = classInfo->GetFlags(&flags); - NS_ENSURE_SUCCESS(rv, rv); - - mIsThreadsafe = !!(flags & nsIClassInfo::THREADSAFE); - return NS_OK; - } - - PRBool IsThreadsafe() - { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - return mIsThreadsafe; - } - -private: - nsCString mContractId; - PRBool mService; - PRBool mIsThreadsafe; -}; - -NS_IMPL_THREADSAFE_ISUPPORTS1(TestComponentThreadsafetyRunnable, nsIRunnable) - -class nsDOMWorkerFunctions -{ -public: - typedef nsDOMWorker::WorkerPrivilegeModel WorkerPrivilegeModel; - - // Same as window.dump(). - static JSBool - Dump(JSContext* aCx, uintN aArgc, jsval* aVp); - - // Same as window.setTimeout(). - static JSBool - SetTimeout(JSContext* aCx, uintN aArgc, jsval* aVp) { - return MakeTimeout(aCx, aArgc, aVp, PR_FALSE); - } - - // Same as window.setInterval(). - static JSBool - SetInterval(JSContext* aCx, uintN aArgc, jsval* aVp) { - return MakeTimeout(aCx, aArgc, aVp, PR_TRUE); - } - - // Used for both clearTimeout() and clearInterval(). - static JSBool - KillTimeout(JSContext* aCx, uintN aArgc, jsval* aVp); - - static JSBool - LoadScripts(JSContext* aCx, uintN aArgc, jsval* aVp); - - static JSBool - NewXMLHttpRequest(JSContext* aCx, uintN aArgc, jsval* aVp); - - static JSBool - NewWorker(JSContext* aCx, uintN aArgc, jsval* aVp) { - return MakeNewWorker(aCx, aArgc, aVp, nsDOMWorker::CONTENT); - } - - static JSBool - AtoB(JSContext* aCx, uintN aArgc, jsval* aVp); - - static JSBool - BtoA(JSContext* aCx, uintN aArgc, jsval* aVp); - - // Chrome-only functions - static JSBool - NewChromeWorker(JSContext* aCx, uintN aArgc, jsval* aVp); - - static JSBool - XPCOMLazyGetter(JSContext* aCx, JSObject* aObj, jsid aId, jsval* aVp); - - static JSBool - CreateInstance(JSContext* aCx, uintN aArgc, jsval* aVp) { - return GetInstanceCommon(aCx, aArgc, aVp, PR_FALSE); - } - - static JSBool - GetService(JSContext* aCx, uintN aArgc, jsval* aVp) { - return GetInstanceCommon(aCx, aArgc, aVp, PR_TRUE); - } - -#ifdef BUILD_CTYPES - static JSBool - CTypesLazyGetter(JSContext* aCx, JSObject* aObj, jsid aId, jsval* aVp); -#endif - -private: - // Internal helper for SetTimeout and SetInterval. - static JSBool - MakeTimeout(JSContext* aCx, uintN aArgc, jsval* aVp, PRBool aIsInterval); - - static JSBool - MakeNewWorker(JSContext* aCx, uintN aArgc, jsval* aVp, - WorkerPrivilegeModel aPrivilegeModel); - - static JSBool - GetInstanceCommon(JSContext* aCx, uintN aArgc, jsval* aVp, PRBool aService); -}; - -JSFunctionSpec gDOMWorkerXPCOMFunctions[] = { - {"createInstance", nsDOMWorkerFunctions::CreateInstance, 1, JSPROP_ENUMERATE}, - {"getService", nsDOMWorkerFunctions::GetService, 1, JSPROP_ENUMERATE}, - { nsnull, nsnull, 0, 0 } -}; - -JSBool -nsDOMWorkerFunctions::Dump(JSContext* aCx, - uintN aArgc, - jsval* aVp) -{ - JS_SET_RVAL(cx, aVp, JSVAL_VOID); - if (!nsGlobalWindow::DOMWindowDumpEnabled()) { - return JS_TRUE; - } - - JSString* str; - if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) { - nsDependentJSString depStr; - if (depStr.init(aCx, str)) { - fputs(NS_ConvertUTF16toUTF8(depStr).get(), stderr); - fflush(stderr); - } - } - return JS_TRUE; -} - -JSBool -nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx, - uintN aArgc, - jsval* aVp, - PRBool aIsInterval) -{ - nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); - NS_ASSERTION(worker, "This should be set by the DOM thread service!"); - - if (worker->IsCanceled()) { - return JS_FALSE; - } - - PRUint32 id = worker->NextTimeoutId(); - - if (worker->IsClosing()) { - // Timeouts won't run in the close handler, fake success and bail. - JS_SET_RVAL(aCx, aVp, INT_TO_JSVAL(id)); - return JS_TRUE; - } - - nsRefPtr<nsDOMWorkerTimeout> timeout = new nsDOMWorkerTimeout(worker, id); - if (!timeout) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - nsresult rv = timeout->Init(aCx, aArgc, JS_ARGV(aCx, aVp), aIsInterval); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to initialize timeout!"); - return JS_FALSE; - } - - rv = worker->AddFeature(timeout, aCx); - if (NS_FAILED(rv)) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - rv = timeout->Start(); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to start timeout!"); - return JS_FALSE; - } - - JS_SET_RVAL(aCx, aVp, INT_TO_JSVAL(id)); - return JS_TRUE; -} - -JSBool -nsDOMWorkerFunctions::KillTimeout(JSContext* aCx, - uintN aArgc, - jsval* aVp) -{ - nsDOMWorker* worker = static_cast<nsDOMWorker*>(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 requires at least 1 parameter"); - return JS_FALSE; - } - - uint32 id; - if (!JS_ValueToECMAUint32(aCx, JS_ARGV(aCx, aVp)[0], &id)) { - JS_ReportError(aCx, "First argument must be a timeout id"); - return JS_FALSE; - } - - worker->CancelTimeoutWithId(PRUint32(id)); - JS_SET_RVAL(aCx, aVp, JSVAL_VOID); - return JS_TRUE; -} - -JSBool -nsDOMWorkerFunctions::LoadScripts(JSContext* aCx, - uintN aArgc, - jsval* aVp) -{ - nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); - NS_ASSERTION(worker, "This should be set by the DOM thread service!"); - - if (worker->IsCanceled()) { - return JS_FALSE; - } - - if (!aArgc) { - // No argument is ok according to spec. - return JS_TRUE; - } - - nsAutoTArray<nsString, 10> urls; - - if (!urls.SetCapacity((PRUint32)aArgc)) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - jsval* argv = JS_ARGV(aCx, aVp); - for (uintN index = 0; index < aArgc; index++) { - jsval val = argv[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!"); - - nsDependentJSString depStr; - if (!depStr.init(aCx, str)) { - return JS_FALSE; - } - - newURL->Assign(depStr); - } - - nsRefPtr<nsDOMWorkerScriptLoader> loader = - new nsDOMWorkerScriptLoader(worker); - if (!loader) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - nsresult rv = worker->AddFeature(loader, aCx); - if (NS_FAILED(rv)) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - rv = loader->LoadScripts(aCx, urls, PR_TRUE); - if (NS_FAILED(rv)) { - if (!JS_IsExceptionPending(aCx)) { - JS_ReportError(aCx, "Failed to load scripts"); - } - return JS_FALSE; - } - - JS_SET_RVAL(aCx, aVp, JSVAL_VOID); - return JS_TRUE; -} - -JSBool -nsDOMWorkerFunctions::NewXMLHttpRequest(JSContext* aCx, - uintN aArgc, - jsval* aVp) -{ - nsDOMWorker* worker = static_cast<nsDOMWorker*>(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, "XMLHttpRequest constructor takes no arguments!"); - return JS_FALSE; - } - - nsRefPtr<nsDOMWorkerXHR> xhr = new nsDOMWorkerXHR(worker); - if (!xhr) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - nsresult rv = xhr->Init(); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to construct XMLHttpRequest!"); - return JS_FALSE; - } - - rv = worker->AddFeature(xhr, aCx); - if (NS_FAILED(rv)) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - nsCOMPtr<nsIXPConnectJSObjectHolder> xhrWrapped; - jsval v; - rv = nsContentUtils::WrapNative(aCx, JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp)), - static_cast<nsIXMLHttpRequest*>(xhr), &v, - getter_AddRefs(xhrWrapped)); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to wrap XMLHttpRequest!"); - return JS_FALSE; - } - - JS_SET_RVAL(aCs, aVp, v); - return JS_TRUE; -} - -JSBool -nsDOMWorkerFunctions::AtoB(JSContext* aCx, - uintN aArgc, - jsval* aVp) -{ - nsDOMWorker* worker = static_cast<nsDOMWorker*>(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 requires at least 1 parameter"); - return JS_FALSE; - } - - return nsXPConnect::Base64Decode(aCx, JS_ARGV(aCx, aVp)[0], - &JS_RVAL(aCx, aVp)); -} - -JSBool -nsDOMWorkerFunctions::BtoA(JSContext* aCx, - uintN aArgc, - jsval* aVp) -{ - nsDOMWorker* worker = static_cast<nsDOMWorker*>(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 requires at least 1 parameter"); - return JS_FALSE; - } - - return nsXPConnect::Base64Encode(aCx, JS_ARGV(aCx, aVp)[0], - &JS_RVAL(aCx, aVp)); -} - -JSBool -nsDOMWorkerFunctions::NewChromeWorker(JSContext* aCx, - uintN aArgc, - jsval* aVp) -{ - nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); - NS_ASSERTION(worker, "This should be set by the DOM thread service!"); - - if (!worker->IsPrivileged()) { - JS_ReportError(aCx, "Cannot create a priviliged worker!"); - return JS_FALSE; - } - - return MakeNewWorker(aCx, aArgc, aVp, nsDOMWorker::CHROME); -} - -JSBool -nsDOMWorkerFunctions::XPCOMLazyGetter(JSContext* aCx, - JSObject* aObj, - jsid aId, - jsval* aVp) -{ -#ifdef DEBUG - { - NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!"); - NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!"); - NS_ASSERTION(nsDependentJSString(aId).EqualsLiteral("XPCOM"), "Bad id!"); - } -#endif - nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); - NS_ASSERTION(worker, "This should be set by the DOM thread service!"); - - if (worker->IsCanceled()) { - return JS_FALSE; - } - - PRUint16 dummy; - nsCOMPtr<nsIXPCSecurityManager> secMan; - nsContentUtils::XPConnect()-> - GetSecurityManagerForJSContext(aCx, getter_AddRefs(secMan), &dummy); - if (!secMan) { - JS_ReportError(aCx, "Could not get security manager!"); - return JS_FALSE; - } - - nsCID dummyCID; - if (NS_FAILED(secMan->CanGetService(aCx, dummyCID))) { - JS_ReportError(aCx, "Access to the XPCOM object is denied!"); - return JS_FALSE; - } - - JSObject* xpcom = JS_NewObject(aCx, nsnull, nsnull, nsnull); - NS_ENSURE_TRUE(xpcom, JS_FALSE); - - JSBool ok = JS_DefineFunctions(aCx, xpcom, gDOMWorkerXPCOMFunctions); - NS_ENSURE_TRUE(ok, JS_FALSE); - - ok = JS_DeletePropertyById(aCx, aObj, aId); - NS_ENSURE_TRUE(ok, JS_FALSE); - - jsval xpcomVal = OBJECT_TO_JSVAL(xpcom); - ok = JS_SetPropertyById(aCx, aObj, aId, &xpcomVal); - NS_ENSURE_TRUE(ok, JS_FALSE); - - JS_SET_RVAL(aCx, aVp, xpcomVal); - return JS_TRUE; -} - -JSBool -nsDOMWorkerFunctions::GetInstanceCommon(JSContext* aCx, - uintN aArgc, - jsval* aVp, - PRBool aService) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - nsDOMWorker* worker = static_cast<nsDOMWorker*>(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 requires at least 1 parameter"); - return JS_FALSE; - } - - JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]); - if (!str) { - NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!"); - return JS_FALSE; - } - - JSAutoByteString strBytes(aCx, str); - if (!strBytes) { - NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!"); - return JS_FALSE; - } - - nsDependentCString contractId(strBytes.ptr(), JS_GetStringLength(str)); - - nsDOMThreadService* threadService = nsDOMThreadService::get(); - - ThreadsafeStatus status = - threadService->GetContractIdThreadsafeStatus(contractId); - - if (status == Unknown) { - nsCOMPtr<nsIThread> mainThread; - nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread)); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to get main thread!"); - return JS_FALSE; - } - - nsRefPtr<TestComponentThreadsafetyRunnable> runnable = - new TestComponentThreadsafetyRunnable(contractId, aService); - - rv = mainThread->Dispatch(runnable, NS_DISPATCH_SYNC); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to check threadsafety!"); - return JS_FALSE; - } - - // The worker may have been canceled while waiting above. Check again. - if (worker->IsCanceled()) { - return JS_FALSE; - } - - if (runnable->IsThreadsafe()) { - threadService->NoteThreadsafeContractId(contractId, PR_TRUE); - status = Threadsafe; - } - else { - threadService->NoteThreadsafeContractId(contractId, PR_FALSE); - status = NotThreadsafe; - } - } - - if (status == NotThreadsafe) { - JS_ReportError(aCx, "ChromeWorker may not create an XPCOM object that is " - "not threadsafe!"); - return JS_FALSE; - } - - nsCOMPtr<nsISupports> instance; - if (aService) { - instance = do_GetService(contractId.get()); - if (!instance) { - JS_ReportError(aCx, "Could not get the service!"); - return JS_FALSE; - } - } - else { - instance = do_CreateInstance(contractId.get()); - if (!instance) { - JS_ReportError(aCx, "Could not create the instance!"); - return JS_FALSE; - } - } - - JSObject* global = JS_GetGlobalForObject(aCx, JS_GetScopeChain(aCx)); - if (!global) { - NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!"); - return JS_FALSE; - } - - jsval val; - nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper; - if (NS_FAILED(nsContentUtils::WrapNative(aCx, global, instance, &val, - getter_AddRefs(wrapper)))) { - JS_ReportError(aCx, "Failed to wrap object!"); - return JS_FALSE; - } - - JS_SET_RVAL(aCx, aVp, val); - return JS_TRUE; -} - -JSBool -nsDOMWorkerFunctions::MakeNewWorker(JSContext* aCx, - uintN aArgc, - jsval* aVp, - WorkerPrivilegeModel aPrivilegeModel) -{ - JSObject *obj = JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp)); - - nsDOMWorker* worker = static_cast<nsDOMWorker*>(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, "Worker constructor must have an argument!"); - return JS_FALSE; - } - - // This pointer is protected by our pool, but it is *not* threadsafe and must - // not be used in any way other than to pass it along to the Initialize call. - nsIScriptGlobalObject* owner = worker->Pool()->ScriptGlobalObject(); - - nsCOMPtr<nsIXPConnectWrappedNative> wrappedWorker = - worker->GetWrappedNative(); - if (!wrappedWorker) { - JS_ReportError(aCx, "Couldn't get wrapped native of worker!"); - return JS_FALSE; - } - - nsRefPtr<nsDOMWorker> newWorker = - new nsDOMWorker(worker, wrappedWorker, aPrivilegeModel); - if (!newWorker) { - JS_ReportOutOfMemory(aCx); - return JS_FALSE; - } - - nsresult rv = newWorker->InitializeInternal(owner, aCx, obj, aArgc, - JS_ARGV(aCx, aVp)); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Couldn't initialize new worker!"); - return JS_FALSE; - } - - nsCOMPtr<nsIXPConnectJSObjectHolder> workerWrapped; - jsval v; - rv = nsContentUtils::WrapNative(aCx, obj, static_cast<nsIWorker*>(newWorker), &v, - getter_AddRefs(workerWrapped)); - if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to wrap new worker!"); - return JS_FALSE; - } - - JS_SET_RVAL(aCx, aVp, v); - return JS_TRUE; -} - -#ifdef BUILD_CTYPES -static char* -UnicodeToNative(JSContext *cx, const jschar *source, size_t slen) -{ - nsCAutoString native; - nsDependentString unicode(reinterpret_cast<const PRUnichar*>(source), slen); - nsresult rv = NS_CopyUnicodeToNative(unicode, native); - if (NS_FAILED(rv)) { - JS_ReportError(cx, "could not convert string to native charset"); - return NULL; - } - - char* result = static_cast<char*>(JS_malloc(cx, native.Length() + 1)); - if (!result) - return NULL; - - memcpy(result, native.get(), native.Length() + 1); - return result; -} - -static JSCTypesCallbacks sCallbacks = { - UnicodeToNative -}; - -JSBool -nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx, - JSObject* aObj, - jsid aId, - jsval* aVp) -{ -#ifdef DEBUG - { - NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!"); - NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!"); - NS_ASSERTION(nsDependentJSString(aId).EqualsLiteral("ctypes"), "Bad id!"); - } -#endif - nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx)); - NS_ASSERTION(worker, "This should be set by the DOM thread service!"); - NS_ASSERTION(worker->IsPrivileged(), "This shouldn't be possible!"); - - if (worker->IsCanceled()) { - return JS_FALSE; - } - - jsval ctypes; - return JS_DeletePropertyById(aCx, aObj, aId) && - JS_InitCTypesClass(aCx, aObj) && - JS_GetProperty(aCx, aObj, "ctypes", &ctypes) && - JS_SetCTypesCallbacks(aCx, JSVAL_TO_OBJECT(ctypes), &sCallbacks) && - JS_GetPropertyById(aCx, aObj, aId, aVp); -} -#endif -JSFunctionSpec gDOMWorkerFunctions[] = { - { "dump", nsDOMWorkerFunctions::Dump, 1, 0 }, - { "setTimeout", nsDOMWorkerFunctions::SetTimeout, 1, 0 }, - { "clearTimeout", nsDOMWorkerFunctions::KillTimeout, 1, 0 }, - { "setInterval", nsDOMWorkerFunctions::SetInterval, 1, 0 }, - { "clearInterval", nsDOMWorkerFunctions::KillTimeout, 1, 0 }, - { "importScripts", nsDOMWorkerFunctions::LoadScripts, 1, 0 }, - { "XMLHttpRequest", nsDOMWorkerFunctions::NewXMLHttpRequest, 0, JSFUN_CONSTRUCTOR }, - { "Worker", nsDOMWorkerFunctions::NewWorker, 1, JSFUN_CONSTRUCTOR }, - { "atob", nsDOMWorkerFunctions::AtoB, 1, 0 }, - { "btoa", nsDOMWorkerFunctions::BtoA, 1, 0 }, - { nsnull, nsnull, 0, 0 } -}; -JSFunctionSpec gDOMWorkerChromeFunctions[] = { - { "ChromeWorker", nsDOMWorkerFunctions::NewChromeWorker, 1, JSFUN_CONSTRUCTOR }, - { nsnull, nsnull, 0, 0 } -}; -enum DOMWorkerStructuredDataType -{ - // We have a special tag for XPCWrappedNatives that are being passed between - // threads. This will not work across processes and cannot be persisted. Only - // for ChromeWorker use at present. - DOMWORKER_SCTAG_WRAPPEDNATIVE = JS_SCTAG_USER_MIN + 0x1000, - - DOMWORKER_SCTAG_END -}; - -PR_STATIC_ASSERT(DOMWORKER_SCTAG_END <= JS_SCTAG_USER_MAX); - -// static -JSBool -WriteStructuredClone(JSContext* aCx, - JSStructuredCloneWriter* aWriter, - JSObject* aObj, - void* aClosure) -{ - NS_ASSERTION(aClosure, "Null pointer!"); - - // We'll stash any nsISupports pointers that need to be AddRef'd here. - nsTArray<nsCOMPtr<nsISupports> >* wrappedNatives = - static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure); - - // See if this is a wrapped native. - nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative; - nsContentUtils::XPConnect()-> - GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative)); - if (wrappedNative) { - // Get the raw nsISupports out of it. - nsISupports* wrappedObject = wrappedNative->Native(); - NS_ASSERTION(wrappedObject, "Null pointer?!"); - - // See if this nsISupports is threadsafe. - nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(wrappedObject); - if (classInfo) { - PRUint32 flags; - if (NS_SUCCEEDED(classInfo->GetFlags(&flags)) && - (flags & nsIClassInfo::THREADSAFE)) { - // Write the raw pointer into the stream, and add it to the list we're - // building. - return JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_WRAPPEDNATIVE, 0) && - JS_WriteBytes(aWriter, &wrappedObject, sizeof(wrappedObject)) && - wrappedNatives->AppendElement(wrappedObject); - } - } - } - - // Something failed above, try using the runtime callbacks instead. - const JSStructuredCloneCallbacks* runtimeCallbacks = - aCx->runtime->structuredCloneCallbacks; - if (runtimeCallbacks) { - return runtimeCallbacks->write(aCx, aWriter, aObj, nsnull); - } - - // We can't handle this object, throw an exception if one hasn't been thrown - // already. - if (!JS_IsExceptionPending(aCx)) { - nsDOMClassInfo::ThrowJSException(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); - } - return JS_FALSE; -} - -nsDOMWorkerScope::nsDOMWorkerScope(nsDOMWorker* aWorker) -: mWorker(aWorker), - mWrappedNative(nsnull), - mHasOnerror(PR_FALSE) -{ - NS_ASSERTION(aWorker, "Null pointer!"); -} - -NS_IMPL_ISUPPORTS_INHERITED3(nsDOMWorkerScope, nsDOMWorkerMessageHandler, - nsIWorkerScope, - nsIWorkerGlobalScope, - nsIXPCScriptable) - -NS_IMPL_CI_INTERFACE_GETTER4(nsDOMWorkerScope, nsIWorkerScope, - nsIWorkerGlobalScope, - nsIDOMEventTarget, - nsIXPCScriptable) - -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerScope) -NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerScope) - -// Need to return a scriptable helper so that XPConnect can get our -// nsIXPCScriptable flags properly (to not enumerate QI, for instance). -NS_IMETHODIMP -nsDOMWorkerScope::GetHelperForLanguage(PRUint32 aLanguage, - nsISupports** _retval) -{ - if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) { - NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(nsIWorkerScope*, this)); - } - else { - *_retval = nsnull; - } - return NS_OK; -} - -// Use the xpc_map_end.h macros to generate the nsIXPCScriptable methods we want -// for the scope. - -#define XPC_MAP_CLASSNAME nsDOMWorkerScope -#define XPC_MAP_QUOTED_CLASSNAME "DedicatedWorkerGlobalScope" -#define XPC_MAP_WANT_POSTCREATE -#define XPC_MAP_WANT_TRACE -#define XPC_MAP_WANT_FINALIZE - -#define XPC_MAP_FLAGS \ - nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \ - nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \ - nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \ - nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES | \ - nsIXPCScriptable::WANT_ADDPROPERTY - -#define XPC_MAP_WANT_ADDPROPERTY - -#include "xpc_map_end.h" - -NS_IMETHODIMP -nsDOMWorkerScope::PostCreate(nsIXPConnectWrappedNative* aWrapper, - JSContext* /* aCx */, - JSObject* /* aObj */) -{ - NS_ASSERTION(!mWrappedNative, "Already got a wrapper?!"); - mWrappedNative = aWrapper; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::Trace(nsIXPConnectWrappedNative* /* aWrapper */, - JSTracer* aTracer, - JSObject* /*aObj */) -{ - nsDOMWorkerMessageHandler::Trace(aTracer); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::Finalize(nsIXPConnectWrappedNative* /* aWrapper */, - JSContext* /* aCx */, - JSObject* /* aObj */) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - ClearAllListeners(); - mWrappedNative = nsnull; - return NS_OK; -} - -already_AddRefed<nsIXPConnectWrappedNative> -nsDOMWorkerScope::GetWrappedNative() -{ - nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative = mWrappedNative; - NS_ASSERTION(wrappedNative, "Null wrapped native!"); - return wrappedNative.forget(); -} - -NS_IMETHODIMP -nsDOMWorkerScope::AddProperty(nsIXPConnectWrappedNative* aWrapper, - JSContext* aCx, - JSObject* aObj, - jsid aId, - jsval* aVp, - PRBool* _retval) -{ - // We're not going to be setting any exceptions manually so set _retval to - // true in the beginning. - *_retval = PR_TRUE; - - // Bail out now if any of our prerequisites are not met. We only care about - // someone making an 'onmessage' or 'onerror' function so aId must be a - // string and aVp must be a function. - JSObject* funObj; - if (!(JSID_IS_STRING(aId) && - JSVAL_IS_OBJECT(*aVp) && - (funObj = JSVAL_TO_OBJECT(*aVp)) && - JS_ObjectIsFunction(aCx, funObj))) { - return NS_OK; - } - - JSFlatString *str = JSID_TO_FLAT_STRING(aId); - - // Figure out which listener we're setting. - SetListenerFunc func; - if (JS_FlatStringEqualsAscii(str, "onmessage")) { - func = &nsDOMWorkerScope::SetOnmessage; - } - else if (JS_FlatStringEqualsAscii(str, "onerror")) { - func = &nsDOMWorkerScope::SetOnerror; - } - else { - // Some other function, we don't need to do anything special after all. - return NS_OK; - } - - // Wrap the function as an nsIDOMEventListener. - nsCOMPtr<nsIDOMEventListener> listener; - nsresult rv = - nsContentUtils::XPConnect()->WrapJS(aCx, funObj, - NS_GET_IID(nsIDOMEventListener), - getter_AddRefs(listener)); - NS_ENSURE_SUCCESS(rv, rv); - - // And pass the listener to the appropriate setter. - rv = (this->*func)(listener); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::GetSelf(nsIWorkerGlobalScope** aSelf) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - NS_ENSURE_ARG_POINTER(aSelf); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - NS_ADDREF(*aSelf = this); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::GetNavigator(nsIWorkerNavigator** _retval) -{ - if (!mNavigator) { - mNavigator = new nsDOMWorkerNavigator(); - NS_ENSURE_TRUE(mNavigator, NS_ERROR_OUT_OF_MEMORY); - } - - NS_ADDREF(*_retval = mNavigator); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::GetLocation(nsIWorkerLocation** _retval) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - nsCOMPtr<nsIWorkerLocation> location = mWorker->GetLocation(); - NS_ASSERTION(location, "This should never be null!"); - - location.forget(_retval); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::GetOnerror(nsIDOMEventListener** aOnerror) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - NS_ENSURE_ARG_POINTER(aOnerror); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - if (!mHasOnerror) { - // Spec says we have to return 'undefined' until something is set here. - nsIXPConnect* xpc = nsContentUtils::XPConnect(); - NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED); - - nsAXPCNativeCallContext* cc; - nsresult rv = xpc->GetCurrentNativeCallContext(&cc); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(cc, NS_ERROR_UNEXPECTED); - - jsval* retval; - rv = cc->GetRetValPtr(&retval); - NS_ENSURE_SUCCESS(rv, rv); - - *retval = JSVAL_VOID; - return cc->SetReturnValueWasSet(PR_TRUE); - } - - nsCOMPtr<nsIDOMEventListener> listener = - GetOnXListener(NS_LITERAL_STRING("error")); - listener.forget(aOnerror); - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::SetOnerror(nsIDOMEventListener* aOnerror) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - mHasOnerror = PR_TRUE; - - return SetOnXListener(NS_LITERAL_STRING("error"), aOnerror); -} - -NS_IMETHODIMP -nsDOMWorkerScope::PostMessage(/* JSObject aMessage */) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - return mWorker->PostMessageInternal(PR_FALSE); -} - -NS_IMETHODIMP -nsDOMWorkerScope::Close() -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - return mWorker->Close(); -} - -NS_IMETHODIMP -nsDOMWorkerScope::GetOnmessage(nsIDOMEventListener** aOnmessage) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - NS_ENSURE_ARG_POINTER(aOnmessage); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - nsCOMPtr<nsIDOMEventListener> listener = - GetOnXListener(NS_LITERAL_STRING("message")); - listener.forget(aOnmessage); - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::SetOnmessage(nsIDOMEventListener* aOnmessage) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - return SetOnXListener(NS_LITERAL_STRING("message"), aOnmessage); -} - -NS_IMETHODIMP -nsDOMWorkerScope::GetOnclose(nsIDOMEventListener** aOnclose) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - NS_ENSURE_ARG_POINTER(aOnclose); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - nsCOMPtr<nsIDOMEventListener> listener = - GetOnXListener(NS_LITERAL_STRING("close")); - listener.forget(aOnclose); - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::SetOnclose(nsIDOMEventListener* aOnclose) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - nsresult rv = SetOnXListener(NS_LITERAL_STRING("close"), aOnclose); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerScope::RemoveEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - return nsDOMWorkerMessageHandler::RemoveEventListener(aType, aListener, - aUseCapture); -} - -NS_IMETHODIMP -nsDOMWorkerScope::DispatchEvent(nsIDOMEvent* aEvent, - PRBool* _retval) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - return nsDOMWorkerMessageHandler::DispatchEvent(aEvent, _retval); -} - -NS_IMETHODIMP -nsDOMWorkerScope::AddEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture, - PRBool aWantsUntrusted, - PRUint8 optional_argc) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (mWorker->IsCanceled()) { - return NS_ERROR_ABORT; - } - - return nsDOMWorkerMessageHandler::AddEventListener(aType, aListener, - aUseCapture, - aWantsUntrusted, - optional_argc); -} - -class nsWorkerHoldingRunnable : public nsIRunnable -{ -public: - NS_DECL_ISUPPORTS - - nsWorkerHoldingRunnable(nsDOMWorker* aWorker) - : mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()) { } - - NS_IMETHOD Run() { - return NS_OK; - } - - void ReplaceWrappedNative(nsIXPConnectWrappedNative* aWrappedNative) { - mWorkerWN = aWrappedNative; - } - -protected: - virtual ~nsWorkerHoldingRunnable() { } - - nsRefPtr<nsDOMWorker> mWorker; - -private: - nsCOMPtr<nsIXPConnectWrappedNative> mWorkerWN; -}; - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsWorkerHoldingRunnable, nsIRunnable) - -class nsDOMFireEventRunnable : public nsWorkerHoldingRunnable -{ -public: - NS_DECL_ISUPPORTS_INHERITED - - nsDOMFireEventRunnable(nsDOMWorker* aWorker, - nsDOMWorkerEvent* aEvent, - PRBool aToInner) - : nsWorkerHoldingRunnable(aWorker), mEvent(aEvent), mToInner(aToInner) - { - NS_ASSERTION(aWorker && aEvent, "Null pointer!"); - } - - NS_IMETHOD Run() { -#ifdef DEBUG - if (NS_IsMainThread()) { - NS_ASSERTION(!mToInner, "Should only run outer events on main thread!"); - NS_ASSERTION(!mWorker->mParent, "Worker shouldn't have a parent!"); - } - else { - JSContext* cx = nsDOMThreadService::GetCurrentContext(); - nsDOMWorker* currentWorker = (nsDOMWorker*)JS_GetContextPrivate(cx); - NS_ASSERTION(currentWorker, "Must have a worker here!"); - - nsDOMWorker* targetWorker = mToInner ? mWorker.get() : mWorker->mParent; - NS_ASSERTION(currentWorker == targetWorker, "Wrong worker!"); - } -#endif - if (mWorker->IsCanceled()) { - 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); - - NS_ASSERTION(target, "Null target!"); - NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); - - mEvent->SetTarget(target); - return target->DispatchEvent(mEvent, nsnull); - } - -protected: - nsRefPtr<nsDOMWorkerEvent> mEvent; - PRBool mToInner; -}; - -NS_IMPL_ISUPPORTS_INHERITED0(nsDOMFireEventRunnable, nsWorkerHoldingRunnable) - -// Standard NS_IMPL_THREADSAFE_ADDREF without the logging stuff (since this -// class is made to be inherited anyway). -NS_IMETHODIMP_(nsrefcnt) -nsDOMWorkerFeature::AddRef() -{ - NS_ASSERTION(mRefCnt >= 0, "Illegal refcnt!"); - return NS_AtomicIncrementRefcnt(mRefCnt); -} - -// Custom NS_IMPL_THREADSAFE_RELEASE. Checks the mFreeToDie flag before calling -// delete. If the flag is false then the feature still lives in the worker's -// list and must be removed. We rely on the fact that the RemoveFeature method -// calls AddRef and Release after setting the mFreeToDie flag so we won't leak. -NS_IMETHODIMP_(nsrefcnt) -nsDOMWorkerFeature::Release() -{ - NS_ASSERTION(mRefCnt, "Double release!"); - nsrefcnt count = NS_AtomicDecrementRefcnt(mRefCnt); - if (count == 0) { - if (mFreeToDie) { - mRefCnt = 1; - delete this; - } - else { - mWorker->RemoveFeature(this, nsnull); - } - } - return count; -} - -NS_IMPL_QUERY_INTERFACE0(nsDOMWorkerFeature) - -nsDOMWorker::nsDOMWorker(nsDOMWorker* aParent, - nsIXPConnectWrappedNative* aParentWN, - WorkerPrivilegeModel aPrivilegeModel) -: mParent(aParent), - mParentWN(aParentWN), - mPrivilegeModel(aPrivilegeModel), - mLock("nsDOMWorker.mLock"), - mInnerScope(nsnull), - mGlobal(NULL), - mNextTimeoutId(0), - mFeatureSuspendDepth(0), - mWrappedNative(nsnull), - mErrorHandlerRecursionCount(0), - mStatus(eRunning), - mExpirationTime(0), - mSuspended(PR_FALSE), - mCompileAttempted(PR_FALSE) -{ -#ifdef DEBUG - PRBool mainThread = NS_IsMainThread(); - NS_ASSERTION(aParent ? !mainThread : mainThread, "Wrong thread!"); -#endif -} - -nsDOMWorker::~nsDOMWorker() -{ - if (mPool) { - mPool->NoteDyingWorker(this); - } - - NS_ASSERTION(!mFeatures.Length(), "Live features!"); - NS_ASSERTION(!mQueuedRunnables.Length(), "Events that never ran!"); - - nsCOMPtr<nsIThread> mainThread; - NS_GetMainThread(getter_AddRefs(mainThread)); - - nsIPrincipal* principal; - mPrincipal.forget(&principal); - if (principal) { - NS_ProxyRelease(mainThread, principal, PR_FALSE); - } - - nsIURI* uri; - mBaseURI.forget(&uri); - if (uri) { - NS_ProxyRelease(mainThread, uri, PR_FALSE); - } -} - -// static -nsresult -nsDOMWorker::NewWorker(nsISupports** aNewObject) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - nsCOMPtr<nsISupports> newWorker = - NS_ISUPPORTS_CAST(nsIWorker*, new nsDOMWorker(nsnull, nsnull, CONTENT)); - NS_ENSURE_TRUE(newWorker, NS_ERROR_OUT_OF_MEMORY); - - newWorker.forget(aNewObject); - return NS_OK; -} - -// static -nsresult -nsDOMWorker::NewChromeDOMWorker(nsDOMWorker** aNewObject) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - // Subsumes nsContentUtils::IsCallerChrome - nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); - NS_ASSERTION(ssm, "Should never be null!"); - - PRBool enabled; - nsresult rv = ssm->IsCapabilityEnabled("UniversalXPConnect", &enabled); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(enabled, NS_ERROR_DOM_SECURITY_ERR); - - nsRefPtr<nsDOMWorker> newWorker = new nsDOMWorker(nsnull, nsnull, CHROME); - NS_ENSURE_TRUE(newWorker, NS_ERROR_OUT_OF_MEMORY); - - newWorker.forget(aNewObject); - return NS_OK; -} - -// static -nsresult -nsDOMWorker::NewChromeWorker(nsISupports** aNewObject) -{ - nsDOMWorker* newWorker; - nsresult rv = NewChromeDOMWorker(&newWorker); - NS_ENSURE_SUCCESS(rv, rv); - - *aNewObject = NS_ISUPPORTS_CAST(nsIWorker*, newWorker); - return NS_OK; -} - -NS_IMPL_ADDREF_INHERITED(nsDOMWorker, nsDOMWorkerMessageHandler) -NS_IMPL_RELEASE_INHERITED(nsDOMWorker, nsDOMWorkerMessageHandler) - -NS_INTERFACE_MAP_BEGIN(nsDOMWorker) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWorker) - NS_INTERFACE_MAP_ENTRY(nsIClassInfo) - NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) - NS_INTERFACE_MAP_ENTRY(nsIWorker) - NS_INTERFACE_MAP_ENTRY(nsIAbstractWorker) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventTarget, - nsDOMWorkerMessageHandler) - NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer) - NS_INTERFACE_MAP_ENTRY(nsITimerCallback) -NS_INTERFACE_MAP_END - -// Use the xpc_map_end.h macros to generate the nsIXPCScriptable methods we want -// for the worker. - -#define XPC_MAP_CLASSNAME nsDOMWorker -#define XPC_MAP_QUOTED_CLASSNAME "Worker" -#define XPC_MAP_WANT_PRECREATE -#define XPC_MAP_WANT_POSTCREATE -#define XPC_MAP_WANT_TRACE -#define XPC_MAP_WANT_FINALIZE - -#define XPC_MAP_FLAGS \ - nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \ - nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \ - nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \ - nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES - -#include "xpc_map_end.h" - -NS_IMETHODIMP -nsDOMWorker::PreCreate(nsISupports* aObject, - JSContext* aCx, - JSObject* /* aPlannedParent */, - JSObject** aParent) -{ - nsCOMPtr<nsIWorker> iworker(do_QueryInterface(aObject)); - NS_ENSURE_TRUE(iworker, NS_ERROR_UNEXPECTED); - - nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative; - { - MutexAutoLock lock(mLock); - wrappedNative = mWrappedNative; - } - - // Don't allow XPConnect to create multiple WrappedNatives for this object. - if (wrappedNative) { - JSObject* object; - nsresult rv = wrappedNative->GetJSObject(&object); - NS_ENSURE_SUCCESS(rv, rv); - - *aParent = JS_GetParent(aCx, object); - } - - return IsPrivileged() ? NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK; -} - -NS_IMETHODIMP -nsDOMWorker::PostCreate(nsIXPConnectWrappedNative* aWrapper, - JSContext* /* aCx */, - JSObject* /* aObj */) -{ - MutexAutoLock lock(mLock); - mWrappedNative = aWrapper; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorker::Trace(nsIXPConnectWrappedNative* /* aWrapper */, - JSTracer* aTracer, - JSObject* /*aObj */) -{ - PRBool canceled = PR_FALSE; - { - MutexAutoLock lock(mLock); - canceled = mStatus == eKilled; - } - - if (!canceled) { - nsDOMWorkerMessageHandler::Trace(aTracer); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorker::Finalize(nsIXPConnectWrappedNative* /* aWrapper */, - JSContext* aCx, - JSObject* /* aObj */) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - // Don't leave dangling JSObject pointers in our handlers! - ClearAllListeners(); - - // Clear our wrapped native now that it has died. - { - MutexAutoLock lock(mLock); - mWrappedNative = nsnull; - } - - // Do this *after* we null out mWrappedNative so that we don't hand out a - // freed pointer. - if (TerminateInternal(PR_TRUE) == NS_ERROR_ILLEGAL_DURING_SHUTDOWN) { - // We're shutting down, jump right to Kill. - Kill(); - } - - return NS_OK; -} - -NS_IMPL_CI_INTERFACE_GETTER3(nsDOMWorker, nsIWorker, - nsIAbstractWorker, - nsIDOMEventTarget) -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorker) -NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorker) - -NS_IMETHODIMP -nsDOMWorker::GetHelperForLanguage(PRUint32 aLanguage, - nsISupports** _retval) -{ - if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) { - NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(nsIWorker*, this)); - } - else { - *_retval = nsnull; - } - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorker::Initialize(nsISupports* aOwner, - JSContext* aCx, - JSObject* aObj, - PRUint32 aArgc, - jsval* aArgv) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ENSURE_ARG_POINTER(aOwner); - - nsCOMPtr<nsIScriptGlobalObject> globalObj(do_QueryInterface(aOwner)); - NS_ENSURE_TRUE(globalObj, NS_NOINTERFACE); - - return InitializeInternal(globalObj, aCx, aObj, aArgc, aArgv); -} - -nsresult -nsDOMWorker::InitializeInternal(nsIScriptGlobalObject* aOwner, - JSContext* aCx, - JSObject* aObj, - PRUint32 aArgc, - jsval* aArgv) -{ - NS_ASSERTION(aCx, "Null context!"); - NS_ASSERTION(aObj, "Null global object!"); - - NS_ENSURE_TRUE(aArgc, NS_ERROR_XPC_NOT_ENOUGH_ARGS); - NS_ENSURE_ARG_POINTER(aArgv); - - JSString* str = JS_ValueToString(aCx, aArgv[0]); - NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS); - - nsDependentJSString depStr; - NS_ENSURE_TRUE(depStr.init(aCx, str), NS_ERROR_OUT_OF_MEMORY); - - mScriptURL.Assign(depStr); - NS_ENSURE_FALSE(mScriptURL.IsEmpty(), NS_ERROR_INVALID_ARG); - - nsresult rv; - - // Figure out the principal and base URI to use if we're on the main thread. - // Otherwise this is a sub-worker and it will have its principal set by the - // script loader. - if (NS_IsMainThread()) { - nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); - NS_ASSERTION(ssm, "Should never be null!"); - - PRBool isChrome; - rv = ssm->IsCapabilityEnabled("UniversalXPConnect", &isChrome); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(isChrome || aOwner, "How can we have a non-chrome, non-window " - "worker?!"); - - // Chrome callers (whether ChromeWorker of Worker) always get the system - // principal here as they're allowed to load anything. The script loader may - // change the principal later depending on the script uri. - if (isChrome) { - rv = ssm->GetSystemPrincipal(getter_AddRefs(mPrincipal)); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (aOwner) { - // We're being created inside a window. Get the document's base URI and - // use it as our base URI. - nsCOMPtr<nsPIDOMWindow> domWindow = do_QueryInterface(aOwner, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsIDOMDocument* domDocument = domWindow->GetExtantDocument(); - NS_ENSURE_STATE(domDocument); - - nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - mBaseURI = document->GetDocBaseURI(); - - if (!mPrincipal) { - // Use the document's NodePrincipal as our principal if we're not being - // called from chrome. - mPrincipal = document->NodePrincipal(); - NS_ENSURE_STATE(mPrincipal); - } - } - else { - // We're being created outside of a window. Need to figure out the script - // that is creating us in order for us to use relative URIs later on. - JSStackFrame* frame = JS_GetScriptedCaller(aCx, nsnull); - if (frame) { - JSScript* script = JS_GetFrameScript(aCx, frame); - NS_ENSURE_STATE(script); - - const char* filename = JS_GetScriptFilename(aCx, script); - - rv = NS_NewURI(getter_AddRefs(mBaseURI), filename); - NS_ENSURE_SUCCESS(rv, rv); - } - } - - NS_ASSERTION(mPrincipal, "Should have set the principal!"); - } - - NS_ASSERTION(!mGlobal, "Already got a global?!"); - - nsCOMPtr<nsIXPConnectJSObjectHolder> thisWrapped; - jsval v; - rv = nsContentUtils::WrapNative(aCx, aObj, static_cast<nsIWorker*>(this), &v, - getter_AddRefs(thisWrapped)); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(mWrappedNative, "Post-create hook should have set this!"); - - mKillTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIThread> mainThread; - rv = NS_GetMainThread(getter_AddRefs(mainThread)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mKillTimer->SetTarget(mainThread); - NS_ENSURE_SUCCESS(rv, rv); - - // 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 nsWorkerHoldingRunnable(this)); - NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY); - - nsRefPtr<nsDOMThreadService> threadService = - nsDOMThreadService::GetOrInitService(); - NS_ENSURE_STATE(threadService); - - rv = threadService->RegisterWorker(this, aOwner); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(mPool, "RegisterWorker should have set our pool!"); - - rv = threadService->Dispatch(this, runnable); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -void -nsDOMWorker::Cancel() -{ - // Called by the pool when the window that created us is being torn down. Must - // always be on the main thread. - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - // We set the eCanceled status to indicate this. It behaves just like the - // eTerminated status (canceled while close runnable is unscheduled, not - // canceled while close runnable is running) except that it always reports - // that it is canceled when running on the main thread. This status trumps all - // others (except eKilled). Have to do this because the window that created - // us has gone away and had its scope cleared so XPConnect will assert all - // over the place if we try to run anything. - - PRBool enforceTimeout = PR_FALSE; - { - MutexAutoLock lock(mLock); - - NS_ASSERTION(mStatus != eCanceled, "Canceled more than once?!"); - - if (mStatus == eKilled) { - return; - } - - DOMWorkerStatus oldStatus = mStatus; - mStatus = eCanceled; - if (oldStatus != eRunning) { - enforceTimeout = PR_TRUE; - } - } - - PRUint32 timeoutMS = nsDOMThreadService::GetWorkerCloseHandlerTimeoutMS(); - NS_ASSERTION(timeoutMS, "This must not be 0!"); - -#ifdef DEBUG - nsresult rv; -#endif - if (enforceTimeout) { - // Tell the thread service to enforce a timeout on the close handler that - // is already scheduled. - nsDOMThreadService::get()-> - SetWorkerTimeout(this, PR_MillisecondsToInterval(timeoutMS)); - -#ifdef DEBUG - rv = -#endif - mKillTimer->InitWithCallback(this, timeoutMS, nsITimer::TYPE_ONE_SHOT); - NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to init kill timer!"); - - return; - } - -#ifdef DEBUG - rv = -#endif - FireCloseRunnable(PR_MillisecondsToInterval(timeoutMS), PR_TRUE, PR_FALSE); - NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to fire close runnable!"); -} - -void -nsDOMWorker::Kill() -{ - // Cancel all features and set our status to eKilled. This should only be - // called on the main thread by the thread service or our kill timer to - // indicate that the worker's close handler has run (or timed out). - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(IsClosing(), "Close handler should have run by now!"); - - // If the close handler finished before our kill timer then we don't need it - // any longer. - if (mKillTimer) { - mKillTimer->Cancel(); - mKillTimer = nsnull; - } - - PRUint32 count, index; - nsAutoTArray<nsRefPtr<nsDOMWorkerFeature>, 20> features; - { - MutexAutoLock lock(mLock); - - if (mStatus == eKilled) { - NS_ASSERTION(mFeatures.Length() == 0, "Features added after killed!"); - return; - } - mStatus = eKilled; - - count = mFeatures.Length(); - for (index = 0; index < count; index++) { - nsDOMWorkerFeature*& feature = mFeatures[index]; - -#ifdef DEBUG - nsRefPtr<nsDOMWorkerFeature>* newFeature = -#endif - features.AppendElement(feature); - NS_ASSERTION(newFeature, "Out of memory!"); - - feature->FreeToDie(PR_TRUE); - } - - mFeatures.Clear(); - } - - count = features.Length(); - for (index = 0; index < count; index++) { - 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; - mGlobal = NULL; - - // And we can let our parent die now too. - mParent = nsnull; - mParentWN = nsnull; -} - -void -nsDOMWorker::Suspend() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - PRBool shouldSuspendFeatures; - { - MutexAutoLock lock(mLock); - NS_ASSERTION(!mSuspended, "Suspended more than once!"); - shouldSuspendFeatures = !mSuspended; - mSuspended = PR_TRUE; - } - - if (shouldSuspendFeatures) { - SuspendFeatures(); - } -} - -void -nsDOMWorker::Resume() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - PRBool shouldResumeFeatures; - { - MutexAutoLock lock(mLock); -#ifdef DEBUG - // Should only have a mismatch if GC or Cancel happened while suspended. - if (!mSuspended) { - NS_ASSERTION(mStatus == eCanceled || - (mStatus == eTerminated && !mWrappedNative), - "Not suspended!"); - } -#endif - shouldResumeFeatures = mSuspended; - mSuspended = PR_FALSE; - } - - 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 -nsDOMWorker::IsCanceled() -{ - MutexAutoLock lock(mLock); - return IsCanceledNoLock(); -} - -PRBool -nsDOMWorker::IsCanceledNoLock() -{ - // If we haven't started the close process then we're not canceled. - if (mStatus == eRunning) { - return PR_FALSE; - } - - // There are several conditions under which we want JS code to abort and all - // other functions to bail: - // 1. If we've already run our close handler then we are canceled forevermore. - // 2. If we've been terminated then we want to pretend to be canceled until - // our close handler is scheduled and running. - // 3. If we've been canceled then we pretend to be canceled until the close - // handler has been scheduled. - // 4. If the close handler has run for longer than the allotted time then we - // should be canceled as well. - // 5. If we're on the main thread then we'll pretend to be canceled if the - // user has navigated away from the page. - return mStatus == eKilled || - (mStatus == eTerminated && !mExpirationTime) || - (mStatus == eCanceled && !mExpirationTime) || - (mExpirationTime && mExpirationTime != PR_INTERVAL_NO_TIMEOUT && - mExpirationTime <= PR_IntervalNow()) || - (mStatus == eCanceled && NS_IsMainThread()); -} - -PRBool -nsDOMWorker::IsClosing() -{ - MutexAutoLock lock(mLock); - return mStatus != eRunning; -} - -PRBool -nsDOMWorker::IsSuspended() -{ - MutexAutoLock lock(mLock); - return mSuspended; -} - -nsresult -nsDOMWorker::PostMessageInternal(PRBool aToInner) -{ - nsIXPConnect* xpc = nsContentUtils::XPConnect(); - NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED); - - nsAXPCNativeCallContext* cc; - nsresult rv = xpc->GetCurrentNativeCallContext(&cc); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(cc, NS_ERROR_UNEXPECTED); - - PRUint32 argc; - rv = cc->GetArgc(&argc); - NS_ENSURE_SUCCESS(rv, rv); - - if (!argc) { - return NS_ERROR_XPC_NOT_ENOUGH_ARGS; - } - - jsval* argv; - rv = cc->GetArgvPtr(&argv); - NS_ENSURE_SUCCESS(rv, rv); - - JSContext* cx; - rv = cc->GetJSContext(&cx); - NS_ENSURE_SUCCESS(rv, rv); - - // If we're a ChromeWorker then we allow wrapped natives to be passed via - // structured cloning by supplying a custom write callback. To do that we need - // to make sure they stay alive while the message is being sent, so we collect - // the wrapped natives in an array to be packaged with the message. - JSStructuredCloneCallbacks callbacks = { - nsnull, IsPrivileged() ? WriteStructuredClone : nsnull, nsnull - }; - - JSAutoRequest ar(cx); - - JSAutoStructuredCloneBuffer buffer; - nsTArray<nsCOMPtr<nsISupports> > wrappedNatives; - if (!buffer.write(cx, argv[0], &callbacks, &wrappedNatives)) { - return NS_ERROR_DOM_DATA_CLONE_ERR; - } - - nsRefPtr<nsDOMWorkerMessageEvent> message = new nsDOMWorkerMessageEvent(); - NS_ENSURE_TRUE(message, NS_ERROR_OUT_OF_MEMORY); - - rv = message->InitMessageEvent(NS_LITERAL_STRING("message"), PR_FALSE, - PR_FALSE, EmptyString(), EmptyString(), - nsnull); - NS_ENSURE_SUCCESS(rv, rv); - - rv = message->SetJSData(cx, buffer, wrappedNatives); - NS_ENSURE_SUCCESS(rv, rv); - - nsRefPtr<nsDOMFireEventRunnable> runnable = - new nsDOMFireEventRunnable(this, message, aToInner); - NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY); - - // If aToInner is true then we want to target the runnable at this worker's - // thread. Otherwise we need to target the parent's thread. - nsDOMWorker* target = aToInner ? this : mParent; - - // If this is a top-level worker then target the main thread. Otherwise use - // the thread service to find the target's thread. - if (!target) { - nsCOMPtr<nsIThread> mainThread; - rv = NS_GetMainThread(getter_AddRefs(mainThread)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mainThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); - } - else { - rv = nsDOMThreadService::get()->Dispatch(target, runnable); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} - -PRBool -nsDOMWorker::SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest, - JSAutoEnterCompartment *aComp) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - if (!CompileGlobalObject(aCx, aRequest, aComp)) { - return PR_FALSE; - } - - JS_SetGlobalObject(aCx, mGlobal); - return PR_TRUE; -} - -PRBool -nsDOMWorker::CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest, - JSAutoEnterCompartment *aComp) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - // On success, we enter a request and a cross-compartment call that both - // belong to the caller. But on failure, we must not remain in a request or - // cross-compartment call. So we enter both only locally at first. On - // failure, the local request and call will automatically get cleaned - // up. Once success is certain, we swap them into *aRequest and *aCall. - nsLazyAutoRequest localRequest; - JSAutoEnterCompartment localAutoCompartment; - localRequest.enter(aCx); - - PRBool success; - if (mGlobal) { - success = localAutoCompartment.enter(aCx, mGlobal); - NS_ENSURE_TRUE(success, PR_FALSE); - - aRequest->swap(localRequest); - aComp->swap(localAutoCompartment); - return PR_TRUE; - } - - if (mCompileAttempted) { - // Don't try to recompile a bad script. - return PR_FALSE; - } - mCompileAttempted = PR_TRUE; - - NS_ASSERTION(!mScriptURL.IsEmpty(), "Must have a url here!"); - - NS_ASSERTION(!JS_GetGlobalObject(aCx), "Global object should be unset!"); - - nsRefPtr<nsDOMWorkerScope> scope = new nsDOMWorkerScope(this); - NS_ENSURE_TRUE(scope, PR_FALSE); - - nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIWorkerScope*, scope); - - nsIXPConnect* xpc = nsContentUtils::XPConnect(); - - const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES | - nsIXPConnect::OMIT_COMPONENTS_OBJECT; - - nsCOMPtr<nsIXPConnectJSObjectHolder> globalWrapper; - nsresult rv = - xpc->InitClassesWithNewWrappedGlobal(aCx, scopeSupports, - NS_GET_IID(nsISupports), nsnull, - NS_ISUPPORTS_CAST(nsIWorker*, this), - flags, getter_AddRefs(globalWrapper)); - NS_ENSURE_SUCCESS(rv, PR_FALSE); - - JSObject* global; - rv = globalWrapper->GetJSObject(&global); - NS_ENSURE_SUCCESS(rv, PR_FALSE); - - NS_ASSERTION(JS_GetGlobalObject(aCx) == global, "Global object mismatch!"); - - success = localAutoCompartment.enter(aCx, global); - NS_ENSURE_TRUE(success, PR_FALSE); - -#ifdef DEBUG - { - jsval components; - if (JS_GetProperty(aCx, global, "Components", &components)) { - NS_ASSERTION(components == JSVAL_VOID, - "Components property still defined!"); - } - } -#endif - - // Set up worker thread functions. - success = JS_DefineFunctions(aCx, global, gDOMWorkerFunctions); - NS_ENSURE_TRUE(success, PR_FALSE); - - success = JS_DefineProfilingFunctions(aCx, global); - NS_ENSURE_TRUE(success, PR_FALSE); - - if (IsPrivileged()) { - // Add chrome functions. - success = JS_DefineFunctions(aCx, global, gDOMWorkerChromeFunctions); - NS_ENSURE_TRUE(success, PR_FALSE); - - success = JS_DefineProperty(aCx, global, "XPCOM", JSVAL_VOID, - nsDOMWorkerFunctions::XPCOMLazyGetter, nsnull, - 0); - NS_ENSURE_TRUE(success, PR_FALSE); - -#ifdef BUILD_CTYPES - // Add the lazy getter for ctypes. - success = JS_DefineProperty(aCx, global, "ctypes", JSVAL_VOID, - nsDOMWorkerFunctions::CTypesLazyGetter, nsnull, - 0); - NS_ENSURE_TRUE(success, PR_FALSE); -#endif - } - - // From here on out we have to remember to null mGlobal, mInnerScope, and - // mScopeWN if something fails! We really don't need to hang on to mGlobal - // as long as we have mScopeWN, but it saves us a virtual call every time the - // worker is scheduled. Meh. - mGlobal = global; - mInnerScope = scope; - mScopeWN = scope->GetWrappedNative(); - NS_ASSERTION(mScopeWN, "Should have a wrapped native here!"); - - nsRefPtr<nsDOMWorkerScriptLoader> loader = - new nsDOMWorkerScriptLoader(this); - - rv = AddFeature(loader, aCx); - if (NS_FAILED(rv)) { - mGlobal = NULL; - mInnerScope = nsnull; - mScopeWN = nsnull; - return PR_FALSE; - } - - rv = loader->LoadWorkerScript(aCx, mScriptURL); - - JS_ReportPendingException(aCx); - - if (NS_FAILED(rv)) { - mGlobal = NULL; - mInnerScope = nsnull; - mScopeWN = nsnull; - return PR_FALSE; - } - - NS_ASSERTION(mPrincipal, "Script loader didn't set our principal!"); - NS_ASSERTION(mBaseURI, "Script loader didn't set our base uri!"); - - // Make sure we kept the system principal. - if (IsPrivileged() && !nsContentUtils::IsSystemPrincipal(mPrincipal)) { - static const char warning[] = "ChromeWorker attempted to load a " - "non-chrome worker script!"; - NS_WARNING(warning); - - JS_ReportError(aCx, warning); - - mGlobal = NULL; - mInnerScope = nsnull; - mScopeWN = nsnull; - return PR_FALSE; - } - - rv = loader->ExecuteScripts(aCx); - - JS_ReportPendingException(aCx); - - if (NS_FAILED(rv)) { - mGlobal = NULL; - mInnerScope = nsnull; - mScopeWN = nsnull; - return PR_FALSE; - } - - aRequest->swap(localRequest); - aComp->swap(localAutoCompartment); - return PR_TRUE; -} - -void -nsDOMWorker::SetPool(nsDOMWorkerPool* aPool) -{ - NS_ASSERTION(!mPool, "Shouldn't ever set pool more than once!"); - mPool = aPool; -} - -already_AddRefed<nsIXPConnectWrappedNative> -nsDOMWorker::GetWrappedNative() -{ - nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative; - { - MutexAutoLock lock(mLock); - wrappedNative = mWrappedNative; - } - return wrappedNative.forget(); -} - -nsresult -nsDOMWorker::AddFeature(nsDOMWorkerFeature* aFeature, - JSContext* aCx) -{ - NS_ASSERTION(aFeature, "Null pointer!"); - - PRBool shouldSuspend; - { - // aCx may be null. - JSAutoSuspendRequest asr(aCx); - - MutexAutoLock lock(mLock); - - if (mStatus == eKilled) { - // No features may be added after we've been canceled. Sorry. - return NS_ERROR_FAILURE; - } - - nsDOMWorkerFeature** newFeature = mFeatures.AppendElement(aFeature); - NS_ENSURE_TRUE(newFeature, NS_ERROR_OUT_OF_MEMORY); - - aFeature->FreeToDie(PR_FALSE); - shouldSuspend = mFeatureSuspendDepth > 0; - } - - if (shouldSuspend) { - aFeature->Suspend(); - } - - return NS_OK; -} - -void -nsDOMWorker::RemoveFeature(nsDOMWorkerFeature* aFeature, - JSContext* aCx) -{ - NS_ASSERTION(aFeature, "Null pointer!"); - - // This *must* be a nsRefPtr so that we call Release after setting FreeToDie. - nsRefPtr<nsDOMWorkerFeature> feature(aFeature); - { - // aCx may be null. - JSAutoSuspendRequest asr(aCx); - - MutexAutoLock lock(mLock); - -#ifdef DEBUG - PRBool removed = -#endif - mFeatures.RemoveElement(aFeature); - NS_ASSERTION(removed, "Feature not in the list!"); - - aFeature->FreeToDie(PR_TRUE); - } -} - -void -nsDOMWorker::CancelTimeoutWithId(PRUint32 aId) -{ - nsRefPtr<nsDOMWorkerFeature> foundFeature; - { - MutexAutoLock lock(mLock); - PRUint32 count = mFeatures.Length(); - for (PRUint32 index = 0; index < count; index++) { - nsDOMWorkerFeature*& feature = mFeatures[index]; - if (feature->HasId() && feature->GetId() == aId) { - foundFeature = feature; - feature->FreeToDie(PR_TRUE); - mFeatures.RemoveElementAt(index); - break; - } - } - } - - if (foundFeature) { - foundFeature->Cancel(); - } -} - -void -nsDOMWorker::SuspendFeatures() -{ - nsAutoTArray<nsRefPtr<nsDOMWorkerFeature>, 20> features; - { - MutexAutoLock lock(mLock); - - // We don't really have to worry about overflow here because the only way - // to do this is through recursive script loading, which uses the stack. We - // would exceed our stack limit long before this counter. - NS_ASSERTION(mFeatureSuspendDepth < PR_UINT32_MAX, "Shouldn't happen!"); - if (++mFeatureSuspendDepth != 1) { - // Allow nested suspending of timeouts. - return; - } - -#ifdef DEBUG - nsRefPtr<nsDOMWorkerFeature>* newFeatures = -#endif - features.AppendElements(mFeatures); - NS_WARN_IF_FALSE(newFeatures, "Out of memory!"); - } - - PRUint32 count = features.Length(); - for (PRUint32 i = 0; i < count; i++) { - features[i]->Suspend(); - } -} - -void -nsDOMWorker::ResumeFeatures() -{ - nsAutoTArray<nsRefPtr<nsDOMWorkerFeature>, 20> features; - { - MutexAutoLock lock(mLock); - - NS_ASSERTION(mFeatureSuspendDepth > 0, "Shouldn't happen!"); - if (--mFeatureSuspendDepth != 0) { - return; - } - - features.AppendElements(mFeatures); - } - - PRUint32 count = features.Length(); - for (PRUint32 i = 0; i < count; i++) { - features[i]->Resume(); - } -} - -void -nsDOMWorker::SetPrincipal(nsIPrincipal* aPrincipal) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(aPrincipal, "Null pointer!"); - - mPrincipal = aPrincipal; -} - -nsresult -nsDOMWorker::SetBaseURI(nsIURI* aURI) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(aURI, "Don't hand me a null pointer!"); - - mBaseURI = aURI; - - nsCOMPtr<nsIURL> url(do_QueryInterface(aURI)); - NS_ENSURE_TRUE(url, NS_ERROR_NO_INTERFACE); - - mLocation = nsDOMWorkerLocation::NewLocation(url); - NS_ENSURE_TRUE(mLocation, NS_ERROR_FAILURE); - - return NS_OK; -} - -void -nsDOMWorker::ClearBaseURI() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - mBaseURI = nsnull; - mLocation = nsnull; -} - -nsresult -nsDOMWorker::FireCloseRunnable(PRIntervalTime aTimeoutInterval, - PRBool aClearQueue, - PRBool aFromFinalize) -{ - // Resume the worker (but not its features) if we're currently suspended. This - // should only ever happen if we are being called from Cancel (page falling - // out of bfcache or quitting) or Finalize, in which case all we really want - // to do is unblock the waiting thread. - PRBool wakeUp; - { - MutexAutoLock lock(mLock); - NS_ASSERTION(mExpirationTime == 0, - "Close runnable should not be scheduled already!"); - - if ((wakeUp = mSuspended)) { - NS_ASSERTION(mStatus == eCanceled || - (mStatus == eTerminated && aFromFinalize), - "How can this happen otherwise?!"); - mSuspended = PR_FALSE; - } - } - - if (wakeUp) { - ReentrantMonitorAutoEnter mon(mPool->GetReentrantMonitor()); - mon.NotifyAll(); - } - - nsRefPtr<nsDOMWorkerEvent> event = new nsDOMWorkerEvent(); - NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); - - nsresult rv = - event->InitEvent(NS_LITERAL_STRING("close"), PR_FALSE, PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); - - nsRefPtr<nsDOMFireEventRunnable> runnable = - new nsDOMFireEventRunnable(this, event, PR_TRUE); - NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY); - - // Our worker has been collected and we want to keep the inner scope alive, - // so pass that along in the runnable. - if (aFromFinalize) { - // Make sure that our scope wrapped native exists here, but if the worker - // script failed to compile then it will be null already. - if (mGlobal) { - NS_ASSERTION(mScopeWN, "This shouldn't be null!"); - } - runnable->ReplaceWrappedNative(mScopeWN); - } - - return nsDOMThreadService::get()->Dispatch(this, runnable, aTimeoutInterval, - aClearQueue); -} - -nsresult -nsDOMWorker::Close() -{ - { - MutexAutoLock lock(mLock); - NS_ASSERTION(mStatus != eKilled, "This should be impossible!"); - if (mStatus != eRunning) { - return NS_OK; - } - mStatus = eClosed; - } - - nsresult rv = FireCloseRunnable(PR_INTERVAL_NO_TIMEOUT, PR_FALSE, PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -nsresult -nsDOMWorker::TerminateInternal(PRBool aFromFinalize) -{ - { - MutexAutoLock lock(mLock); -#ifdef DEBUG - if (!aFromFinalize) { - NS_ASSERTION(mStatus != eCanceled, "Shouldn't be able to get here!"); - } -#endif - - if (mStatus == eRunning) { - // This is the beginning of the close process, fire an event and prevent - // any other close events from being generated. - mStatus = eTerminated; - } - else { - if (mStatus == eClosed) { - // The worker was previously closed which means that an expiration time - // might not be set. Setting the status to eTerminated will force the - // worker to jump to its close handler. - mStatus = eTerminated; - } - // No need to fire another close handler, it has already been done. - return NS_OK; - } - } - - nsresult rv = FireCloseRunnable(PR_INTERVAL_NO_TIMEOUT, PR_TRUE, - aFromFinalize); - if (rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN) { - return rv; - } - - // Warn about other kinds of failures. - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -already_AddRefed<nsDOMWorker> -nsDOMWorker::GetParent() -{ - nsRefPtr<nsDOMWorker> parent(mParent); - return parent.forget(); -} - -void -nsDOMWorker::SetExpirationTime(PRIntervalTime aExpirationTime) -{ - { - MutexAutoLock lock(mLock); - - NS_ASSERTION(mStatus != eRunning && mStatus != eKilled, "Bad status!"); - NS_ASSERTION(!mExpirationTime || mExpirationTime == PR_INTERVAL_NO_TIMEOUT, - "Overwriting a timeout that was previously set!"); - - mExpirationTime = aExpirationTime; - } -} - -#ifdef DEBUG -PRIntervalTime -nsDOMWorker::GetExpirationTime() -{ - MutexAutoLock lock(mLock); - return mExpirationTime; -} -#endif - -// static -JSObject* -nsDOMWorker::ReadStructuredClone(JSContext* aCx, - JSStructuredCloneReader* aReader, - uint32 aTag, - uint32 aData, - void* aClosure) -{ - NS_ASSERTION(aCx, "Null context!"); - NS_ASSERTION(aReader, "Null reader!"); - NS_ASSERTION(!aClosure, "Shouldn't have a closure here!"); - - if (aTag == DOMWORKER_SCTAG_WRAPPEDNATIVE) { - NS_ASSERTION(!aData, "Huh?"); - - nsISupports* wrappedNative; - if (JS_ReadBytes(aReader, &wrappedNative, sizeof(wrappedNative))) { - NS_ASSERTION(wrappedNative, "Null pointer?!"); - - JSObject* global = JS_GetGlobalForObject(aCx, JS_GetScopeChain(aCx)); - if (global) { - jsval val; - nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper; - if (NS_SUCCEEDED(nsContentUtils::WrapNative(aCx, global, wrappedNative, - &val, - getter_AddRefs(wrapper)))) { - return JSVAL_TO_OBJECT(val); - } - } - } - } - - // Something failed above, try using the runtime callbacks instead. - const JSStructuredCloneCallbacks* runtimeCallbacks = - aCx->runtime->structuredCloneCallbacks; - if (runtimeCallbacks) { - return runtimeCallbacks->read(aCx, aReader, aTag, aData, nsnull); - } - - // We can't handle this object, throw an exception if one hasn't been thrown - // already. - if (!JS_IsExceptionPending(aCx)) { - nsDOMClassInfo::ThrowJSException(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); - } - return nsnull; -} - -PRBool -nsDOMWorker::QueueSuspendedRunnable(nsIRunnable* aRunnable) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - return mQueuedRunnables.AppendElement(aRunnable) ? PR_TRUE : PR_FALSE; -} - -NS_IMETHODIMP -nsDOMWorker::RemoveEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture) -{ - if (IsCanceled()) { - return NS_OK; - } - - return nsDOMWorkerMessageHandler::RemoveEventListener(aType, aListener, - aUseCapture); -} - -NS_IMETHODIMP -nsDOMWorker::DispatchEvent(nsIDOMEvent* aEvent, - PRBool* _retval) -{ - { - MutexAutoLock lock(mLock); - if (IsCanceledNoLock()) { - return NS_OK; - } - if (mStatus == eTerminated) { - nsCOMPtr<nsIWorkerMessageEvent> messageEvent(do_QueryInterface(aEvent)); - if (messageEvent) { - // This is a message event targeted to a terminated worker. Ignore it. - return NS_OK; - } - } - } - - return nsDOMWorkerMessageHandler::DispatchEvent(aEvent, _retval); -} - -NS_IMETHODIMP -nsDOMWorker::AddEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture, - PRBool aWantsUntrusted, - PRUint8 aOptionalArgc) -{ - NS_ASSERTION(mWrappedNative, "Called after Finalize!"); - if (IsCanceled()) { - return NS_OK; - } - - return nsDOMWorkerMessageHandler::AddEventListener(aType, aListener, - aUseCapture, - aWantsUntrusted, - aOptionalArgc); -} - -/** - * See nsIWorker - */ -NS_IMETHODIMP -nsDOMWorker::PostMessage(/* JSObject aMessage */) -{ - { - MutexAutoLock lock(mLock); - // There's no reason to dispatch this message after the close handler has - // been triggered since it will never be allowed to run. - if (mStatus != eRunning) { - return NS_OK; - } - } - - return PostMessageInternal(PR_TRUE); -} - -/** - * See nsIWorker - */ -NS_IMETHODIMP -nsDOMWorker::GetOnerror(nsIDOMEventListener** aOnerror) -{ - NS_ENSURE_ARG_POINTER(aOnerror); - - if (IsCanceled()) { - *aOnerror = nsnull; - return NS_OK; - } - - nsCOMPtr<nsIDOMEventListener> listener = - GetOnXListener(NS_LITERAL_STRING("error")); - - listener.forget(aOnerror); - return NS_OK; -} - -/** - * See nsIWorker - */ -NS_IMETHODIMP -nsDOMWorker::SetOnerror(nsIDOMEventListener* aOnerror) -{ - NS_ASSERTION(mWrappedNative, "Called after Finalize!"); - if (IsCanceled()) { - return NS_OK; - } - - return SetOnXListener(NS_LITERAL_STRING("error"), aOnerror); -} - -/** - * See nsIWorker - */ -NS_IMETHODIMP -nsDOMWorker::GetOnmessage(nsIDOMEventListener** aOnmessage) -{ - NS_ENSURE_ARG_POINTER(aOnmessage); - - if (IsCanceled()) { - *aOnmessage = nsnull; - return NS_OK; - } - - nsCOMPtr<nsIDOMEventListener> listener = - GetOnXListener(NS_LITERAL_STRING("message")); - - listener.forget(aOnmessage); - return NS_OK; -} - -/** - * See nsIWorker - */ -NS_IMETHODIMP -nsDOMWorker::SetOnmessage(nsIDOMEventListener* aOnmessage) -{ - NS_ASSERTION(mWrappedNative, "Called after Finalize!"); - if (IsCanceled()) { - return NS_OK; - } - - return SetOnXListener(NS_LITERAL_STRING("message"), aOnmessage); -} - -NS_IMETHODIMP -nsDOMWorker::Terminate() -{ - return TerminateInternal(PR_FALSE); -} - -NS_IMETHODIMP -nsDOMWorker::Notify(nsITimer* aTimer) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - Kill(); - return NS_OK; -} - -NS_IMETHODIMP -nsWorkerFactory::NewChromeWorker(nsIWorker** _retval) -{ - nsresult rv; - - // Get the arguments from XPConnect. - nsCOMPtr<nsIXPConnect> xpc; - xpc = do_GetService(nsIXPConnect::GetCID()); - NS_ASSERTION(xpc, "Could not get XPConnect"); - - nsAXPCNativeCallContext* cc; - rv = xpc->GetCurrentNativeCallContext(&cc); - NS_ENSURE_SUCCESS(rv, rv); - - JSContext* cx; - rv = cc->GetJSContext(&cx); - NS_ENSURE_SUCCESS(rv, rv); - - PRUint32 argc; - rv = cc->GetArgc(&argc); - NS_ENSURE_SUCCESS(rv, rv); - - jsval* argv; - rv = cc->GetArgvPtr(&argv); - NS_ENSURE_SUCCESS(rv, rv); - - // Determine the current script global. We need it to register the worker. - // NewChromeDOMWorker will check that we are chrome, so no access check. - JSObject* global = JS_GetGlobalForScopeChain(cx); - NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED); - - // May be null if we're being called from a JSM or something. - nsCOMPtr<nsIScriptGlobalObject> scriptGlobal = - nsJSUtils::GetStaticScriptGlobal(cx, global); - - // Create, initialize, and return the worker. - nsRefPtr<nsDOMWorker> chromeWorker; - rv = nsDOMWorker::NewChromeDOMWorker(getter_AddRefs(chromeWorker)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = chromeWorker->InitializeInternal(scriptGlobal, cx, global, argc, argv); - NS_ENSURE_SUCCESS(rv, rv); - - chromeWorker.forget(_retval); - return NS_OK; -} - -NS_IMPL_ISUPPORTS1(nsWorkerFactory, nsIWorkerFactory)
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorker.h +++ /dev/null @@ -1,471 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; 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 Web Workers. - * - * 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 __NSDOMWORKER_H__ -#define __NSDOMWORKER_H__ - -#include "nsIDOMEventTarget.h" -#include "nsIDOMWorkers.h" -#include "nsIJSNativeInitializer.h" -#include "nsIPrincipal.h" -#include "nsITimer.h" -#include "nsIURI.h" -#include "nsIXPCScriptable.h" - -#include "jsapi.h" -#include "mozilla/Mutex.h" -#include "nsAutoPtr.h" -#include "nsCOMPtr.h" -#include "nsTPtrArray.h" - -#include "nsDOMWorkerMessageHandler.h" - -// {1295EFB5-8644-42B2-8B8E-80EEF56E4284} -#define NS_WORKERFACTORY_CID \ - {0x1295efb5, 0x8644, 0x42b2, \ - {0x8b, 0x8e, 0x80, 0xee, 0xf5, 0x6e, 0x42, 0x84} } - -class nsDOMWorker; -class nsDOMWorkerFeature; -class nsDOMWorkerMessageHandler; -class nsDOMWorkerNavigator; -class nsDOMWorkerPool; -class nsDOMWorkerTimeout; -class nsICancelable; -class nsIDOMEventListener; -class nsIEventTarget; -class nsIRunnable; -class nsIScriptGlobalObject; -class nsIXPConnectWrappedNative; - -class nsDOMWorkerScope : public nsDOMWorkerMessageHandler, - public nsIWorkerScope, - public nsIXPCScriptable -{ - friend class nsDOMWorker; - -public: - NS_DECL_ISUPPORTS_INHERITED - - // nsIDOMEventHandler - NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::) - NS_IMETHOD AddEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture, - PRBool aWantsUntrusted, - PRUint8 optional_argc); - NS_IMETHOD RemoveEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture); - NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent, - PRBool* _retval); - NS_DECL_NSIWORKERGLOBALSCOPE - NS_DECL_NSIWORKERSCOPE - NS_DECL_NSIXPCSCRIPTABLE - NS_DECL_NSICLASSINFO - - typedef NS_STDCALL_FUNCPROTO(nsresult, SetListenerFunc, nsDOMWorkerScope, - SetOnmessage, (nsIDOMEventListener*)); - - nsDOMWorkerScope(nsDOMWorker* aWorker); - -protected: - already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative(); - -private: - nsDOMWorker* mWorker; - nsIXPConnectWrappedNative* mWrappedNative; - - nsRefPtr<nsDOMWorkerNavigator> mNavigator; - - PRPackedBool mHasOnerror; -}; - -class nsLazyAutoRequest -{ -public: - nsLazyAutoRequest() : mCx(nsnull) {} - - ~nsLazyAutoRequest() { - if (mCx) - JS_EndRequest(mCx); - } - - void enter(JSContext *aCx) { - JS_BeginRequest(aCx); - mCx = aCx; - } - - bool entered() const { return mCx != nsnull; } - - void swap(nsLazyAutoRequest &other) { - JSContext *tmp = mCx; - mCx = other.mCx; - other.mCx = tmp; - } - -private: - JSContext *mCx; -}; - -class nsDOMWorker : public nsDOMWorkerMessageHandler, - public nsIWorker, - public nsITimerCallback, - public nsIJSNativeInitializer, - public nsIXPCScriptable -{ - typedef mozilla::Mutex Mutex; - - friend class nsDOMWorkerFeature; - friend class nsDOMWorkerFunctions; - friend class nsDOMWorkerScope; - friend class nsDOMWorkerScriptLoader; - friend class nsDOMWorkerTimeout; - friend class nsDOMWorkerXHR; - friend class nsDOMWorkerXHRProxy; - friend class nsReportErrorRunnable; - friend class nsDOMFireEventRunnable; - - friend JSBool DOMWorkerOperationCallback(JSContext* aCx); - friend void DOMWorkerErrorReporter(JSContext* aCx, - const char* aMessage, - JSErrorReport* aReport); - -public: - NS_DECL_ISUPPORTS_INHERITED - - // nsIDOMEventHandler - NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::) - NS_IMETHOD AddEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture, - PRBool aWantsUntrusted, - PRUint8 optional_argc); - NS_IMETHOD RemoveEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture); - NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent, - PRBool* _retval); - - NS_DECL_NSIABSTRACTWORKER - NS_DECL_NSIWORKER - NS_DECL_NSITIMERCALLBACK - NS_DECL_NSICLASSINFO - NS_DECL_NSIXPCSCRIPTABLE - - static nsresult NewWorker(nsISupports** aNewObject); - static nsresult NewChromeWorker(nsISupports** aNewObject); - static nsresult NewChromeDOMWorker(nsDOMWorker** aNewObject); - - enum WorkerPrivilegeModel { CONTENT, CHROME }; - - nsDOMWorker(nsDOMWorker* aParent, - nsIXPConnectWrappedNative* aParentWN, - WorkerPrivilegeModel aModel); - - NS_IMETHOD Initialize(nsISupports* aOwner, - JSContext* aCx, - JSObject* aObj, - PRUint32 aArgc, - jsval* aArgv); - - nsresult InitializeInternal(nsIScriptGlobalObject* aOwner, - JSContext* aCx, - JSObject* aObj, - PRUint32 aArgc, - jsval* aArgv); - - void Cancel(); - void Kill(); - void Suspend(); - void Resume(); - - // This just calls IsCanceledNoLock with an autolock around the call. - PRBool IsCanceled(); - - PRBool IsClosing(); - PRBool IsSuspended(); - - PRBool SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp); - - void SetPool(nsDOMWorkerPool* aPool); - - nsDOMWorkerPool* Pool() { - return mPool; - } - - Mutex& GetLock() { - return mLock; - } - - already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative(); - already_AddRefed<nsDOMWorker> GetParent(); - - nsDOMWorkerScope* GetInnerScope() { - return mInnerScope; - } - - void SetExpirationTime(PRIntervalTime aExpirationTime); -#ifdef DEBUG - PRIntervalTime GetExpirationTime(); -#endif - - PRBool IsPrivileged() { - return mPrivilegeModel == CHROME; - } - - static JSObject* ReadStructuredClone(JSContext* aCx, - JSStructuredCloneReader* aReader, - uint32 aTag, - uint32 aData, - void* aClosure); - - /** - * Use this chart to help figure out behavior during each of the closing - * statuses. Details below. - * - * +=============+=============+=================+=======================+ - * | status | clear queue | abort execution | close handler timeout | - * +=============+=============+=================+=======================+ - * | eClosed | yes | no | no | - * +-------------+-------------+-----------------+-----------------------+ - * | eTerminated | yes | yes | no | - * +-------------+-------------+-----------------+-----------------------+ - * | eCanceled | yes | yes | yes | - * +-------------+-------------+-----------------+-----------------------+ - * - */ - - enum DOMWorkerStatus { - // This status means that the close handler has not yet been scheduled. - eRunning = 0, - - // Inner script called Close() on the worker global scope. Setting this - // status causes the worker to clear its queue of events but does not abort - // the currently running script. The close handler is also scheduled with - // no expiration time. This status may be superseded by 'eTerminated' in - // which case the currently running script will be aborted as detailed - // below. It may also be superseded by 'eCanceled' at which point the close - // handler will be assigned an expiration time. Once the close handler has - // completed or timed out the status will be changed to 'eKilled'. - eClosed, - - // Outer script called Terminate() on the worker or the worker object was - // garbage collected in its outer script. Setting this status causes the - // worker to abort immediately, clear its queue of events, and schedules the - // close handler with no expiration time. This status may be superseded by - // 'eCanceled' at which point the close handler will have an expiration time - // assigned. Once the close handler has completed or timed out the status - // will be changed to 'eKilled'. - eTerminated, - - // Either the user navigated away from the owning page, the owning page fell - // out of bfcache, or the user quit the application. Setting this status - // causes the worker to abort immediately and schedules the close handler - // with an expiration time. Since the page has gone away the worker may not - // post any messages. Once the close handler has completed or timed out the - // status will be changed to 'eKilled'. - eCanceled, - - // The close handler has run and the worker is effectively dead. - eKilled - }; - -private: - ~nsDOMWorker(); - - nsresult PostMessageInternal(PRBool aToInner); - - PRBool CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp); - - PRUint32 NextTimeoutId() { - return ++mNextTimeoutId; - } - - nsresult AddFeature(nsDOMWorkerFeature* aFeature, - JSContext* aCx); - void RemoveFeature(nsDOMWorkerFeature* aFeature, - JSContext* aCx); - void CancelTimeoutWithId(PRUint32 aId); - void SuspendFeatures(); - void ResumeFeatures(); - - nsIPrincipal* GetPrincipal() { - return mPrincipal; - } - - void SetPrincipal(nsIPrincipal* aPrincipal); - - nsIURI* GetBaseURI() { - return mBaseURI; - } - - nsresult SetBaseURI(nsIURI* aURI); - - void ClearBaseURI(); - - nsresult FireCloseRunnable(PRIntervalTime aTimeoutInterval, - PRBool aClearQueue, - PRBool aFromFinalize); - nsresult Close(); - - nsresult TerminateInternal(PRBool aFromFinalize); - - nsIWorkerLocation* GetLocation() { - return mLocation; - } - - PRBool QueueSuspendedRunnable(nsIRunnable* aRunnable); - - // Determines if the worker should be considered "canceled". See the large - // comment in the implementation for more details. - PRBool IsCanceledNoLock(); - -private: - - // mParent will live as long as mParentWN but only mParentWN will keep the JS - // reflection alive, so we only hold one strong reference to mParentWN. - nsDOMWorker* mParent; - nsCOMPtr<nsIXPConnectWrappedNative> mParentWN; - - // Whether or not this worker has chrome privileges. Never changed after the - // worker is created. - WorkerPrivilegeModel mPrivilegeModel; - - Mutex mLock; - - nsRefPtr<nsDOMWorkerPool> mPool; - - nsDOMWorkerScope* mInnerScope; - nsCOMPtr<nsIXPConnectWrappedNative> mScopeWN; - JSObject* mGlobal; - - PRUint32 mNextTimeoutId; - - nsTArray<nsDOMWorkerFeature*> mFeatures; - PRUint32 mFeatureSuspendDepth; - - nsString mScriptURL; - - nsIXPConnectWrappedNative* mWrappedNative; - - nsCOMPtr<nsIPrincipal> mPrincipal; - nsCOMPtr<nsIURI> mBaseURI; - - PRInt32 mErrorHandlerRecursionCount; - - // Always protected by mLock - DOMWorkerStatus mStatus; - - // Always protected by mLock - PRIntervalTime mExpirationTime; - - nsCOMPtr<nsITimer> mKillTimer; - - nsCOMPtr<nsIWorkerLocation> mLocation; - - nsTArray<nsCOMPtr<nsIRunnable> > mQueuedRunnables; - - PRPackedBool mSuspended; - PRPackedBool mCompileAttempted; -}; - -/** - * A worker "feature" holds the worker alive yet can be canceled, paused, and - * resumed by the worker. It is up to each derived class to implement these - * methods. This class uses a custom implementation of Release in order to - * ensure no races between Cancel and object destruction can occur, so derived - * classes must use the ISUPPORTS_INHERITED macros. - * - * To use this class you should inherit it and use the ISUPPORTS_INHERITED - * macros. Then add or remove an instance to the worker using the - * AddFeature/RemoveFeature functions. - */ -class nsDOMWorkerFeature : public nsISupports -{ - friend class nsDOMWorker; - -public: - NS_DECL_ISUPPORTS - - nsDOMWorkerFeature(nsDOMWorker* aWorker) - : mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()), mId(0), - mHasId(PR_FALSE), mFreeToDie(PR_TRUE) { } - - nsDOMWorkerFeature(nsDOMWorker* aWorker, PRUint32 aId) - : mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()), mId(aId), - mHasId(PR_TRUE), mFreeToDie(PR_TRUE) { } - - virtual void Cancel() = 0; - virtual void Suspend() { } - virtual void Resume() { } - - PRUint32 GetId() { - return mId; - } - - PRBool HasId() { - return mHasId; - } - -protected: - virtual ~nsDOMWorkerFeature() { } - -private: - void FreeToDie(PRBool aFreeToDie) { - mFreeToDie = aFreeToDie; - } - -protected: - nsRefPtr<nsDOMWorker> mWorker; - nsCOMPtr<nsIXPConnectWrappedNative> mWorkerWN; - PRUint32 mId; - -private: - PRPackedBool mHasId; - PRPackedBool mFreeToDie; -}; - -class nsWorkerFactory : public nsIWorkerFactory -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIWORKERFACTORY -}; - -#endif /* __NSDOMWORKER_H__ */
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerEvents.cpp +++ /dev/null @@ -1,635 +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 Web Workers. - * - * 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 "nsDOMWorkerEvents.h" - -#include "nsIXMLHttpRequest.h" -#include "nsIXPConnect.h" - -#include "jsapi.h" -#include "nsAXPCNativeCallContext.h" -#include "nsContentUtils.h" -#include "nsThreadUtils.h" - -#include "nsDOMWorkerMessageHandler.h" -#include "nsDOMThreadService.h" -#include "nsDOMWorkerXHR.h" -#include "nsDOMWorkerXHRProxy.h" - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMWorkerPrivateEvent, - NS_IDOMWORKERPRIVATEEVENT_IID) - -nsDOMWorkerPrivateEvent::nsDOMWorkerPrivateEvent(nsIDOMEvent* aEvent) -: mEvent(aEvent), - mProgressEvent(do_QueryInterface(aEvent)), - mMessageEvent(do_QueryInterface(aEvent)), - mErrorEvent(do_QueryInterface(aEvent)), - mPreventDefaultCalled(PR_FALSE) -{ - NS_ASSERTION(aEvent, "Null pointer!"); -} - -NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerPrivateEvent) -NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerPrivateEvent) - -NS_INTERFACE_MAP_BEGIN(nsDOMWorkerPrivateEvent) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWorkerPrivateEvent) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEvent, nsIDOMWorkerPrivateEvent) - NS_INTERFACE_MAP_ENTRY(nsIDOMWorkerPrivateEvent) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMProgressEvent, mProgressEvent) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIWorkerMessageEvent, mMessageEvent) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIWorkerErrorEvent, mErrorEvent) - NS_INTERFACE_MAP_ENTRY(nsIClassInfo) -NS_INTERFACE_MAP_END - -NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerPrivateEvent, nsIDOMEvent) - -NS_IMPL_THREADSAFE_DOM_CI_HELPER(nsDOMWorkerPrivateEvent) -NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerPrivateEvent) - -NS_IMETHODIMP -nsDOMWorkerPrivateEvent::GetInterfaces(PRUint32* aCount, nsIID*** aArray) -{ - nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(mEvent)); - if (ci) { - return ci->GetInterfaces(aCount, aArray); - } - return NS_CI_INTERFACE_GETTER_NAME(nsDOMWorkerPrivateEvent)(aCount, aArray); -} - -NS_IMETHODIMP -nsDOMWorkerPrivateEvent::PreventDefault() -{ - PRBool cancelable = PR_FALSE; - mEvent->GetCancelable(&cancelable); - - if (cancelable) { - mPreventDefaultCalled = PR_TRUE; - } - - return mEvent->PreventDefault(); -} - -NS_IMETHODIMP -nsDOMWorkerPrivateEvent::GetDefaultPrevented(PRBool* aRetVal) -{ - *aRetVal = mPreventDefaultCalled; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerPrivateEvent::InitEvent(const nsAString& aEventType, - PRBool aCanBubble, - PRBool aCancelable) -{ - mPreventDefaultCalled = PR_FALSE; - return mEvent->InitEvent(aEventType, aCanBubble, aCancelable); -} - -NS_IMETHODIMP -nsDOMWorkerPrivateEvent::InitProgressEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - PRBool aLengthComputableArg, - PRUint64 aLoadedArg, - PRUint64 aTotalArg) -{ - NS_ASSERTION(mProgressEvent, "Impossible!"); - - mPreventDefaultCalled = PR_FALSE; - return mProgressEvent->InitProgressEvent(aTypeArg, aCanBubbleArg, - aCancelableArg, aLengthComputableArg, - aLoadedArg, aTotalArg); -} - -NS_IMETHODIMP -nsDOMWorkerPrivateEvent::InitMessageEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - const nsAString& aDataArg, - const nsAString& aOriginArg, - nsISupports* aSourceArg) -{ - NS_ASSERTION(mMessageEvent, "Impossible!"); - - mPreventDefaultCalled = PR_FALSE; - return mMessageEvent->InitMessageEvent(aTypeArg, aCanBubbleArg, - aCancelableArg, aDataArg, aOriginArg, - aSourceArg); -} - -NS_IMETHODIMP -nsDOMWorkerPrivateEvent::InitErrorEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - const nsAString& aMessageArg, - const nsAString& aFilenameArg, - PRUint32 aLinenoArg) -{ - NS_ASSERTION(mErrorEvent, "Impossible!"); - - mPreventDefaultCalled = PR_FALSE; - return mErrorEvent->InitErrorEvent(aTypeArg, aCanBubbleArg, aCancelableArg, - aMessageArg, aFilenameArg, aLinenoArg); -} - -PRBool -nsDOMWorkerPrivateEvent::PreventDefaultCalled() -{ - return mPreventDefaultCalled; -} - -NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerEvent, nsIDOMEvent, - nsIClassInfo) - -NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerEvent, nsIDOMEvent) - -NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerEvent) - -NS_IMETHODIMP -nsDOMWorkerEvent::GetType(nsAString& aType) -{ - aType.Assign(mType); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::GetTarget(nsIDOMEventTarget** aTarget) -{ - NS_ENSURE_ARG_POINTER(aTarget); - NS_IF_ADDREF(*aTarget = mTarget); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) -{ - NS_ENSURE_ARG_POINTER(aCurrentTarget); - NS_IF_ADDREF(*aCurrentTarget = mTarget); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::GetEventPhase(PRUint16* aEventPhase) -{ - NS_ENSURE_ARG_POINTER(aEventPhase); - *aEventPhase = mEventPhase; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::GetBubbles(PRBool* aBubbles) -{ - NS_ENSURE_ARG_POINTER(aBubbles); - *aBubbles = mBubbles; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::GetCancelable(PRBool* aCancelable) -{ - NS_ENSURE_ARG_POINTER(aCancelable); - *aCancelable = mCancelable; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::GetTimeStamp(DOMTimeStamp* aTimeStamp) -{ - NS_ENSURE_ARG_POINTER(aTimeStamp); - *aTimeStamp = mTimeStamp; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::StopPropagation() -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::PreventDefault() -{ - mPreventDefaultCalled = PR_TRUE; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::GetDefaultPrevented(PRBool* aRetVal) -{ - *aRetVal = mPreventDefaultCalled; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerEvent::InitEvent(const nsAString& aEventTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg) -{ - NS_ENSURE_FALSE(aEventTypeArg.IsEmpty(), NS_ERROR_INVALID_ARG); - - mType.Assign(aEventTypeArg); - mBubbles = aCanBubbleArg; - mCancelable = aCancelableArg; - mPreventDefaultCalled = PR_FALSE; - mTimeStamp = PR_Now(); - return NS_OK; -} - -nsDOMWorkerMessageEvent::~nsDOMWorkerMessageEvent() -{ - if (mData) { - JSContext* cx = nsDOMThreadService::GetCurrentContext(); - if (cx) { - JS_free(cx, mData); - } - else { - NS_WARNING("Failed to get safe JSContext, leaking event data!"); - } - } -} - -NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerMessageEvent, nsDOMWorkerEvent, - nsIWorkerMessageEvent) - -NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerMessageEvent, nsIDOMEvent, - nsIWorkerMessageEvent) - -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerMessageEvent) - -nsresult -nsDOMWorkerMessageEvent::SetJSData( - JSContext* aCx, - JSAutoStructuredCloneBuffer& aBuffer, - nsTArray<nsCOMPtr<nsISupports> >& aWrappedNatives) -{ - NS_ASSERTION(aCx, "Null context!"); - - if (!mDataVal.Hold(aCx)) { - NS_WARNING("Failed to hold jsval!"); - return NS_ERROR_FAILURE; - } - - if (!mWrappedNatives.SwapElements(aWrappedNatives)) { - NS_ERROR("This should never fail!"); - } - - aBuffer.steal(&mData, &mDataLen); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerMessageEvent::GetData(nsAString& aData) -{ - nsIXPConnect* xpc = nsContentUtils::XPConnect(); - NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED); - - nsAXPCNativeCallContext* cc; - nsresult rv = xpc->GetCurrentNativeCallContext(&cc); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(cc, NS_ERROR_UNEXPECTED); - - if (mData) { - JSContext* cx; - rv = cc->GetJSContext(&cx); - NS_ENSURE_SUCCESS(rv, rv); - - JSAutoRequest ar(cx); - JSAutoStructuredCloneBuffer buffer; - buffer.adopt(cx, mData, mDataLen); - mData = nsnull; - mDataLen = 0; - - JSStructuredCloneCallbacks callbacks = { - nsDOMWorker::ReadStructuredClone, nsnull, nsnull - }; - - JSBool ok = buffer.read(mDataVal.ToJSValPtr(), cx, &callbacks); - - // Release wrapped natives now, regardless of whether or not the deserialize - // succeeded. - mWrappedNatives.Clear(); - - if (!ok) { - NS_WARNING("Failed to deserialize!"); - return NS_ERROR_FAILURE; - } - } - - jsval* retval; - rv = cc->GetRetValPtr(&retval); - NS_ENSURE_SUCCESS(rv, rv); - - cc->SetReturnValueWasSet(PR_TRUE); - *retval = mDataVal; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerMessageEvent::GetOrigin(nsAString& aOrigin) -{ - aOrigin.Assign(mOrigin); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerMessageEvent::GetSource(nsISupports** aSource) -{ - NS_ENSURE_ARG_POINTER(aSource); - NS_IF_ADDREF(*aSource = mSource); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerMessageEvent::InitMessageEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - const nsAString& aDataArg, - const nsAString& aOriginArg, - nsISupports* aSourceArg) -{ - mOrigin.Assign(aOriginArg); - mSource = aSourceArg; - return nsDOMWorkerEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); -} - -NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerProgressEvent, nsDOMWorkerEvent, - nsIDOMProgressEvent) - -NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerProgressEvent, nsIDOMEvent, - nsIDOMProgressEvent) - -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerProgressEvent) - -NS_IMETHODIMP -nsDOMWorkerProgressEvent::GetLengthComputable(PRBool* aLengthComputable) -{ - NS_ENSURE_ARG_POINTER(aLengthComputable); - *aLengthComputable = mLengthComputable; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerProgressEvent::GetLoaded(PRUint64* aLoaded) -{ - NS_ENSURE_ARG_POINTER(aLoaded); - *aLoaded = mLoaded; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerProgressEvent::GetTotal(PRUint64* aTotal) -{ - NS_ENSURE_ARG_POINTER(aTotal); - *aTotal = mTotal; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerProgressEvent::InitProgressEvent(const nsAString_internal& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - PRBool aLengthComputableArg, - PRUint64 aLoadedArg, - PRUint64 aTotalArg) -{ - mLengthComputable = aLengthComputableArg; - mLoaded = aLoadedArg; - mTotal = aTotalArg; - return nsDOMWorkerEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); -} - -NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerXHRState) -NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerXHRState) - -nsDOMWorkerXHREvent::nsDOMWorkerXHREvent(nsDOMWorkerXHRProxy* aXHRProxy) -: mXHRProxy(aXHRProxy), - mXHREventType(PR_UINT32_MAX), - mChannelID(-1), - mUploadEvent(PR_FALSE), - mProgressEvent(PR_FALSE) -{ - NS_ASSERTION(aXHRProxy, "Can't be null!"); -} - -NS_IMPL_ADDREF_INHERITED(nsDOMWorkerXHREvent, nsDOMWorkerProgressEvent) -NS_IMPL_RELEASE_INHERITED(nsDOMWorkerXHREvent, nsDOMWorkerProgressEvent) - -NS_INTERFACE_MAP_BEGIN(nsDOMWorkerXHREvent) - NS_INTERFACE_MAP_ENTRY(nsIRunnable) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMProgressEvent, mProgressEvent) -NS_INTERFACE_MAP_END_INHERITING(nsDOMWorkerEvent) - -NS_IMETHODIMP -nsDOMWorkerXHREvent::GetInterfaces(PRUint32* aCount, - nsIID*** aArray) -{ - PRUint32 count = *aCount = mProgressEvent ? 2 : 1; - - *aArray = (nsIID**)nsMemory::Alloc(sizeof(nsIID*) * count); - - if (mProgressEvent) { - (*aArray)[--count] = - (nsIID*)nsMemory::Clone(&NS_GET_IID(nsIDOMProgressEvent), sizeof(nsIID)); - } - - (*aArray)[--count] = - (nsIID *)nsMemory::Clone(&NS_GET_IID(nsIDOMEvent), sizeof(nsIID)); - - NS_ASSERTION(!count, "Bad math!"); - return NS_OK; -} - -nsresult -nsDOMWorkerXHREvent::Init(PRUint32 aXHREventType, - const nsAString& aType, - nsIDOMEvent* aEvent, - SnapshotChoice aSnapshot) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(aEvent, "Don't pass null here!"); - - mXHREventType = aXHREventType; - - // Only set a channel id if we're not going to be run immediately. - mChannelID = mXHRProxy->mSyncEventQueue ? -1 : mXHRProxy->ChannelID(); - - mTarget = static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR); - NS_ENSURE_TRUE(mTarget, NS_ERROR_UNEXPECTED); - - mXHRWN = mXHRProxy->mWorkerXHR->GetWrappedNative(); - NS_ENSURE_STATE(mXHRWN); - - nsCOMPtr<nsIDOMEventTarget> mainThreadTarget; - nsresult rv = aEvent->GetTarget(getter_AddRefs(mainThreadTarget)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_STATE(mainThreadTarget); - - nsCOMPtr<nsIXMLHttpRequestUpload> upload(do_QueryInterface(mainThreadTarget)); - if (upload) { - mUploadEvent = PR_TRUE; - mTarget = - static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR->mUpload); - } - else { - mUploadEvent = PR_FALSE; - mTarget = static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR); - } - NS_ASSERTION(mTarget, "Null target!"); - - PRBool bubbles; - rv = aEvent->GetBubbles(&bubbles); - NS_ENSURE_SUCCESS(rv, rv); - - PRBool cancelable; - rv = aEvent->GetCancelable(&cancelable); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aEvent->GetTimeStamp(&mTimeStamp); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aEvent->GetEventPhase(&mEventPhase); - NS_ENSURE_SUCCESS(rv, rv); - NS_ASSERTION(mEventPhase == nsIDOMEvent::AT_TARGET, "Unsupported phase!"); - - nsCOMPtr<nsIDOMProgressEvent> progressEvent(do_QueryInterface(aEvent)); - if (progressEvent) { - mProgressEvent = PR_TRUE; - - PRBool lengthComputable; - rv = progressEvent->GetLengthComputable(&lengthComputable); - NS_ENSURE_SUCCESS(rv, rv); - - PRUint64 loaded; - rv = progressEvent->GetLoaded(&loaded); - NS_ENSURE_SUCCESS(rv, rv); - - PRUint64 total; - rv = progressEvent->GetTotal(&total); - NS_ENSURE_SUCCESS(rv, rv); - - rv = InitProgressEvent(aType, bubbles, cancelable, lengthComputable, loaded, - total); - NS_ENSURE_SUCCESS(rv, rv); - } - else { - mProgressEvent = PR_FALSE; - - rv = InitEvent(aType, bubbles, cancelable); - NS_ENSURE_SUCCESS(rv, rv); - } - - mState = new nsDOMWorkerXHRState(); - NS_ENSURE_TRUE(mState, NS_ERROR_OUT_OF_MEMORY); - - if (aSnapshot == SNAPSHOT) { - SnapshotXHRState(mXHRProxy->mXHR, mState); - } - - return NS_OK; -} - -/* static */ -void -nsDOMWorkerXHREvent::SnapshotXHRState(nsIXMLHttpRequest* aXHR, - nsDOMWorkerXHRState* aState) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(aXHR && aState, "Don't pass null here!"); - - aState->responseTextResult = aXHR->GetResponseText(aState->responseText); - aState->statusTextResult = aXHR->GetStatusText(aState->statusText); - aState->statusResult = aXHR->GetStatus(&aState->status); - aState->readyStateResult = aXHR->GetReadyState(&aState->readyState); -} - -NS_IMETHODIMP -nsDOMWorkerXHREvent::Run() -{ - nsresult rv = mXHRProxy->HandleWorkerEvent(this, mUploadEvent); - - // Prevent reference cycles by releasing this here. - mXHRProxy = nsnull; - - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; -} - -NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerErrorEvent, nsDOMWorkerEvent, - nsIWorkerErrorEvent) - -NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerErrorEvent, nsIDOMEvent, - nsIWorkerErrorEvent) - -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerErrorEvent) - -nsresult -nsDOMWorkerErrorEvent::GetMessage(nsAString& aMessage) -{ - aMessage.Assign(mMessage); - return NS_OK; -} - -nsresult -nsDOMWorkerErrorEvent::GetFilename(nsAString& aFilename) -{ - aFilename.Assign(mFilename); - return NS_OK; -} - -nsresult -nsDOMWorkerErrorEvent::GetLineno(PRUint32* aLineno) -{ - NS_ENSURE_ARG_POINTER(aLineno); - *aLineno = mLineno; - return NS_OK; -} - -nsresult -nsDOMWorkerErrorEvent::InitErrorEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - const nsAString& aMessageArg, - const nsAString& aFilenameArg, - PRUint32 aLinenoArg) -{ - mMessage.Assign(aMessageArg); - mFilename.Assign(aFilenameArg); - mLineno = aLinenoArg; - return InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); -}
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerEvents.h +++ /dev/null @@ -1,340 +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 Web Workers. - * - * 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 __NSDOMWORKEREVENTS_H__ -#define __NSDOMWORKEREVENTS_H__ - -#include "nsIClassInfo.h" -#include "nsIDOMEvent.h" -#include "nsIDOMEventTarget.h" -#include "nsIDOMProgressEvent.h" -#include "nsIDOMWorkers.h" -#include "nsIRunnable.h" - -#include "jsapi.h" -#include "jsutil.h" -#include "nsAutoJSValHolder.h" -#include "nsAutoPtr.h" -#include "nsCOMPtr.h" -#include "nsStringGlue.h" - -#include "nsDOMWorkerMacros.h" - -class nsDOMWorkerXHRProxy; -class nsIXMLHttpRequest; -class nsIXPConnectWrappedNative; - -/* 4d5794d6-98ab-4a6b-ad5a-8ed1fa1d4839 */ -#define NS_IDOMWORKERPRIVATEEVENT_IID \ -{ \ - 0x4d5794d6, \ - 0x98ab, \ - 0x4a6b, \ - { 0xad, 0x5a, 0x8e, 0xd1, 0xfa, 0x1d, 0x48, 0x39 } \ -} - -class nsIDOMWorkerPrivateEvent : public nsIDOMEvent -{ -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOMWORKERPRIVATEEVENT_IID) - virtual PRBool PreventDefaultCalled() = 0; -}; - -#define NS_FORWARD_NSIDOMEVENT_SPECIAL \ - NS_IMETHOD GetType(nsAString& aType) \ - { return mEvent->GetType(aType); } \ - NS_IMETHOD GetTarget(nsIDOMEventTarget** aTarget) \ - { return mEvent->GetTarget(aTarget); } \ - NS_IMETHOD GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) \ - { return mEvent->GetCurrentTarget(aCurrentTarget); } \ - NS_IMETHOD GetEventPhase(PRUint16* aEventPhase) \ - { return mEvent->GetEventPhase(aEventPhase); } \ - NS_IMETHOD GetBubbles(PRBool* aBubbles) \ - { return mEvent->GetBubbles(aBubbles); } \ - NS_IMETHOD GetCancelable(PRBool* aCancelable) \ - { return mEvent->GetCancelable(aCancelable); } \ - NS_IMETHOD GetTimeStamp(DOMTimeStamp* aTimeStamp) \ - { return mEvent->GetTimeStamp(aTimeStamp); } \ - NS_IMETHOD StopPropagation() \ - { return mEvent->StopPropagation(); } - -#define NS_FORWARD_NSIDOMPROGRESSEVENT_SPECIAL \ - NS_IMETHOD GetLengthComputable(PRBool* aLengthComputable) \ - { return mProgressEvent->GetLengthComputable(aLengthComputable); } \ - NS_IMETHOD GetLoaded(PRUint64* aLoaded) \ - { return mProgressEvent->GetLoaded(aLoaded); } \ - NS_IMETHOD GetTotal(PRUint64* aTotal) \ - { return mProgressEvent->GetTotal(aTotal); } - -#define NS_FORWARD_NSIWORKERMESSAGEEVENT_SPECIAL \ - NS_IMETHOD GetData(nsAString& aData) \ - { return mMessageEvent->GetData(aData); } \ - NS_IMETHOD GetOrigin(nsAString& aOrigin) \ - { return mMessageEvent->GetOrigin(aOrigin); } \ - NS_IMETHOD GetSource(nsISupports** aSource) \ - { return mMessageEvent->GetSource(aSource); } - -#define NS_FORWARD_NSIWORKERERROREVENT_SPECIAL \ - NS_IMETHOD GetMessage(nsAString& aMessage) \ - { return mErrorEvent->GetMessage(aMessage); } \ - NS_IMETHOD GetFilename(nsAString& aFilename) \ - { return mErrorEvent->GetFilename(aFilename); } \ - NS_IMETHOD GetLineno(PRUint32* aLineno) \ - { return mErrorEvent->GetLineno(aLineno); } - -class nsDOMWorkerPrivateEvent : public nsIDOMWorkerPrivateEvent, - public nsIDOMProgressEvent, - public nsIWorkerMessageEvent, - public nsIWorkerErrorEvent, - public nsIClassInfo -{ -public: - NS_DECL_ISUPPORTS - NS_FORWARD_NSIDOMEVENT_SPECIAL - NS_FORWARD_NSIWORKERMESSAGEEVENT_SPECIAL - NS_FORWARD_NSIDOMPROGRESSEVENT_SPECIAL - NS_FORWARD_NSIWORKERERROREVENT_SPECIAL - NS_DECL_NSICLASSINFO - - nsDOMWorkerPrivateEvent(nsIDOMEvent* aEvent); - - NS_IMETHOD PreventDefault(); - - NS_IMETHOD InitEvent(const nsAString& aEventType, - PRBool aCanBubble, - PRBool aCancelable); - - NS_IMETHOD InitProgressEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - PRBool aLengthComputableArg, - PRUint64 aLoadedArg, - PRUint64 aTotalArg); - - NS_IMETHOD InitMessageEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - const nsAString& aDataArg, - const nsAString& aOriginArg, - nsISupports* aSourceArg); - - NS_IMETHOD InitErrorEvent(const nsAString& aTypeArg, - PRBool aCanBubbleArg, - PRBool aCancelableArg, - const nsAString& aMessageArg, - const nsAString& aFilenameArg, - PRUint32 aLinenoArg); - - NS_IMETHOD GetDefaultPrevented(PRBool* aRetVal); - - virtual PRBool PreventDefaultCalled(); - -private: - nsCOMPtr<nsIDOMEvent> mEvent; - nsCOMPtr<nsIDOMProgressEvent> mProgressEvent; - nsCOMPtr<nsIWorkerMessageEvent> mMessageEvent; - nsCOMPtr<nsIWorkerErrorEvent> mErrorEvent; - PRBool mPreventDefaultCalled; -}; - -class nsDOMWorkerEvent : public nsIDOMEvent, - public nsIClassInfo -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMEVENT - NS_DECL_NSICLASSINFO - - nsDOMWorkerEvent() - : mEventPhase(nsIDOMEvent::AT_TARGET), mTimeStamp(0), mBubbles(PR_FALSE), - mCancelable(PR_FALSE), mPreventDefaultCalled(PR_FALSE) { } - - void SetTarget(nsIDOMEventTarget* aTarget) { - mTarget = aTarget; - } - - PRBool PreventDefaultCalled() { - return PRBool(mPreventDefaultCalled); - } - -protected: - virtual ~nsDOMWorkerEvent() { } - - nsString mType; - nsCOMPtr<nsIDOMEventTarget> mTarget; - PRUint16 mEventPhase; - DOMTimeStamp mTimeStamp; - PRPackedBool mBubbles; - PRPackedBool mCancelable; - PRPackedBool mPreventDefaultCalled; -}; - -class nsDOMWorkerMessageEvent : public nsDOMWorkerEvent, - public nsIWorkerMessageEvent -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::) - NS_DECL_NSIWORKERMESSAGEEVENT - NS_DECL_NSICLASSINFO_GETINTERFACES - - nsDOMWorkerMessageEvent() : mData(nsnull) { } - ~nsDOMWorkerMessageEvent(); - - nsresult SetJSData(JSContext* aCx, - JSAutoStructuredCloneBuffer& aBuffer, - nsTArray<nsCOMPtr<nsISupports> >& aWrappedNatives); - -protected: - nsString mOrigin; - nsCOMPtr<nsISupports> mSource; - - nsAutoJSValHolder mDataVal; - uint64* mData; - size_t mDataLen; - nsTArray<nsCOMPtr<nsISupports> > mWrappedNatives; -}; - -class nsDOMWorkerProgressEvent : public nsDOMWorkerEvent, - public nsIDOMProgressEvent -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::) - NS_DECL_NSIDOMPROGRESSEVENT - NS_DECL_NSICLASSINFO_GETINTERFACES - - nsDOMWorkerProgressEvent() - : mLoaded(0), mTotal(0), mLengthComputable(PR_FALSE) { } - -protected: - PRUint64 mLoaded; - PRUint64 mTotal; - PRBool mLengthComputable; -}; - -class nsDOMWorkerXHRState -{ -public: - nsDOMWorkerXHRState() - : responseTextResult(NS_OK), statusTextResult(NS_OK), status(NS_OK), - statusResult(NS_OK), readyState(0), readyStateResult(NS_OK) { } - - NS_IMETHOD_(nsrefcnt) AddRef(); - NS_IMETHOD_(nsrefcnt) Release(); - - nsString responseText; - nsresult responseTextResult; - - nsCString statusText; - nsresult statusTextResult; - - nsresult status; - nsresult statusResult; - - PRUint16 readyState; - nsresult readyStateResult; - -protected: - virtual ~nsDOMWorkerXHRState() { } - - nsAutoRefCnt mRefCnt; -}; - -class nsDOMWorkerXHREvent : public nsDOMWorkerProgressEvent, - public nsIRunnable -{ - friend class nsDOMWorkerXHRProxy; - -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIRUNNABLE - NS_DECL_NSICLASSINFO_GETINTERFACES - - enum SnapshotChoice { - SNAPSHOT, - NO_SNAPSHOT - }; - - nsDOMWorkerXHREvent(nsDOMWorkerXHRProxy* aXHRProxy); - - nsresult Init(PRUint32 aXHREventType, - const nsAString& aType, - nsIDOMEvent* aEvent, - SnapshotChoice = SNAPSHOT); - - static void SnapshotXHRState(nsIXMLHttpRequest* aXHR, - nsDOMWorkerXHRState* aState); - - already_AddRefed<nsDOMWorkerXHRState> ForgetState() { - return mState.forget(); - } - -protected: - nsDOMWorkerXHRState* GetState() { - return mState; - } - - nsRefPtr<nsDOMWorkerXHRProxy> mXHRProxy; - nsCOMPtr<nsIXPConnectWrappedNative> mXHRWN; - nsRefPtr<nsDOMWorkerXHRState> mState; - PRUint32 mXHREventType; - PRInt32 mChannelID; - PRPackedBool mUploadEvent; - PRPackedBool mProgressEvent; -}; - -class nsDOMWorkerErrorEvent : public nsDOMWorkerEvent, - public nsIWorkerErrorEvent -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::) - NS_DECL_NSIWORKERERROREVENT - NS_DECL_NSICLASSINFO_GETINTERFACES - - nsDOMWorkerErrorEvent() - : mLineno(0) { } - -protected: - nsString mMessage; - nsString mFilename; - PRUint32 mLineno; -}; - -#endif /* __NSDOMWORKEREVENTS_H__ */
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerLocation.cpp +++ /dev/null @@ -1,223 +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) 2009 - * 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 "nsDOMWorkerLocation.h" - -#include "nsIClassInfoImpl.h" -#include "nsITextToSubURI.h" -#include "nsIURL.h" - -#include "nsDOMWorkerMacros.h" - -#include "nsAutoPtr.h" -#include "nsEscape.h" -#include "nsNetUtil.h" - -#define XPC_MAP_CLASSNAME nsDOMWorkerLocation -#define XPC_MAP_QUOTED_CLASSNAME "WorkerLocation" - -#define XPC_MAP_FLAGS \ - nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \ - nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \ - nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \ - nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES - -#include "xpc_map_end.h" - -NS_IMPL_THREADSAFE_ISUPPORTS3(nsDOMWorkerLocation, nsIWorkerLocation, - nsIClassInfo, - nsIXPCScriptable) - -NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerLocation, nsIWorkerLocation) - -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerLocation) -NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerLocation) - -NS_IMETHODIMP -nsDOMWorkerLocation::GetHelperForLanguage(PRUint32 aLanguage, - nsISupports** _retval) -{ - if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) { - NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(nsIWorkerLocation*, this)); - } - else { - *_retval = nsnull; - } - return NS_OK; -} - -// static -already_AddRefed<nsIWorkerLocation> -nsDOMWorkerLocation::NewLocation(nsIURL* aURL) -{ - NS_ASSERTION(aURL, "Don't hand me a null pointer!"); - - nsAutoPtr<nsDOMWorkerLocation> location(new nsDOMWorkerLocation()); - NS_ENSURE_TRUE(location, nsnull); - - nsresult rv = aURL->GetSpec(location->mHref); - NS_ENSURE_SUCCESS(rv, nsnull); - - rv = aURL->GetHost(location->mHostname); - NS_ENSURE_SUCCESS(rv, nsnull); - - rv = aURL->GetPath(location->mPathname); - NS_ENSURE_SUCCESS(rv, nsnull); - - nsCString temp; - - rv = aURL->GetQuery(temp); - NS_ENSURE_SUCCESS(rv, nsnull); - if (!temp.IsEmpty()) { - location->mSearch.AssignLiteral("?"); - location->mSearch.Append(temp); - } - - rv = aURL->GetRef(temp); - NS_ENSURE_SUCCESS(rv, nsnull); - - if (!temp.IsEmpty()) { - nsAutoString unicodeRef; - - nsCOMPtr<nsITextToSubURI> converter = - do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); - if (NS_SUCCEEDED(rv)) { - nsCString charset; - rv = aURL->GetOriginCharset(charset); - if (NS_SUCCEEDED(rv)) { - rv = converter->UnEscapeURIForUI(charset, temp, unicodeRef); - if (NS_SUCCEEDED(rv)) { - location->mHash.AssignLiteral("#"); - location->mHash.Append(NS_ConvertUTF16toUTF8(unicodeRef)); - } - } - } - - if (NS_FAILED(rv)) { - location->mHash.AssignLiteral("#"); - location->mHash.Append(temp); - } - } - - rv = aURL->GetScheme(location->mProtocol); - NS_ENSURE_SUCCESS(rv, nsnull); - - location->mProtocol.AppendLiteral(":"); - - PRInt32 port; - rv = aURL->GetPort(&port); - if (NS_SUCCEEDED(rv) && port != -1) { - location->mPort.AppendInt(port); - - nsCAutoString host(location->mHostname); - host.AppendLiteral(":"); - host.Append(location->mPort); - - location->mHost.Assign(host); - } - else { - location->mHost.Assign(location->mHostname); - } - - NS_ADDREF(location); - return location.forget(); -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetHref(nsACString& aHref) -{ - aHref.Assign(mHref); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetProtocol(nsACString& aProtocol) -{ - aProtocol.Assign(mProtocol); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetHost(nsACString& aHost) -{ - aHost.Assign(mHost); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetHostname(nsACString& aHostname) -{ - aHostname.Assign(mHostname); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetPort(nsACString& aPort) -{ - aPort.Assign(mPort); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetPathname(nsACString& aPathname) -{ - aPathname.Assign(mPathname); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetSearch(nsACString& aSearch) -{ - aSearch.Assign(mSearch); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::GetHash(nsACString& aHash) -{ - aHash.Assign(mHash); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerLocation::ToString(nsACString& _retval) -{ - return GetHref(_retval); -}
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerLocation.h +++ /dev/null @@ -1,77 +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) 2009 - * 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 __NSDOMWORKERLOCATION_H__ -#define __NSDOMWORKERLOCATION_H__ - -#include "nsIClassInfo.h" -#include "nsIDOMWorkers.h" -#include "nsIXPCScriptable.h" - -#include "nsCOMPtr.h" -#include "nsStringGlue.h" - -class nsIURL; - -class nsDOMWorkerLocation : public nsIWorkerLocation, - public nsIClassInfo, - public nsIXPCScriptable -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIWORKERLOCATION - NS_DECL_NSICLASSINFO - NS_DECL_NSIXPCSCRIPTABLE - - static already_AddRefed<nsIWorkerLocation> NewLocation(nsIURL* aURL); - -protected: - nsDOMWorkerLocation() { } - -private: - nsCString mHref; - nsCString mProtocol; - nsCString mHost; - nsCString mHostname; - nsCString mPort; - nsCString mPathname; - nsCString mSearch; - nsCString mHash; -}; - -#endif /* __NSDOMWORKERLOCATION_H__ */
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerMacros.h +++ /dev/null @@ -1,135 +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 Web Workers. - * - * 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 __NSDOMWORKERMACROS_H__ -#define __NSDOMWORKERMACROS_H__ - -// Macro to generate nsIClassInfo methods for these threadsafe DOM classes -#define NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \ -NS_IMETHODIMP \ -_class::GetInterfaces(PRUint32* _count, nsIID*** _array) \ -{ \ - return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \ -} \ - -#define NS_IMPL_THREADSAFE_DOM_CI_HELPER(_class) \ -NS_IMETHODIMP \ -_class::GetHelperForLanguage(PRUint32 _language, nsISupports** _retval) \ -{ \ - *_retval = nsnull; \ - return NS_OK; \ -} - -#define NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class) \ -NS_IMETHODIMP \ -_class::GetContractID(char** _contractID) \ -{ \ - *_contractID = nsnull; \ - return NS_OK; \ -} \ - \ -NS_IMETHODIMP \ -_class::GetClassDescription(char** _classDescription) \ -{ \ - *_classDescription = nsnull; \ - return NS_OK; \ -} \ - \ -NS_IMETHODIMP \ -_class::GetClassID(nsCID** _classID) \ -{ \ - *_classID = nsnull; \ - return NS_OK; \ -} \ - \ -NS_IMETHODIMP \ -_class::GetImplementationLanguage(PRUint32* _language) \ -{ \ - *_language = nsIProgrammingLanguage::CPLUSPLUS; \ - return NS_OK; \ -} \ - \ -NS_IMETHODIMP \ -_class::GetFlags(PRUint32* _flags) \ -{ \ - *_flags = nsIClassInfo::THREADSAFE | nsIClassInfo::DOM_OBJECT; \ - return NS_OK; \ -} \ - \ -NS_IMETHODIMP \ -_class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \ -{ \ - return NS_ERROR_NOT_AVAILABLE; \ -} - -#define NS_IMPL_THREADSAFE_DOM_CI(_class) \ -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \ -NS_IMPL_THREADSAFE_DOM_CI_HELPER(_class) \ -NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class) - -#define NS_FORWARD_NSICLASSINFO_NOGETINTERFACES(_to) \ - NS_IMETHOD GetHelperForLanguage(PRUint32 aLanguage, nsISupports** _retval) \ - { return _to GetHelperForLanguage(aLanguage, _retval); } \ - NS_IMETHOD GetContractID(char** aContractID) \ - { return _to GetContractID(aContractID); } \ - NS_IMETHOD GetClassDescription(char** aClassDescription) \ - { return _to GetClassDescription(aClassDescription); } \ - NS_IMETHOD GetClassID(nsCID** aClassID) \ - { return _to GetClassID(aClassID); } \ - NS_IMETHOD GetImplementationLanguage(PRUint32* aImplementationLanguage) \ - { return _to GetImplementationLanguage(aImplementationLanguage); } \ - NS_IMETHOD GetFlags(PRUint32* aFlags) \ - { return _to GetFlags(aFlags); } \ - NS_IMETHOD GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) \ - { return _to GetClassIDNoAlloc(aClassIDNoAlloc); } - -#define NS_DECL_NSICLASSINFO_GETINTERFACES \ - NS_IMETHOD GetInterfaces(PRUint32* aCount, nsIID*** aArray); - -// Don't know why nsISupports.idl defines this out... -#define NS_FORWARD_NSISUPPORTS(_to) \ - NS_IMETHOD QueryInterface(const nsIID& uuid, void** result) { \ - return _to QueryInterface(uuid, result); \ - } \ - NS_IMETHOD_(nsrefcnt) AddRef(void) { return _to AddRef(); } \ - NS_IMETHOD_(nsrefcnt) Release(void) { return _to Release(); } - -#define JSON_PRIMITIVE_PROPNAME \ - "primitive" - -#endif /* __NSDOMWORKERMACROS_H__ */
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerMessageHandler.cpp +++ /dev/null @@ -1,440 +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 Web Workers. - * - * 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 "nsDOMWorkerMessageHandler.h" - -#include "nsIDOMEvent.h" -#include "nsIXPConnect.h" - -#include "nsContentUtils.h" - -#include "nsDOMThreadService.h" -#include "nsDOMWorkerEvents.h" - -NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerEventListenerBase) -NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerEventListenerBase) - -nsresult -nsDOMWorkerWeakEventListener::Init(nsIDOMEventListener* aListener) -{ - NS_ENSURE_ARG_POINTER(aListener); - - nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(aListener)); - NS_ENSURE_TRUE(wrappedJS, NS_NOINTERFACE); - - JSObject* obj; - nsresult rv = wrappedJS->GetJSObject(&obj); - NS_ENSURE_SUCCESS(rv, rv); - - mObj = obj; - - return NS_OK; -} - -already_AddRefed<nsIDOMEventListener> -nsDOMWorkerWeakEventListener::GetListener() -{ - JSContext* cx = nsDOMThreadService::GetCurrentContext(); - NS_ENSURE_TRUE(cx, nsnull); - - nsIXPConnect* xpc = nsContentUtils::XPConnect(); - - nsCOMPtr<nsIDOMEventListener> listener; - nsresult rv = xpc->WrapJS(cx, mObj, NS_GET_IID(nsIDOMEventListener), - getter_AddRefs(listener)); - NS_ENSURE_SUCCESS(rv, nsnull); - - return listener.forget(); -} - -nsDOMWorkerWrappedWeakEventListener:: -nsDOMWorkerWrappedWeakEventListener(nsDOMWorkerWeakEventListener* aInner) -: mInner(aInner) -{ - NS_ASSERTION(aInner, "Null pointer!"); -} - -NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerMessageHandler, - nsIDOMEventTarget, - nsIClassInfo) - -NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerMessageHandler, - nsIDOMEventTarget) - -NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerMessageHandler) - -const nsDOMWorkerMessageHandler::ListenerCollection* -nsDOMWorkerMessageHandler::GetListenerCollection(const nsAString& aType) const -{ - PRUint32 count = mCollections.Length(); - for (PRUint32 index = 0; index < count; index++) { - const ListenerCollection& collection = mCollections[index]; - if (collection.type.Equals(aType)) { - return &collection; - } - } - return nsnull; -} - -void -nsDOMWorkerMessageHandler::GetListenersForType(const nsAString& aType, - ListenerArray& _retval) const -{ - _retval.Clear(); - - const ListenerCollection* collection = GetListenerCollection(aType); - if (collection) { - PRUint32 count = collection->listeners.Length(); - - if (!_retval.SetLength(count)) { - NS_WARNING("Out of memory!"); - return; - } - - for (PRUint32 index = 0; index < count; index++) { - nsCOMPtr<nsIDOMEventListener> listener = - collection->listeners[index]->GetListener(); - _retval[index].swap(listener); - } - } -} - -nsresult -nsDOMWorkerMessageHandler::SetOnXListener(const nsAString& aType, - nsIDOMEventListener* aListener) -{ - nsRefPtr<nsDOMWorkerWrappedWeakEventListener> wrappedListener; - - ListenerCollection* collection = - const_cast<ListenerCollection*>(GetListenerCollection(aType)); - -#ifdef DEBUG - PRBool removed; -#endif - - if (collection) { - wrappedListener.swap(collection->onXListener); - if (wrappedListener) { -#ifdef DEBUG - removed = -#endif - collection->listeners.RemoveElement(wrappedListener); - NS_ASSERTION(removed, "Element wasn't in the list!"); - } - } - - if (!aListener) { - if (collection && !collection->listeners.Length()) { -#ifdef DEBUG - removed = -#endif - mCollections.RemoveElement(*collection); - NS_ASSERTION(removed, "Element wasn't in the list!"); - } - return NS_OK; - } - - nsRefPtr<nsDOMWorkerWeakEventListener> weakListener = - new nsDOMWorkerWeakEventListener(); - NS_ENSURE_TRUE(weakListener, NS_ERROR_OUT_OF_MEMORY); - - nsresult rv = weakListener->Init(aListener); - NS_ENSURE_SUCCESS(rv, rv); - - wrappedListener = new nsDOMWorkerWrappedWeakEventListener(weakListener); - NS_ENSURE_TRUE(wrappedListener, NS_ERROR_OUT_OF_MEMORY); - - if (!collection) { - collection = mCollections.AppendElement(aType); - NS_ENSURE_TRUE(collection, NS_ERROR_OUT_OF_MEMORY); - } - - WeakListener* newListener = - collection->listeners.AppendElement(wrappedListener); - NS_ENSURE_TRUE(newListener, NS_ERROR_OUT_OF_MEMORY); - - wrappedListener.swap(collection->onXListener); - return NS_OK; -} - -already_AddRefed<nsIDOMEventListener> -nsDOMWorkerMessageHandler::GetOnXListener(const nsAString& aType) const -{ - const ListenerCollection* collection = GetListenerCollection(aType); - if (collection && collection->onXListener) { - return collection->onXListener->GetListener(); - } - - return nsnull; -} - -void -nsDOMWorkerMessageHandler::ClearListeners(const nsAString& aType) -{ - PRUint32 count = mCollections.Length(); - for (PRUint32 index = 0; index < count; index++) { - if (mCollections[index].type.Equals(aType)) { - mCollections.RemoveElementAt(index); - return; - } - } -} - -PRBool -nsDOMWorkerMessageHandler::HasListeners(const nsAString& aType) -{ - const ListenerCollection* collection = GetListenerCollection(aType); - return collection && collection->listeners.Length(); -} - -void -nsDOMWorkerMessageHandler::ClearAllListeners() -{ - mCollections.Clear(); -} - -void -nsDOMWorkerMessageHandler::Trace(JSTracer* aTracer) -{ - PRUint32 cCount = mCollections.Length(); - for (PRUint32 cIndex = 0; cIndex < cCount; cIndex++) { - const ListenerCollection& collection = mCollections[cIndex]; - PRUint32 lCount = collection.listeners.Length(); - for (PRUint32 lIndex = 0; lIndex < lCount; lIndex++) { - JSObject* obj = collection.listeners[lIndex]->GetJSObject(); - NS_ASSERTION(obj, "Null object!"); - JS_SET_TRACING_DETAILS(aTracer, nsnull, this, 0); - JS_CallTracer(aTracer, obj, JSTRACE_OBJECT); - } - } -} - -/** - * See nsIDOMEventTarget - */ -NS_IMETHODIMP -nsDOMWorkerMessageHandler::RemoveEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture) -{ - ListenerCollection* collection = - const_cast<ListenerCollection*>(GetListenerCollection(aType)); - - if (collection) { - PRUint32 count = collection->listeners.Length(); - for (PRUint32 index = 0; index < count; index++) { - WeakListener& weakListener = collection->listeners[index]; - if (weakListener == collection->onXListener) { - continue; - } - nsCOMPtr<nsIDOMEventListener> listener = weakListener->GetListener(); - if (listener == aListener) { - collection->listeners.RemoveElementAt(index); - break; - } - } - - if (!collection->listeners.Length()) { -#ifdef DEBUG - PRBool removed = -#endif - mCollections.RemoveElement(*collection); - NS_ASSERTION(removed, "Somehow this wasn't in the list!"); - } - } - - return NS_OK; -} - -/** - * See nsIDOMEventTarget - */ -NS_IMETHODIMP -nsDOMWorkerMessageHandler::DispatchEvent(nsIDOMEvent* aEvent, - PRBool* _retval) -{ - NS_ENSURE_ARG_POINTER(aEvent); - - nsCOMPtr<nsIDOMWorkerPrivateEvent> event; - - if (_retval) { - event = do_QueryInterface(aEvent); - if (!event) { - event = new nsDOMWorkerPrivateEvent(aEvent); - NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); - } - aEvent = event; - } - - nsAutoString type; - nsresult rv = aEvent->GetType(type); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoTArray<Listener, 10> listeners; - GetListenersForType(type, listeners); - - PRUint32 count = listeners.Length(); - for (PRUint32 index = 0; index < count; index++) { - const Listener& listener = listeners[index]; - NS_ASSERTION(listener, "Null listener in array!"); - - listener->HandleEvent(aEvent); - } - - if (_retval) { - *_retval = event->PreventDefaultCalled(); - } - - return NS_OK; -} - -/** - * See nsIDOMEventTarget - */ -NS_IMETHODIMP -nsDOMWorkerMessageHandler::AddEventListener(const nsAString& aType, - nsIDOMEventListener* aListener, - PRBool aUseCapture, - PRBool aWantsUntrusted, - PRUint8 aOptionalArgc) -{ - // We don't support aWantsUntrusted yet. - NS_ENSURE_TRUE(aOptionalArgc < 2, NS_ERROR_NOT_IMPLEMENTED); - - ListenerCollection* collection = - const_cast<ListenerCollection*>(GetListenerCollection(aType)); - - if (!collection) { - collection = mCollections.AppendElement(aType); - NS_ENSURE_TRUE(collection, NS_ERROR_OUT_OF_MEMORY); - } - - nsRefPtr<nsDOMWorkerWeakEventListener> weakListener = - new nsDOMWorkerWeakEventListener(); - NS_ENSURE_TRUE(weakListener, NS_ERROR_OUT_OF_MEMORY); - - nsresult rv = weakListener->Init(aListener); - NS_ENSURE_SUCCESS(rv, rv); - - WeakListener* newListener = collection->listeners.AppendElement(weakListener); - NS_ENSURE_TRUE(newListener, NS_ERROR_OUT_OF_MEMORY); - - return NS_OK; -} - -nsIDOMEventTarget * -nsDOMWorkerMessageHandler::GetTargetForDOMEvent() -{ - NS_ERROR("Should not be called"); - return nsnull; -} - -nsIDOMEventTarget * -nsDOMWorkerMessageHandler::GetTargetForEventTargetChain() -{ - NS_ERROR("Should not be called"); - return nsnull; -} - -nsresult -nsDOMWorkerMessageHandler::PreHandleEvent(nsEventChainPreVisitor & aVisitor) -{ - NS_ERROR("Should not be called"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsresult -nsDOMWorkerMessageHandler::WillHandleEvent(nsEventChainPostVisitor & aVisitor) -{ - NS_ERROR("Should not be called"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsresult -nsDOMWorkerMessageHandler::PostHandleEvent(nsEventChainPostVisitor & aVisitor) -{ - NS_ERROR("Should not be called"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsresult -nsDOMWorkerMessageHandler::DispatchDOMEvent(nsEvent *aEvent, nsIDOMEvent *aDOMEvent, - nsPresContext *aPresContext, - nsEventStatus *aEventStatus) -{ - NS_ERROR("Should not be called"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsEventListenerManager* -nsDOMWorkerMessageHandler::GetListenerManager(PRBool aMayCreate) -{ - NS_ERROR("Should not be called"); - return nsnull; -} - -nsresult -nsDOMWorkerMessageHandler::AddEventListenerByIID(nsIDOMEventListener *aListener, - const nsIID & aIID) -{ - NS_ERROR("Should not be called"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsresult -nsDOMWorkerMessageHandler::RemoveEventListenerByIID(nsIDOMEventListener *aListener, - const nsIID & aIID) -{ - NS_ERROR("Should not be called"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsIScriptContext* -nsDOMWorkerMessageHandler::GetContextForEventHandlers(nsresult *aRv) -{ - NS_ERROR("Should not be called"); - *aRv = NS_ERROR_NOT_IMPLEMENTED; - return nsnull; -} - -JSContext* -nsDOMWorkerMessageHandler::GetJSContextForEventHandlers() -{ - NS_ERROR("Should not be called"); - return nsnull; -}
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerMessageHandler.h +++ /dev/null @@ -1,175 +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 Web Workers. - * - * 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 __NSDOMWORKERMESSAGEHANDLER_H__ -#define __NSDOMWORKERMESSAGEHANDLER_H__ - -#include "nsIClassInfo.h" -#include "nsIDOMEventListener.h" -#include "nsIDOMEventTarget.h" -#include "nsIDOMWorkers.h" - -#include "nsIProgrammingLanguage.h" - -#include "jsapi.h" -#include "nsAutoPtr.h" -#include "nsCOMPtr.h" -#include "nsIClassInfoImpl.h" -#include "nsStringGlue.h" -#include "nsTArray.h" -#include "nsIWeakReference.h" - -class nsDOMWorkerEventListenerBase -{ -public: - NS_IMETHOD_(nsrefcnt) AddRef(); - NS_IMETHOD_(nsrefcnt) Release(); - - virtual already_AddRefed<nsIDOMEventListener> GetListener() = 0; - virtual JSObject* GetJSObject() = 0; - -protected: - virtual ~nsDOMWorkerEventListenerBase() { } - - nsAutoRefCnt mRefCnt; -}; - -class nsDOMWorkerWeakEventListener : public nsDOMWorkerEventListenerBase -{ -public: - nsDOMWorkerWeakEventListener() - : mObj(NULL) { } - - nsresult Init(nsIDOMEventListener* aListener); - - already_AddRefed<nsIDOMEventListener> GetListener(); - - virtual JSObject* GetJSObject() { - return mObj; - } - -private: - JSObject* mObj; -}; - -class nsDOMWorkerWrappedWeakEventListener : public nsDOMWorkerEventListenerBase -{ -public: - nsDOMWorkerWrappedWeakEventListener(nsDOMWorkerWeakEventListener* aInner); - - already_AddRefed<nsIDOMEventListener> GetListener() { - return mInner->GetListener(); - } - - virtual JSObject* GetJSObject() { - return mInner->GetJSObject(); - } - -private: - nsRefPtr<nsDOMWorkerWeakEventListener> mInner; -}; - -class nsDOMWorkerMessageHandler : public nsIDOMEventTarget, - public nsIClassInfo -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMEVENTTARGET - NS_DECL_NSICLASSINFO - - virtual nsresult SetOnXListener(const nsAString& aType, - nsIDOMEventListener* aListener); - - already_AddRefed<nsIDOMEventListener> - GetOnXListener(const nsAString& aType) const; - - void ClearListeners(const nsAString& aType); - - PRBool HasListeners(const nsAString& aType); - - void ClearAllListeners(); - - void Trace(JSTracer* aTracer); - -protected: - virtual ~nsDOMWorkerMessageHandler() { } - -private: - - typedef nsCOMPtr<nsIDOMEventListener> Listener; - typedef nsTArray<Listener> ListenerArray; - - typedef nsRefPtr<nsDOMWorkerEventListenerBase> WeakListener; - typedef nsTArray<WeakListener> WeakListenerArray; - - struct ListenerCollection { - PRBool operator==(const ListenerCollection& aOther) const { - return this == &aOther; - } - - ListenerCollection(const nsAString& aType) - : type(aType) { } - - nsString type; - WeakListenerArray listeners; - nsRefPtr<nsDOMWorkerWrappedWeakEventListener> onXListener; - }; - - const ListenerCollection* GetListenerCollection(const nsAString& aType) const; - - void GetListenersForType(const nsAString& aType, - ListenerArray& _retval) const; - - nsTArray<ListenerCollection> mCollections; -}; - -#define NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(_to) \ - virtual nsIDOMEventTarget * GetTargetForDOMEvent(void) { return _to GetTargetForDOMEvent(); } \ - virtual nsIDOMEventTarget * GetTargetForEventTargetChain(void) { return _to GetTargetForEventTargetChain(); } \ - virtual nsresult PreHandleEvent(nsEventChainPreVisitor & aVisitor) { return _to PreHandleEvent(aVisitor); } \ - virtual nsresult WillHandleEvent(nsEventChainPostVisitor & aVisitor) { return _to WillHandleEvent(aVisitor); } \ - virtual nsresult PostHandleEvent(nsEventChainPostVisitor & aVisitor) { return _to PostHandleEvent(aVisitor); } \ - virtual nsresult DispatchDOMEvent(nsEvent *aEvent, nsIDOMEvent *aDOMEvent, nsPresContext *aPresContext, nsEventStatus *aEventStatus) { return _to DispatchDOMEvent(aEvent, aDOMEvent, aPresContext, aEventStatus); } \ - virtual nsEventListenerManager * GetListenerManager(PRBool aMayCreate) { return _to GetListenerManager(aMayCreate); } \ - virtual nsresult AddEventListenerByIID(nsIDOMEventListener *aListener, const nsIID & aIID) { return _to AddEventListenerByIID(aListener, aIID); } \ - virtual nsresult RemoveEventListenerByIID(nsIDOMEventListener *aListener, const nsIID & aIID) { return _to RemoveEventListenerByIID(aListener, aIID); } \ - virtual nsIScriptContext * GetContextForEventHandlers(nsresult *aRv NS_OUTPARAM) { return _to GetContextForEventHandlers(aRv); } \ - virtual JSContext * GetJSContextForEventHandlers(void) { return _to GetJSContextForEventHandlers(); } - - -#endif /* __NSDOMWORKERMESSAGEHANDLER_H__ */
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerNavigator.cpp +++ /dev/null @@ -1,108 +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 "nsDOMWorkerNavigator.h" - -#include "nsIClassInfoImpl.h" -#include "nsStringGlue.h" - -#include "nsDOMThreadService.h" -#include "nsDOMWorkerMacros.h" - -#define XPC_MAP_CLASSNAME nsDOMWorkerNavigator -#define XPC_MAP_QUOTED_CLASSNAME "Navigator" - -#define XPC_MAP_FLAGS \ - nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \ - nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \ - nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \ - nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \ - nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES - -#include "xpc_map_end.h" - -NS_IMPL_THREADSAFE_ISUPPORTS3(nsDOMWorkerNavigator, nsIWorkerNavigator, - nsIClassInfo, - nsIXPCScriptable) - -NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerNavigator, nsIWorkerNavigator) - -NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerNavigator) -NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerNavigator) - -NS_IMETHODIMP -nsDOMWorkerNavigator::GetHelperForLanguage(PRUint32 aLanguage, - nsISupports** _retval) -{ - if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) { - NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(nsIWorkerNavigator*, this)); - } - else { - *_retval = nsnull; - } - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerNavigator::GetAppName(nsAString& aAppName) -{ - nsDOMThreadService::get()->GetAppName(aAppName); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerNavigator::GetAppVersion(nsAString& aAppVersion) -{ - nsDOMThreadService::get()->GetAppVersion(aAppVersion); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerNavigator::GetPlatform(nsAString& aPlatform) -{ - nsDOMThreadService::get()->GetPlatform(aPlatform); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMWorkerNavigator::GetUserAgent(nsAString& aUserAgent) -{ - nsDOMThreadService::get()->GetUserAgent(aUserAgent); - return NS_OK; -}
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerNavigator.h +++ /dev/null @@ -1,57 +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 __NSDOMWORKERNAVIGATOR_H__ -#define __NSDOMWORKERNAVIGATOR_H__ - -#include "nsIClassInfo.h" -#include "nsIDOMWorkers.h" -#include "nsIXPCScriptable.h" - -class nsDOMWorkerNavigator : public nsIWorkerNavigator, - public nsIClassInfo, - public nsIXPCScriptable -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIWORKERNAVIGATOR - NS_DECL_NSICLASSINFO - NS_DECL_NSIXPCSCRIPTABLE -}; - -#endif /* __NSDOMWORKERNAVIGATOR_H__ */
deleted file mode 100644 --- a/dom/src/threads/nsDOMWorkerPool.cpp +++ /dev/null @@ -1,238 +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): - * Vladimir Vukicevic <vladimir@pobox.com> (Original Author) - * Ben Turner <bent.mozilla@gmail.com> - * - * 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 "nsDOMWorkerPool.h" - -// Interfaces -#include "nsIDocument.h" -#include "nsIDOMClassInfo.h" -#include "nsIJSContextStack.h" -#include "nsIScriptGlobalObject.h" -#include "nsIServiceManager.h" -#include "nsIThreadManager.h" -#include "nsIXPConnect.h" -#include "nsPIDOMWindow.h" - -// Other includes -#include "nsContentUtils.h" -#include "nsDOMJSUtils.h" -#include "nsProxyRelease.h" -#include "nsThreadUtils.h" - -// DOMWorker includes -#include "nsDOMThreadService.h" -#include "nsDOMWorker.h" - -using namespace mozilla; - -#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args) - -nsDOMWorkerPool::nsDOMWorkerPool(nsIScriptGlobalObject* aGlobalObject, - nsIDocument* aDocument) -: mParentGlobal(aGlobalObject), - mParentDocument(aDocument), - mReentrantMonitor("nsDOMWorkerPool.mReentrantMonitor"), - mCanceled(PR_FALSE), - mSuspended(PR_FALSE), - mWindowID(aDocument ? aDocument->OuterWindowID() : 0) -{ -} - -nsDOMWorkerPool::~nsDOMWorkerPool() -{ - nsCOMPtr<nsIThread> mainThread; - NS_GetMainThread(getter_AddRefs(mainThread)); - - nsIScriptGlobalObject* global; - mParentGlobal.forget(&global); - if (global) { - NS_ProxyRelease(mainThread, global, PR_FALSE); - } - - nsIDocument* document; - mParentDocument.forget(&document); - if (document) { - NS_ProxyRelease(mainThread, document, PR_FALSE); - } -} - -NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerPool) -NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerPool) - -nsresult -nsDOMWorkerPool::Init() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - return NS_OK; -} - -nsresult -nsDOMWorkerPool::NoteWorker(nsDOMWorker* aWorker) -{ - NS_ASSERTION(aWorker, "Null pointer!"); - - PRBool suspendWorker; - - { - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - if (mCanceled) { - return NS_ERROR_ABORT; - } - - nsDOMWorker** newWorker = mWorkers.AppendElement(aWorker); - NS_ENSURE_TRUE(newWorker, NS_ERROR_OUT_OF_MEMORY); - - suspendWorker = mSuspended; - } - - if (suspendWorker) { - aWorker->Suspend(); - } - - return NS_OK; -} - -void -nsDOMWorkerPool::NoteDyingWorker(nsDOMWorker* aWorker) -{ - NS_ASSERTION(aWorker, "Null pointer!"); - - PRBool removeFromThreadService = PR_FALSE; - - { - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - NS_ASSERTION(mWorkers.Contains(aWorker), "Worker from a different pool?!"); - mWorkers.RemoveElement(aWorker); - - if (!mCanceled && !mWorkers.Length()) { - removeFromThreadService = PR_TRUE; - } - }